pax_global_header00006660000000000000000000000064121300255300014501gustar00rootroot0000000000000052 comment=37844a6b9a7656d778280a169605fd9ee0ea3bf8 0xffff-0.6~git20130406/000077500000000000000000000000001213002553000142475ustar00rootroot000000000000000xffff-0.6~git20130406/AUTHORS000066400000000000000000000001631213002553000153170ustar00rootroot00000000000000Copyright (C) 2007-2010 pancake Copyright (C) 2011-2012 Pali Rohár 0xffff-0.6~git20130406/COPYING000066400000000000000000001233251213002553000153100ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded >from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. 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 that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU 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 as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. 0xffff-0.6~git20130406/INSTALL000066400000000000000000000013231213002553000152770ustar00rootroot00000000000000Installation instructions: ========================== To build the flasher you will need gcc, make and libusb. For crosscompiling to arm you can use scratchbox. But you will probably need the libusb.so of the scratchbox environment to the device. Just type: $ make The most interesting targets for make are: all normal build install installs into /usr/local by default uninstall remove installed files clean clean compilation objects and generated binaries The installation procedure is quite simple and you can define a new PREFIX manually from the command line: $ sudo make install PREFIX=/usr The default one is /usr/local (not very userfriendly but standards are standards :P hehe) 0xffff-0.6~git20130406/Makefile000066400000000000000000000000601213002553000157030ustar00rootroot00000000000000all clean install uninstall: $(MAKE) -C src $@ 0xffff-0.6~git20130406/README000066400000000000000000000027331213002553000151340ustar00rootroot00000000000000 ------. ,---------.--.--. / | ___ | | | \\------------ -- . | .__ / \/ . ____/ _/ _/ The 0pen | / . < | | | Free Fiasco | '- > ^ ___| _| .' Firmware Flasher | | ' | - -- --- ----------------\\ \_____/7_/\______ : I 0xFFFF _/ ___|_.|__| '` The 'Open Free Fiasco Firmware Flasher' aka 0xFFFF utility implements a free (under the GPLv3 license) userspace handler for the NOLO bootloader and extended features for flashing, dumping and getting information for the Nokia Internet Tablets. Use it with CARE. This is an experimental tool and it can brick your device. It's not suposed to be stable, so nokia will probably release incompatible bootloaders to break this tool. USE IT AT YOUR OWN RISK. PLEASE. Read carefully all the documentation inside doc/* for more information before building or using the flasher to avoid questions, problems or so. Feel free to join to the mailing list and visit the homepage for more info: 0xffff@lists.nopcode.org http://www.nopcode.org/0xFFFF -----------8<--------------------------------------------------------------- Build: $ make To install: (by default is /usr/local) $ make install PREFIX=/usr DESTDIR=/ Have phun! --pancake --Pali 0xffff-0.6~git20130406/config.mk000066400000000000000000000002001213002553000160350ustar00rootroot00000000000000VERSION = 0.6 PREFIX = /usr/local # NetBSD stuff #CPPFLAGS += -I/usr/pkg/include #LDFLAGS += -L/usr/pkg/lib -Wl,-R/usr/pkg/lib 0xffff-0.6~git20130406/doc/000077500000000000000000000000001213002553000150145ustar00rootroot000000000000000xffff-0.6~git20130406/doc/dumping000066400000000000000000000037751213002553000164160ustar00rootroot00000000000000Dumping the firmware: This technique consists on reconstructing a firmware image dumping pieces at certains offsets of the device internal memory. Technical details: * The internal flash memory is exposed to the system as MTD devices. * Is possible to dump the individual sections of a flashed firmware. * * READ src/local.c for detailed information. mtd0 - contains xloader and sencodary pieces of the bootloaders 0x00000 - xloader.bin (size is 0x03600) 0x04000 - secondary.bin (size is 0x15400) 0x1FFFF - eof mtd1 - looks like there's a pool ConF structures mtd2 - starts with NOLO img\x5c\x13 and \x00 padding 0x00800 - zImage > NOLO is a four byte marker, next four bytes > can vary since it is kernel image size mtd3 - initfs.jffs2 (2M) aka 0x200000 vs 0x3900000 mtd4 - rootfs.jffs2 (a fucking copy of the above rootfs?) For dumping mtd parition is used tool nanddump. Here is example how to dump kernel image without padding to file zImage: $ nanddump -i -o -b -s 0x00000800 -l 0x001FF800 -f zImage /dev/mtd2 Params means: -i - "Ignore errors" -o - "Omit oob data" -b - "Omit bad blocks" -s - "Start address" -l - "Length" -f - "Output file" Please note that some new versions of naddump have some options removed and some are enabled by default. Before using check params of your nanddump version. // Extra notes // [MTD] NAND Consolidate oobinfo handling The info structure for out of band data was copied into the mtd structure. Make it a pointer and remove the ability to set it from userspace. The position of ecc bytes is defined by the hardware and should not be changed by software. // The oob stuff In mtd3 the OOB data is 64 bytes aka 0x40, and this oob stuff appears every 2KB aka 0x800 bytes. /* * Obsolete legacy interface. Keep it in order not to break userspace * interfaces */ struct nand_oobinfo { uint32_t useecc; uint32_t eccbytes; uint32_t oobfree[8][2]; uint32_t eccpos[32]; }; 0xffff-0.6~git20130406/doc/faq000066400000000000000000000013531213002553000155100ustar00rootroot00000000000000FAQ: *) How can I set my Internet Tablet into RD mode with 0xFFFF? Just type '0xFFFF -R 1' as root *) How can I unpack a FIASCO firmware? Just type '0xFFFF -M FiascoFirmware.bin -u' *) How can I flash a new rootfs? # 0xFFFF -m rootfs.jffs2 -f *) How can I flash a full FIASCO image? # 0xFFFF -M FiascoFirmware.fiasco -f Advanced commands: *) How to extract the firmware pieces from a running device? It is possible to dump the firmware pieces from the internal MTD to reconstruct a FIASCO image. To do this recompile the flasher for ARM and run this command in the device: # mkdir /media/mmc1/backup # 0xFFFF -e /media/mmc1/backup To dump directly into FIASCO image run: # 0xFFFF -E /media/mmc1/backup.fiasco 0xffff-0.6~git20130406/doc/faq2000066400000000000000000000053031213002553000155710ustar00rootroot00000000000000FAQ2: This file tries to collect a bunch of common questions/answers about flashing *) Why implement a free software flasher? The Nokia Internet Tablets are based on Free Software (software libre), but not everything included *is* free software, for instance, the firmware flasher tool. The 0xFFFF project aims to feed the minds of those who really want to understand how these gadgets work internally, free the knowledge to avoid the restrictions and fill the lack of information on the most important part of the system. That's it, now you can build and run this flasher on *BSD, w32, MacOSX on ARM, powerpc, x86, mips, etc... *) Can I brick my device? Of course! You're free to do what you want with your device :) Seriously. Flashing a device is not a safe thing, so I give no warranty of what will happen to your device when using this tool. BTW, after a huge number of tests I can say that these devices are hard to brick, but if you are scared about bricking your device you should use the flasher provided by Nokia, it's better for your heart's health. *) What can I do with 0xFFFF? Actually 0xFFFF allows you to: - flash separated pieces of the firmware - flash full FIASCO image - load kernel & initfs without flashing - cold-flash bricked device (without NOLO) - retrieve information about the device - reboot de mother board - extract the current firmware pieces from the device (dump) - set the USB host/slave mode - set the R&R mode and flags - pack/unpack FIASCO firmwares - automatic piece identifier *) What is NOLO? NOLO is the 'server-side' part of the flasher from Nokia. NOLO means NOkia LOader and it's composed by two pieces of the firmware that are flashed together. On the n800 firmwares, these two pieces are distributed in a single file, but when flashing a 770, NOLO requires to provide the xloader (without commiting) and then the secondary piece. This piece of software is closed source and is the responsable of handling the requests from the client-side flasher. It provides a query-like interface via usb control messages for doing different actions on the device. *) How can I identify my device? Theorically 770 and n800 have different USB device ID, but this is not true at all. The first series of the n800 comes with the same usb-id than 770. That's weird! So, the only way to identify the device is by asking nolo for the version information of different pieces of the firmware. This can be faked, because you can flash 770 stuff on n800 and viceversa, but it's not recommended because it wouldn't work :) *) Can I unpack FIASCO blobs? Yes, last version of 0xFFFF has full support of FIASCO images. 0xffff-0.6~git20130406/doc/fiasco000066400000000000000000000043541213002553000162110ustar00rootroot00000000000000 Copyright (C) 2007-2011 pancake Copyright (C) 2011-2012 Pali Rohár SPECS FOR THE FIASCO FIRMWARE FILE FORMAT ffff! ----------------------------------------------- This is final working version of FIASCO format. FIASCO image which is generated by this spec is acceptable by Nokia flasher-3.5 and unpack data same as FIASO image generated by Nokia fiasco-gen. This format is implemented in 0xFFFF and every image which I tested (generated by 0xFFFF and fiasco-gen) was properly unpacked under 0xFFFF and flasher-3.5 with same result. Small difference is that fiasco-gen add some unknown subsection block to image header (type '4' or '/') which contains some messy characters... But if these sections missing, flasher-3.5 working fine too. And old FIASCO images (for N8x0) does not have these subsectin... FILE HEADER 1 byte = 0xb4 -- signature 4 bytes -- FW header length (big endian) FW HEADER 4 bytes -- number of FW header blocks (big endian) block { 1 byte -- type of block 0xE8 - Fiasco name 0x31 - FW name 1 byte -- length of block data N bytes -- block data } IMAGE 1 byte = 0x54 -- signature 1 byte -- number of subsection blocks + 1 5 bytes -- unknown (always 0x2e 0x19 0x01 0x01 0x00) 2 bytes -- checksum for the image contents (xorpair) (big endian) 12 bytes -- image name type (first byte is FF if is the last image) 4 bytes -- length of image data (big endian) 4 bytes -- unknown (always 0x00 0x00 0x00 0x00) block { 1 byte -- type of subsection block '1' - version '2' - device & hw revisions (size of device is 16, hw revision 8) '3' - layout '4' - unknown '/' - unknown 1 byte -- length of subsection block N bytes -- subsection block data } 1 byte -- unknown (0x00 is accepted, maybe end of subsections?) N bytes -- image data 0xffff-0.6~git20130406/doc/local-flash000066400000000000000000000023551213002553000171310ustar00rootroot00000000000000It is possible to flash directly from the device, so this brings the possibility to completely replace the bootloader flasher by a userland one with extended features for backuping and recovering data. The way to flash is using mtd-utils: $ flash_eraseall -j /dev/mtd3 $ nandwrite -a -p /dev/mtd3 initfs.jffs2 This is an specific example plagied from initfs_flasher of bootmenu. The '-j' flag says that this is a jffs2 partition. Theorically this flag is not required for zImage, and the bootloader pieces. The '-a' creates the OOB data automatically, and the '-p' flag pads the data to fill the block. These flags are only fine for initfs, so this will be probably wrong for other pieces. Using the dump functionality you can check if you have flashed properly every piece inside the device, but keep in mind that it is dangerous and you can brick your device. But feel free to send feedback to provide a full support for local flashing on 770 and n800. Nokia N900 using ubi layout on top of /dev/mtd5 rootfs partition. Therefor formatting rootfs should be done via ubiformat tool which preserve erase counters. Erasing N900 rootfs: $ ubiformat /dev/mtd5 Flashing new ubi image to N900 rootfs: $ ubiformat /dev/mtd5 -s 512 -O 512 -f image.ubi 0xffff-0.6~git20130406/doc/mkii000066400000000000000000000061501213002553000156720ustar00rootroot00000000000000 Copyright (C) 2012 Pali Rohár Mk II protocol is the only protocol which can be used to flash eMMC images. NOLO does not support eMMC, so flashing eMMC is done in Maemo system. NOLO will boot device into "update" mode and Maemo will start only softupd daemon (which is responsible for flashing from Maemo system) and load kernel driver g_softupd which handle USB communication to user space daemon. When device is in PC Suite mode Maemo system start softupd daemon and load kernel driver g_nokia which can also handle communication via Mk II protocol. Default Maemo flasher (v2.5.2 (Oct 21 2009)) support only some basic functions via Mk II protocol - it can send eMMC image to softupd server which flash it. But there is unofficial Maemo flasher (flasher v2.8.2 (Jan 8 2010)) distributed with omap aes kernel driver for Nokia RX-51 under name "flasher.rover" which support more functions. So "flasher.rover" is better for RE this protocol. Via Mk II protocol over usb with softupd daemon in device it is possible to flash any type of image except rootfs (xloader, secondary, kernel, mmc, cmt-2nd, cmt-algo, cmt-mcusw). Maemo system using same Mk II protocol over local TCP socket (server also provided by softupd) to update/flash system. Over usb are used only these functions for communication: usb_claim_interface (interface=1) usb_set_altinterface (alternate=1) usb_bulk_write (ep=1, timeout=5000) usb_bulk_read (ep=129, timeout=5000) For every (request) message which is send by host, server send back responce. Format of message every message is same. It has 6 bytes header and (at least) 4 bytes body. HEADER 4 bytes -- type of header 0x8810001B - out (sent by host: usb_bulk_write) 0x8800101B - in (received by host: usb_bulk_read) 2 bytes -- size of body (big endian) BODY 4 bytes -- type of message N bytes -- data Reply message data always starts with char 0x00 (except pong responce). Here are some sniffed messages from Nokia RX-51. First two messages seems to must be always protocol version exchange (first host ask for protocol version of server and then host send its protocol version). On RX-51 is used version "2". Ping: req_type = 0x00000000 res_type = 0x20000000 Get protocol version: req_type = 0x01010000 req_data = "/update/protocol_version" res_type = 0x21010000 res_data = 0x00 "2" Tell our protocol version: req_type = 0x02020000 req_data = "/update/host_protocol_version" 0x00 "2" res_type = 0x22020000 res_data = 0x00 Get device: req_type = 0x01030000 req_data = "/device/product_code" res_type = 0x21030000 res_data = 0x00 "RX-51" Get hwrev: req_type = 0x01040000 req_data = "/device/hw_build" res_type = 0x21040000 res_data = 0x00 "2101" Get image types: req_type = 0x01050000 req_data = "/update/supported_images" res_type = 0x21050000 res_data = 0x00 "xloader,secondary,kernel,mmc,cmt-2nd,cmt-algo,cmt-mcusw" Reboot device: req_type = 0x0C060000 req_data = "reboot" res_type = 0x2C060000 res_data = 0x00 0xffff-0.6~git20130406/doc/nokia-tips000066400000000000000000000073451213002553000170260ustar00rootroot00000000000000Nokia tips: When developing this tool I've found some bugs and misfeatures that should be fixed to make flashing safer and cleaner. Before reading the list of the following items I would like to say that Nokia has done a wonderful work on this device on the flashing/nolo parts, it's really hard to break the device and it works pretty nice. BTW I think that there are some things that should be fixed. *) Flashing at low battery level When the device is under a certain limit of battery it will not start, this is done by initfs, without any warning message or so, this really scares end users, because the battery level check is done in the initfs boot stage, not inside NOLO, so it's possible to flash the device on low level batteries. This is *really* dangerous and not very user friendly. *) Internal nolo state not reset'd It's possible to get nolo on a strange state that always returns error when flashing pieces, it's mandatory to reboot the device to recover the original nolo state and be able to flash again. This is an strange and not very clear to me. *) Buffer overflows The original nokia flasher has some buffer overflow bugs that should be fixed. They're safe for 99.9% of cases, but bofs on critical programs like this one should not be there. If nokia releases the source of the flasher it would be easier to make it better and safer. BTW the original flasher is much more secure and reliable than this one. *) Weird firmware format The (new and old) FIASCO firmware format is not a very clean format, it doesn't provide any checksumming facility to ensure that the contents of the firmware have been modified or incorrect, so i'll rather encourage to design and create a standard firmware format for embedded devices with checksumming, signatures, handling libraries, documentation and so. I'll happilly collaborate on the design of this open firmware format, and it would be used on all the open source-based devices to aim interoperability between devices and flashers, providing a more standard and reliable way of flashing devices. This will ease the development on new devices, so the information and the code could be revised and enhaced by zillions of eyes. *) Poor checksumming The only checksum is a 16 bit xor of the whole firmware piece and it's only checked after sending the piece to the device. This is not very safe, because 16 bit checksum is a very low-quality algorithm. It currently performs a unique check at the end, it could be better to check each data block to avoid errors or invalid flashing, isn't it ? *) No validation of pieces before flashing I've implemented a minimal check of the pieces to avoid flashing invalid pieces on the wrong place. This is done in fpid.c (firmware piece identifier). This should avoid end users to flash initfs on the kernel or weird things that can (pseudo)brick the device. *) Reverse flashing If you want to test a new firmware, but you don't want to loose all the contents of your device. The only way to do that (afaik) is from the device. That's done with `0xFFFF -e [path]`. IMHO the reverse flashing (dump) should be implemented inside the bootloader (NOLO in this case), and allow to retrieve (at least) the most critical pieces of the firmware before flashing a new ones, and restore them in case of a wrong checksumming (for example) *) Documentation The nokia flasher comes as is, without documentation. This is not good to anybody, because the lack of information is always the root of problems, fear and ignorance. So giving a minimal documentation about how to use the flasher (not only the basic usage stuff (like the maemo community has done in the wiki) would be good for everybody. 0xffff-0.6~git20130406/doc/pieces000066400000000000000000000024441213002553000162130ustar00rootroot00000000000000Fiasco firmware pieces ====================== The firmware for the maemo devices is composed by a set of pieces containing the required parts to update the whole system following a partition layout defined by NOLO on the internal flash memory. Nokia provides a blob packed with a proprietary format called 'FIASCO'. This blob contains the following pieces: - 2nd - for Cold Flashing - xloader - first part of nolo - secondary - second part of nolo (usb support and launches kernel) - kernel - the kernel - initfs - initial system that initializes everything and runs rootfs - rootfs - the whole system image Some of these pieces are versioned to match board specific features (mostly xloader and secondary ones). To flash an initfs partition and reboot: $ 0xFFFF -m initfs:initfs.jffs2 -f -r The format of the argument is [[[device:[hw-revision:]]verion:]piece-type:]file-name[%layout-file-name] Pieces can be automatically identified by using the '-i' flag: $ 0xFFFF -m initfs.jffs2 -i You can dump these pieces from the internal memory of the internet tablet by using the mtd-utils over /dev/mtd* or just running: 770$ 0xFFFF -e /media/mmc1 There is another way for dumping pieces with extra parameters and options, read doc/dumping for more information. 0xffff-0.6~git20130406/doc/usage000066400000000000000000000060651213002553000160520ustar00rootroot000000000000000xFFFF v0.6 // The Free Fiasco Firmware Flasher Operations: -b [cmdline] boot default or loaded kernel (default: no cmdline) -b update boot default or loaded kernel to Update mode -r reboot device -l load kernel and initfs images to RAM -f flash all specified images -c cold flash 2nd and secondary image -x [/dev/mtd] check for bad blocks on mtd device (default: all) -E file dump all device images to one fiasco image, see -t -e [dir] dump all device images to directory, see -t (default: current) Device configuration: -I identify, show all information about device -D 0|1|2 change root device: 0 - flash, 1 - mmc, 2 - usb -U 0|1 disable/enable USB host mode -R 0|1 disable/enable R&D mode -F flags change R&D flags, flags are comma separated list, can be empty -H rev change HW revision -N ver change NOLO version string -K ver change kernel version string -T ver change initfs version string -S ver change SW release version string -C ver change content eMMC version string Input image specification: -M file specify fiasco image -m arg specify normal image arg is [[[dev:[hw:]]ver:]type:]file[%lay] dev is device name string (default: emtpy) hw are comma separated list of HW revisions (default: empty) ver is image version string (default: empty) type is image type (default: autodetect) file is image file name lay is layout file name (default: none) Image filters: -t types filter images by type -d dev filter images by device -w hw filter images by HW revision Fiasco image: -u [dir] unpack fiasco image to directory (default: current) -g file[%sw] generate fiasco image with SW rel version (default: no version) Other options: -i identify images -s simulate, do not flash or write on disk -n disable hash, checksum and image type checking -v be verbose and noisy -h show this help message R&D flags: no-omap-wd disable auto reboot by OMAP watchdog no-ext-wd disable auto reboot by external watchdog no-lifeguard-reset disable auto reboot by software lifeguard serial-console enable serial console no-usb-timeout disable usb timeout for flashing sti-console enable sti console no-charging disable battery charging force-power-key force omap boot reason to power key Supported devices: SU-18 Nokia 770 RX-34 Nokia N800 RX-44 Nokia N810 RX-48 Nokia N810 Wimax RX-51 Nokia N900 Supported image types: xloader 2nd secondary kernel initfs rootfs mmc cmt-2nd cmt-algo cmt-mcusw Supported connection protocols: Local on device NOLO via USB Cold flashing via USB Mk II protocol via USB RAW disk via USB 0xffff-0.6~git20130406/src/000077500000000000000000000000001213002553000150365ustar00rootroot000000000000000xffff-0.6~git20130406/src/Makefile000066400000000000000000000012161213002553000164760ustar00rootroot00000000000000include ../config.mk PREFIX ?= /usr/local INSTALL ?= install CPPFLAGS += -DVERSION=\"$(VERSION)\" -D_GNU_SOURCE CFLAGS += -W -Wall -O2 -pedantic -std=c99 LIBS += -lm -lusb OBJS = main.o nolo.o printf-utils.o image.o fiasco.o device.o usb-device.o cold-flash.o operations.o local.o mkii.o disk.o cal.o BIN = 0xFFFF all: $(BIN) $(BIN): $(OBJS) Makefile ../config.mk $(CC) $(CFLAGS) $(LDFLAGS) -o $(BIN) $(OBJS) $(LIBS) %.o: %.c Makefile ../config.mk $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< install: $(BIN) $(INSTALL) -D -m 755 $(BIN) $(DESTDIR)$(PREFIX)/bin/$(BIN) uninstall: $(RM) $(DESTDIR)$(PREFIX)/bin/$(BIN) clean: -$(RM) $(OBJS) $(BIN) 0xffff-0.6~git20130406/src/cal.c000066400000000000000000000122311213002553000157400ustar00rootroot00000000000000/* 0xFFFF - Open Free Fiasco Firmware Flasher Copyright (c) 2011 Michael Buesch Copyright (C) 2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* This is simple CAL parser form Calvaria */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cal.h" #define MAX_SIZE 393216 #define INDEX_LAST (0xFF + 1) #define HDR_MAGIC "ConF" struct cal { int fd; ssize_t size; void * mem; }; struct header { char magic[4]; /* Magic sequence */ uint8_t type; /* Type number */ uint8_t index; /* Index number */ uint16_t flags; /* Flags */ char name[16]; /* Human readable section name */ uint32_t length; /* Payload length */ uint32_t datasum; /* Data CRC32 checksum */ uint32_t hdrsum; /* Header CRC32 checksum */ } __attribute__((__packed__)); int cal_init_file(const char * file, struct cal ** cal_out) { int fd = -1; uint64_t blksize = 0; ssize_t size = 0; void * mem = NULL; struct cal * cal = NULL; struct stat st; mtd_info_t mtd_info; if ( stat(file, &st) != 0 ) return -1; fd = open(file, O_RDONLY); if ( fd < 0 ) return -1; if ( S_ISREG(st.st_mode) ) size = st.st_size; else if ( S_ISBLK(st.st_mode) ) { if ( ioctl(fd, BLKGETSIZE64, &blksize) != 0 ) goto err; if ( blksize > SSIZE_MAX ) goto err; size = blksize; } else if ( S_ISCHR(st.st_mode) && major(st.st_rdev) == 90 ) { if ( ioctl(fd, MEMGETINFO, &mtd_info) != 0 ) goto err; size = mtd_info.size; } else { goto err; } if ( size == 0 || size > MAX_SIZE ) goto err; mem = malloc(size); if ( ! mem ) goto err; if ( read(fd, mem, size) != size ) goto err; cal = malloc(sizeof(struct cal)); if ( ! cal ) goto err; cal->fd = fd; cal->mem = mem; cal->size = size; *cal_out = cal; return 0; err: close(fd); free(mem); return -1; } int cal_init(struct cal ** cal_out) { return cal_init_file("/dev/mtd1ro", cal_out); } void cal_finish(struct cal * cal) { if ( cal ) { free(cal->mem); free(cal); } } static uint32_t crc32(uint32_t crc, const void * _data, size_t size) { const uint8_t * data = _data; uint8_t value; unsigned int bit; size_t i; const uint32_t poly = 0xEDB88320; for ( i = 0; i < size; i++ ) { value = data[i]; for ( bit = 8; bit; bit-- ) { if ( (crc & 1) != (value & 1) ) crc = (crc >> 1) ^ poly; else crc >>= 1; value >>= 1; } } return crc; } static int is_header(void *data, size_t size) { struct header * hdr = data; if ( size < sizeof(struct header) ) return 0; if ( memcmp(hdr->magic, HDR_MAGIC, sizeof(hdr->magic)) != 0 ) return 0; return 1; } static int64_t find_section(void *start, uint64_t count, int want_index, const char *want_name) { int64_t offset = 0, found_offset = -1; uint8_t * data = start; struct header *hdr; char sectname[sizeof(hdr->name) + 1] = { 0, }; uint32_t payload_len; int previous_index = -1; while ( 1 ) { /* Find header start */ if ( count < sizeof(struct header) ) break; if ( ! is_header(data + offset, count) ) { count--; offset++; continue; } hdr = (struct header *)(data + offset); payload_len = hdr->length; if ( count - sizeof(struct header) < payload_len ) return -1; memcpy(sectname, hdr->name, sizeof(hdr->name)); if ( want_index == INDEX_LAST ) { if ((int)hdr->index <= previous_index) goto next; } else { if (want_index >= 0 && want_index != hdr->index) goto next; } if ( want_name && strcmp(sectname, want_name) != 0 ) goto next; /* Found it */ found_offset = offset; if ( want_index == INDEX_LAST ) previous_index = hdr->index; else break; next: count -= sizeof(struct header) + payload_len; offset += sizeof(struct header) + payload_len; } return found_offset; } int cal_read_block(struct cal * cal, const char * name, void ** ptr, unsigned long * len, unsigned long flags) { int64_t find_offset; uint64_t filelen = cal->size; uint8_t * data = cal->mem; struct header * hdr; find_offset = find_section(data, filelen, INDEX_LAST, name); if ( find_offset < 0 ) return -1; hdr = (struct header *)(data + find_offset); if ( flags && hdr->flags != flags ) return -1; if ( crc32(0, hdr, sizeof(*hdr) - 4) != hdr->hdrsum ) return -1; *ptr = data + find_offset + sizeof(struct header); *len = hdr->length; if ( crc32(0, *ptr, *len) != hdr->datasum ) return -1; return 0; } 0xffff-0.6~git20130406/src/cal.h000066400000000000000000000022721213002553000157510ustar00rootroot00000000000000/* 0xFFFF - Open Free Fiasco Firmware Flasher Copyright (c) 2011 Michael Buesch Copyright (C) 2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef CAL_H #define CAL_H #define CAL_MAX_NAME_LEN 16 #define CAL_FLAG_USER 0x0001 #define CAL_FLAG_WRITE_ONCE 0x0002 struct cal; int cal_init(struct cal ** cal_out); int cal_init_file(const char * file, struct cal ** cal_out); void cal_finish(struct cal * cal); int cal_read_block(struct cal * cal, const char * name, void ** ptr, unsigned long * len, unsigned long flags); #endif 0xffff-0.6~git20130406/src/cold-flash.c000066400000000000000000000242471213002553000172270ustar00rootroot00000000000000/* cold-flash.c - Cold flashing Copyright (C) 2011-2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include "global.h" #include "cold-flash.h" #include "image.h" #include "usb-device.h" #include "printf-utils.h" #define READ_DEV 0x81 #define WRITE_DEV 0x01 #define READ_TIMEOUT 500 #define WRITE_TIMEOUT 3000 static uint32_t tab[256]; static void crc32_gentab(void) { int i, j; uint32_t crc; uint32_t poly = 0xEDB88320L; for ( i = 0; i < 256; i++) { crc = i; for ( j = 8; j > 0; j-- ) { if (crc & 1) crc = (crc >> 1) ^ poly; else crc >>= 1; } tab[i] = crc; } } static uint32_t crc32(unsigned char * bytes, size_t size, uint32_t crc) { static int gen = 0; uint32_t i; if ( ! gen ) { crc32_gentab(); gen = 1; } for ( i = 0; i < size; ++i ) crc = (crc >> 8) ^ tab[(crc ^ bytes[i]) & 0xff]; return crc; } /* Omap Boot Messages */ /* See spruf98v.pdf (page 3444): OMAP35x Technical Reference Manual - 25.4.5 Periheral Booting */ /* Omap Peripheral boot message */ static const uint32_t omap_peripheral_msg = 0xF0030002; /* Omap Void (no device) boot message */ static const uint32_t omap_void_msg = 0xF0030006; /* Omap XIP memory boot message */ static const uint32_t omap_xip_msg = 0xF0030106; /* Omap Nand boot message */ static const uint32_t omap_nand_msg = 0xF0030206; /* Omap OneNAND boot message */ static const uint32_t omap_onenand_msg = 0xF0030306; /* Omap DOC boot message */ static const uint32_t omap_doc_msg = 0xF0030406; /* Omap MMC/SD2 boot message */ static const uint32_t omap_mmc2_msg = 0xF0030506; /* Omap MMC/SD1 boot message */ static const uint32_t omap_mmc1_msg = 0xF0030606; /* Omap XIP memory with wait monitoring boot message */ static const uint32_t omap_xipwait_msg = 0xF0030706; /* Omap UART boot message */ static const uint32_t omap_uart_msg = 0xF0031006; /* Omap HS USB boot message */ static const uint32_t omap_hsusb_msg = 0xF0031106; /* Omap next device boot message */ static const uint32_t omap_next_msg = 0xFFFFFFFF; /* Omap memory boot message */ static const uint32_t omap_memory_msg = 0; /* Nokia X-Loader messages */ /* Structure of X-Loader message */ struct xloader_msg { uint32_t type; /* 4 bytes - type of message */ uint32_t size; /* 4 bytes - size of file */ uint32_t crc1; /* 4 bytes - crc32 of file */ uint32_t crc2; /* 4 bytes - crc32 of first 12 bytes of message */ }; #define XLOADER_MSG_TYPE_PING 0x6301326E #define XLOADER_MSG_TYPE_SEND 0x6302326E struct xloader_msg xloader_msg_create(uint32_t type, struct image * image) { struct xloader_msg msg; uint32_t need, readed; int ret; uint8_t buffer[1024]; msg.type = type; msg.size = 0; msg.crc1 = 0; if ( image ) { msg.size = image->size; image_seek(image, 0); readed = 0; while ( readed < image->size ) { need = image->size - readed; if ( need > sizeof(buffer) ) need = sizeof(buffer); ret = image_read(image, buffer, need); if ( ret == 0 ) break; msg.crc1 = crc32(buffer, ret, msg.crc1); readed += ret; } } msg.crc2 = crc32((unsigned char *)&msg, 12, 0); return msg; } static int read_asic(usb_dev_handle * udev, uint8_t * asic_buffer, int size, int asic_size) { int ret; printf("Waiting for ASIC ID...\n"); ret = usb_bulk_read(udev, READ_DEV, (char *)asic_buffer, size, READ_TIMEOUT); if ( ret != asic_size ) ERROR_RETURN("Invalid size of ASIC ID", -1); return 0; } static int send_2nd(usb_dev_handle * udev, struct image * image) { uint8_t buffer[1024]; uint32_t need, readed; int ret; printf("Sending OMAP peripheral boot message...\n"); ret = usb_bulk_write(udev, WRITE_DEV, (char *)&omap_peripheral_msg, sizeof(omap_peripheral_msg), WRITE_TIMEOUT); usleep(5000); if ( ret != sizeof(omap_peripheral_msg) ) ERROR_RETURN("Sending OMAP peripheral boot message failed", -1); printf("Sending 2nd X-Loader image size...\n"); ret = usb_bulk_write(udev, WRITE_DEV, (char *)&image->size, 4, WRITE_TIMEOUT); usleep(5000); if ( ret != 4 ) ERROR_RETURN("Sending 2nd X-Loader image size failed", -1); printf("Sending 2nd X-Loader image...\n"); printf_progressbar(0, image->size); image_seek(image, 0); readed = 0; while ( readed < image->size ) { need = image->size - readed; if ( need > sizeof(buffer) ) need = sizeof(buffer); ret = image_read(image, buffer, need); if ( ret == 0 ) break; if ( usb_bulk_write(udev, WRITE_DEV, (char *)buffer, ret, WRITE_TIMEOUT) != ret ) PRINTF_ERROR_RETURN("Sending 2nd X-Loader image failed", -1); readed += ret; printf_progressbar(readed, image->size); } usleep(50000); return 0; } static int send_secondary(usb_dev_handle * udev, struct image * image) { struct xloader_msg init_msg; uint8_t buffer[1024]; uint32_t need, readed; int ret; init_msg = xloader_msg_create(XLOADER_MSG_TYPE_SEND, image); printf("Sending X-Loader init message...\n"); ret = usb_bulk_write(udev, WRITE_DEV, (char *)&init_msg, sizeof(init_msg), WRITE_TIMEOUT); usleep(5000); if ( ret != sizeof(init_msg) ) ERROR_RETURN("Sending X-Loader init message failed", -1); printf("Waiting for X-Loader response...\n"); ret = usb_bulk_read(udev, READ_DEV, (char *)&buffer, 4, READ_TIMEOUT); /* 4 bytes - dummy value */ if ( ret != 4 ) ERROR_RETURN("No response", -1); printf("Sending Secondary image...\n"); printf_progressbar(0, image->size); image_seek(image, 0); readed = 0; while ( readed < image->size ) { need = image->size - readed; if ( need > sizeof(buffer) ) need = sizeof(buffer); ret = image_read(image, buffer, need); if ( ret == 0 ) break; if ( usb_bulk_write(udev, WRITE_DEV, (char *)buffer, ret, WRITE_TIMEOUT) != ret ) PRINTF_ERROR_RETURN("Sending Secondary image failed", -1); readed += ret; printf_progressbar(readed, image->size); } usleep(5000); printf("Waiting for X-Loader response...\n"); ret = usb_bulk_read(udev, READ_DEV, (char *)&buffer, 4, READ_TIMEOUT); /* 4 bytes - dummy value */ if ( ret != 4 ) ERROR_RETURN("No response", -1); return 0; } static int ping_timeout(usb_dev_handle * udev) { int ret; int pong = 0; int try_ping = 10; while ( try_ping > 0 ) { struct xloader_msg ping_msg = xloader_msg_create(XLOADER_MSG_TYPE_PING, NULL); int try_read = 4; printf("Sending X-Loader ping message\n"); ret = usb_bulk_write(udev, WRITE_DEV, (char *)&ping_msg, sizeof(ping_msg), WRITE_TIMEOUT); if ( ret != sizeof(ping_msg) ) ERROR_RETURN("Sending X-Loader ping message faild", -1); printf("Waiting for X-Loader pong response...\n"); while ( try_read > 0 ) { uint32_t ping_read; ret = usb_bulk_read(udev, READ_DEV, (char *)&ping_read, sizeof(ping_read), READ_TIMEOUT); if ( ret == sizeof(ping_read) ) { printf("Got it\n"); pong = 1; break; } usleep(5000); --try_read; } if ( pong ) break; printf("Responce timeout\n"); --try_ping; } if (pong) return 0; else return -1; } int init_cold_flash(struct usb_device_info * dev) { uint8_t asic_buffer[127]; int asic_size = 69; const char * chip = NULL; int i; if ( dev->flash_device->protocol != FLASH_COLD ) ERROR_RETURN("Device is not in Cold Flash mode", -1); if ( read_asic(dev->udev, asic_buffer, sizeof(asic_buffer), asic_size) != 0 ) ERROR_RETURN("Reading ASIC ID failed", -1); if ( verbose ) { printf("Got ASIC ID:"); for ( i = 0; i < asic_size; ++i ) printf(" 0x%.2X", (unsigned int)asic_buffer[i]); printf("\n"); } /* TODO: Detect device from asic id */ /* ASIC ID specification: http://processors.wiki.ti.com/index.php/OMAP35x_and_AM/DM37x_Initialization#UART.2FUSB_Booting */ /* Number of subblocks */ if ( asic_buffer[0] != 0x05 ) ERROR_RETURN("Invalid ASIC ID", -1); /* ID Subblock - header */ if ( memcmp(asic_buffer+1, "\x01\x05\x01", 3) != 0 ) ERROR_RETURN("Invalid ASIC ID", -1); /* ID Subblock - OMAP chip version (check for OMAP3430 or 3630) */ if ( memcmp(asic_buffer+4, "\x34\x30\x07", 3) == 0 ) chip = "OMAP3430"; else if ( memcmp(asic_buffer+4, "\x36\x30\x07", 3) == 0 ) chip = "OMAP3630"; else ERROR_RETURN("Invalid ASIC ID", -1); /* Reserved1 - header */ if ( memcmp(asic_buffer+8, "\x13\x02\x01", 3) != 0 ) ERROR_RETURN("Invalid ASIC ID", -1); /* 2nd ID Subblock - header */ if ( memcmp(asic_buffer+12, "\x12\x15\x01", 3) != 0 ) ERROR_RETURN("Invalid ASIC ID", -1); /* Reserved2 - header */ if ( memcmp(asic_buffer+35, "\x14\x15\x01", 3) != 0 ) ERROR_RETURN("Invalid ASIC ID", -1); /* Checksum subblock - header */ if ( memcmp(asic_buffer+58, "\x15\x09\x01", 3) != 0 ) ERROR_RETURN("Invalid ASIC ID", -1); printf("Detected %s chip\n", chip); return 0; } int cold_flash(struct usb_device_info * dev, struct image * x2nd, struct image * secondary) { if ( x2nd->type != IMAGE_2ND ) ERROR_RETURN("Image type is not 2nd X-Loader", -1); if ( secondary->type != IMAGE_SECONDARY ) ERROR_RETURN("Image type is not Secondary", -1); if ( send_2nd(dev->udev, x2nd) != 0 ) ERROR_RETURN("Sending 2nd X-Loader image failed", -1); if ( ping_timeout(dev->udev) != 0 ) ERROR_RETURN("Sending X-Loader ping message failed", -1); if ( send_secondary(dev->udev, secondary) != 0 ) ERROR_RETURN("Sending Secondary image failed", -1); printf("Done\n"); return 0; } int leave_cold_flash(struct usb_device_info * dev) { int ret; printf("Sending OMAP memory boot message...\n"); ret = usb_bulk_write(dev->udev, WRITE_DEV, (char *)&omap_memory_msg, sizeof(omap_memory_msg), WRITE_TIMEOUT); usleep(5000); if ( ret != sizeof(omap_memory_msg) ) ERROR_RETURN("Sending OMAP memory boot message failed", -1); usleep(250000); return 0; } 0xffff-0.6~git20130406/src/cold-flash.h000066400000000000000000000023271213002553000172270ustar00rootroot00000000000000/* cold-flash.h - Cold flashing Copyright (C) 2011-2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef COLD_FLASH_H #define COLD_FLASH_H #include "image.h" #include "usb-device.h" /* Initialize Cold Flash mde */ int init_cold_flash(struct usb_device_info * dev); /* Flash 2nd and secondary image in Cold Flash mode. After flashing device will boot secondary image */ int cold_flash(struct usb_device_info * dev, struct image * x2nd, struct image * secondary); /* Leave Cold Flashing mode and continue booting */ int leave_cold_flash(struct usb_device_info * dev); #endif 0xffff-0.6~git20130406/src/device.c000066400000000000000000000134241213002553000164450ustar00rootroot00000000000000/* 0xFFFF - Open Free Fiasco Firmware Flasher Copyright (C) 2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include "global.h" #include "device.h" static const char * devices[] = { [DEVICE_SU_18] = "SU-18", [DEVICE_RX_34] = "RX-34", [DEVICE_RX_44] = "RX-44", [DEVICE_RX_48] = "RX-48", [DEVICE_RX_51] = "RX-51", }; enum device device_from_string(const char * device) { size_t i; if ( ! device || ! device[0] ) return DEVICE_ANY; for ( i = 0; i < sizeof(devices)/sizeof(devices[0]); ++i ) if ( devices[i] && strcmp(devices[i], device) == 0 ) return i; return DEVICE_UNKNOWN; } const char * device_to_string(enum device device) { if ( device >= sizeof(devices)/sizeof(devices[0]) ) return NULL; return devices[device]; } static const char * long_devices[] = { [DEVICE_SU_18] = "Nokia 770", [DEVICE_RX_34] = "Nokia N800", [DEVICE_RX_44] = "Nokia N810", [DEVICE_RX_48] = "Nokia N810 Wimax", [DEVICE_RX_51] = "Nokia N900", }; const char * device_to_long_string(enum device device) { if ( device >= sizeof(long_devices)/sizeof(long_devices[0]) ) return NULL; return long_devices[device]; } int hwrev_is_valid(const int16_t * hwrevs, int16_t hwrev) { int i; /* hwrevs not specified, valid for any hwrev */ if ( ! hwrevs ) return 1; for ( i = 0; hwrevs[i] != -1; ++i ) if ( hwrev == hwrevs[i] ) return 1; return 0; } int16_t * hwrevs_alloc_from_string(const char * str) { const char * ptr = str; const char * oldptr = ptr; int count = 2; int16_t * ret; int16_t tmp; int i; char buf[5]; if ( ! str ) return NULL; while ( (ptr = strchr(ptr, ',')) ) { ++count; ++ptr; } ret = calloc(count, sizeof(int16_t)); if ( ! ret ) return NULL; i = 0; ptr = str; while ( (ptr = strchr(ptr, ',')) ) { strncpy(buf, oldptr, ptr-oldptr); buf[4] = 0; tmp = atoi(buf); if ( tmp >= 0 ) ret[i++] = tmp; ++ptr; oldptr = ptr; } tmp = atoi(oldptr); if ( tmp >= 0 ) ret[i++] = tmp; ret[i++] = -1; return ret; } char * hwrevs_alloc_to_string(const int16_t * hwrevs) { char * ret; char * ptr; int i; int len = 0; for ( i = 0; hwrevs[i] != -1; ++i ) len += log10(hwrevs[i]+1)+2; ret = calloc(1, len+1); if ( ! ret ) return NULL; ptr = ret; for ( i = 0; hwrevs[i] != -1; ++i ) ptr += sprintf(ptr, "%d,", hwrevs[i]); *(ptr-1) = 0; return ret; } #define MAX_HWREVS 29 char ** device_list_alloc_to_bufs(const struct device_list * device_list) { int count = 0; int size = 0; const char * device; const struct device_list * device_first; char ** ret; char * last_ptr; int i, j, k; device_first = device_list; while ( device_first ) { int local = 0; if ( ! device_to_string(device_first->device) ) { device_first = device_first->next; continue; } for ( i = 0; device_first->hwrevs[i] != -1; ++i ) if ( device_first->hwrevs[i] >= 0 && device_first->hwrevs[i] <= 9999 ) ++local; size += (1+16+(MAX_HWREVS+1)*8)*(local/MAX_HWREVS+1); count += local/MAX_HWREVS; if ( local%MAX_HWREVS != 0 || local == 0 ) ++count; device_first = device_first->next; } ret = calloc(1, (count+1)*sizeof(char *) + size); if ( ! ret ) return NULL; j = 0; last_ptr = (char *)ret + (count+1)*sizeof(char *); device_first = device_list; while ( device_first ) { i = -1; device = device_to_string(device_first->device); if ( ! device ) { device_first = device_first->next; continue; } while ( device_first->hwrevs[i+1] != -1 ) { uint8_t len = 0; ret[j] = ++last_ptr; strncpy(ret[j]+1, device, 16); last_ptr += 16; len += 16; k = 0; for ( k = 0; k < MAX_HWREVS; ++k ) { if ( device_first->hwrevs[i+1] == -1 ) break; ++i; if ( device_first->hwrevs[i] < 0 || device_first->hwrevs[i] > 9999 ) continue; snprintf(ret[j]+1+16+k*8, 8, "%d", device_first->hwrevs[i]); last_ptr += 8; len += 8; } ((uint8_t*)ret[j])[0] = len; ++j; } device_first = device_first->next; } ret[j] = NULL; return ret; } struct device_list * device_list_alloc_from_buf(const char * buf, size_t size) { int i; int len; int count; char str[17]; const char * ptr1; const char * ptr; struct device_list * ret; ret = calloc(1, sizeof(struct device_list)); if ( ! ret ) return NULL; len = strnlen(buf, size); if ( len > 16 ) len = 16; memset(str, 0, sizeof(str)); memcpy(str, buf, len); ptr1 = buf + len; ret->device = device_from_string(str); ptr = ptr1; count = 1; while ( ptr < buf + size ) { while ( ptr < buf + size && *ptr < 32 ) ++ptr; if ( ptr >= buf + size ) break; len = strnlen(ptr, buf + size - ptr); if ( len > 8 ) len = 8; ptr += len + 1; ++count; } ret->hwrevs = calloc(count, sizeof(int16_t)); if ( ! ret->hwrevs ) return ret; ptr = ptr1; i = 0; while ( ptr < buf + size ) { while ( ptr < buf + size && *ptr < 32 ) ++ptr; if ( ptr >= buf + size ) break; len = strnlen(ptr, buf + size - ptr); if ( len > 8 ) len = 8; memset(str, 0, sizeof(str)); memcpy(str, ptr, len); ptr += len + 1; ret->hwrevs[i++] = atoi(str); } ret->hwrevs[i] = -1; return ret; } 0xffff-0.6~git20130406/src/device.h000066400000000000000000000033521213002553000164510ustar00rootroot00000000000000/* 0xFFFF - Open Free Fiasco Firmware Flasher Copyright (C) 2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef DEVICE_H #define DEVICE_H #include enum device { DEVICE_UNKNOWN = 0, DEVICE_ANY, /* Unspecified / Any device */ DEVICE_SU_18, /* Nokia 770 */ DEVICE_RX_34, /* Nokia N800 */ DEVICE_RX_44, /* Nokia N810 */ DEVICE_RX_48, /* Nokia N810 WiMax */ DEVICE_RX_51, /* Nokia N900 */ DEVICE_COUNT, }; /* hwrevs - array of int16_t - terminated by -1 - valid numbers: 0-9999 */ struct device_list { enum device device; int16_t * hwrevs; struct device_list * next; }; enum device device_from_string(const char * device); const char * device_to_string(enum device device); const char * device_to_long_string(enum device device); int hwrev_is_valid(const int16_t * hwrevs, int16_t hwrev); int16_t * hwrevs_alloc_from_string(const char * str); char * hwrevs_alloc_to_string(const int16_t * hwrevs); char ** device_list_alloc_to_bufs(const struct device_list * device_list); struct device_list * device_list_alloc_from_buf(const char * buf, size_t size); #endif 0xffff-0.6~git20130406/src/disk.c000066400000000000000000000074711213002553000161450ustar00rootroot00000000000000/* 0xFFFF - Open Free Fiasco Firmware Flasher Copyright (C) 2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include "disk.h" #include "global.h" #include "image.h" #include "device.h" #include "usb-device.h" #include "printf-utils.h" static char global_buf[1 << 22]; /* 4MB */ int disk_init(struct usb_device_info * dev) { ERROR("RAW mode is not implemented yet"); (void)dev; return -1; } enum device disk_get_device(struct usb_device_info * dev) { ERROR("Not implemented yet"); (void)dev; return DEVICE_UNKNOWN; } int disk_flash_raw(const char * blkdev, const char * file) { ERROR("Not implemented yet"); (void)blkdev; (void)file; return -1; } int disk_flash_image(struct usb_device_info * dev, struct image * image) { ERROR("Not implemented yet"); (void)dev; (void)image; return -1; } int disk_dump_raw(const char * blkdev, const char * file) { int fd1, fd2; int ret; char * path; uint64_t blksize; size_t need, readed; ssize_t size; struct stat st; struct statvfs buf; printf("Dump block device %s to file %s...\n", blkdev, file); if ( stat(blkdev, &st) != 0 ) { ERROR_INFO("Cannot stat block device %s", blkdev); return -1; } if ( ! S_ISBLK(st.st_mode) ) { ERROR("Invalid block device %s", blkdev); return -1; } fd1 = open(blkdev, O_RDONLY); if ( fd1 < 0 ) { ERROR_INFO("Cannot open block device %s", blkdev); return -1; } if ( ioctl(fd1, BLKGETSIZE64, &blksize) != 0 ) { ERROR_INFO("Cannot get size of block device %s", blkdev); close(fd1); return -1; } if ( blksize > ULLONG_MAX ) { ERROR("Block device %s is too big", blkdev); close(fd1); return -1; } if ( blksize == 0 ) { ERROR("Block device %s has zero size", blkdev); close(fd1); return -1; } path = strdup(file); if ( ! path ) { ALLOC_ERROR(); close(fd1); return -1; } ret = statvfs(dirname(path), &buf); free(path); if ( ret == 0 && buf.f_bsize * buf.f_bfree < blksize ) { ERROR("Not enought free space (have: %llu, need: %llu)", (unsigned long long int)(buf.f_bsize) * buf.f_bfree, (unsigned long long int)blksize); close(fd1); return -1; } fd2 = creat(file, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if ( fd2 < 0 ) { ERROR_INFO("Cannot create file %s", file); close(fd1); return -1; } readed = 0; printf_progressbar(0, blksize); while ( readed < blksize ) { need = blksize - readed; if ( need > sizeof(global_buf) ) need = sizeof(global_buf); size = read(fd1, global_buf, need); if ( size == 0 ) break; if ( write(fd2, global_buf, size) != size ) { PRINTF_ERROR("Dumping image failed"); close(fd1); close(fd2); return -1; } readed += size; printf_progressbar(readed, blksize); } close(fd1); close(fd2); return 0; } int disk_dump_image(struct usb_device_info * dev, enum image_type image, const char * file) { ERROR("Not implemented yet"); (void)dev; (void)image; (void)file; return -1; } int disk_check_badblocks(struct usb_device_info * dev, const char * device) { ERROR("Not implemented yet"); (void)dev; (void)device; return -1; } 0xffff-0.6~git20130406/src/disk.h000066400000000000000000000024741213002553000161500ustar00rootroot00000000000000/* 0xFFFF - Open Free Fiasco Firmware Flasher Copyright (C) 2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef DISK_H #define DISK_H #include "image.h" #include "device.h" #include "usb-device.h" int disk_init(struct usb_device_info * dev); enum device disk_get_device(struct usb_device_info * dev); int disk_flash_raw(const char * blkdev, const char * file); int disk_dump_raw(const char * blkdev, const char * file); int disk_flash_image(struct usb_device_info * dev, struct image * image); int disk_dump_image(struct usb_device_info * dev, enum image_type image, const char * file); int disk_check_badblocks(struct usb_device_info * dev, const char * device); #endif 0xffff-0.6~git20130406/src/fiasco.c000066400000000000000000000325501213002553000164530ustar00rootroot00000000000000/* 0xFFFF - Open Free Fiasco Firmware Flasher Copyright (C) 2007-2011 pancake Copyright (C) 2011-2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include "global.h" #include "device.h" #include "image.h" #include "fiasco.h" #define FIASCO_READ_ERROR(fiasco, ...) do { ERROR_INFO(__VA_ARGS__); fiasco_free(fiasco); return NULL; } while (0) #define FIASCO_WRITE_ERROR(file, fd, ...) do { ERROR_INFO_STR(file, __VA_ARGS__); if ( fd >= 0 ) close(fd); return -1; } while (0) #define READ_OR_FAIL(fiasco, buf, size) do { if ( read(fiasco->fd, buf, size) != size ) { FIASCO_READ_ERROR(fiasco, "Cannot read %d bytes", size); } } while (0) #define READ_OR_RETURN(fiasco, buf, size) do { if ( read(fiasco->fd, buf, size) != size ) return fiasco; } while (0) #define WRITE_OR_FAIL(file, fd, buf, size) do { if ( ! simulate ) { if ( write(fd, buf, size) != (ssize_t)size ) { FIASCO_WRITE_ERROR(file, fd, "Cannot write %d bytes", size); } } } while (0) struct fiasco * fiasco_alloc_empty(void) { struct fiasco * fiasco = calloc(1, sizeof(struct fiasco)); if ( ! fiasco ) ALLOC_ERROR_RETURN(NULL); fiasco->fd = -1; return fiasco; } struct fiasco * fiasco_alloc_from_file(const char * file) { uint8_t byte; uint32_t length; uint32_t count; uint8_t length8; uint8_t count8; char type[13]; char device[17]; char hwrevs[1024]; char version[257]; char layout[257]; uint16_t hash; off_t offset; struct image * image; char hwrev[9]; unsigned char buf[512]; unsigned char *pbuf; struct fiasco * fiasco = fiasco_alloc_empty(); if ( ! fiasco ) return NULL; fiasco->fd = open(file, O_RDONLY); if ( fiasco->fd < 0 ) { ERROR_INFO("Cannot open file"); fiasco_free(fiasco); return NULL; } fiasco->orig_filename = strdup(file); READ_OR_FAIL(fiasco, &byte, 1); if ( byte != 0xb4 ) FIASCO_READ_ERROR(fiasco, "Invalid fiasco signature"); READ_OR_FAIL(fiasco, &length, 4); length = ntohl(length); READ_OR_FAIL(fiasco, &count, 4); count = ntohl(count); VERBOSE("Number of header blocks: %d\n", count); while ( count > 0 ) { READ_OR_FAIL(fiasco, &byte, 1); READ_OR_FAIL(fiasco, &length8, 1); READ_OR_FAIL(fiasco, buf, length8); if ( byte == 0xe8 ) { memset(fiasco->name, 0, sizeof(fiasco->name)); strncpy(fiasco->name, (char *)buf, length8); VERBOSE("Fiasco name: %s\n", fiasco->name); } else if ( byte == 0x31 ) { memset(fiasco->swver, 0, sizeof(fiasco->swver)); strncpy(fiasco->swver, (char *)buf, length8); VERBOSE("SW version: %s\n", fiasco->swver); } else { VERBOSE("Unknown header %#x\n", byte); } --count; } /* walk the tree */ while ( 1 ) { /* If end of file, return fiasco image */ READ_OR_RETURN(fiasco, buf, 7); /* Header of next image */ if ( ! buf[0] == 0x54 && buf[2] == 0x2E && buf[3] == 0x19 && buf[4] == 0x01 && buf[5] == 0x01 && buf[6] == 0x00 ) { ERROR("Invalid next image header"); return fiasco; } count8 = buf[1]; if ( count8 > 0 ) --count8; READ_OR_RETURN(fiasco, &hash, 2); hash = ntohs(hash); memset(type, 0, sizeof(type)); READ_OR_RETURN(fiasco, type, 12); byte = type[0]; if ( byte == 0xFF ) return fiasco; VERBOSE(" %s\n", type); READ_OR_RETURN(fiasco, &length, 4); length = ntohl(length); /* unknown */ READ_OR_RETURN(fiasco, buf, 4); VERBOSE(" size: %d bytes\n", length); VERBOSE(" hash: %#04x\n", hash); VERBOSE(" subsections: %d\n", count8); memset(device, 0, sizeof(device)); memset(hwrevs, 0, sizeof(hwrevs)); memset(version, 0, sizeof(version)); memset(layout, 0, sizeof(layout)); while ( count8 > 0 ) { READ_OR_RETURN(fiasco, &byte, 1); READ_OR_RETURN(fiasco, &length8, 1); READ_OR_RETURN(fiasco, buf, length8); VERBOSE(" subinfo\n"); VERBOSE(" length: %d\n", length8); VERBOSE(" type: "); if ( byte == '1' ) { memset(version, 0, sizeof(version)); strncpy(version, (char *)buf, length8); VERBOSE("version string\n"); VERBOSE(" version: %s\n", version); } else if ( byte == '2' ) { int tmp = length8; if ( tmp > 16 ) tmp = 16; memset(device, 0, sizeof(device)); strncpy(device, (char *)buf, tmp); VERBOSE("hw revision\n"); VERBOSE(" device: %s\n", device); pbuf = buf + strlen(device) + 1; while ( pbuf < buf + length8 ) { while ( pbuf < buf + length8 && *pbuf < 32 ) ++pbuf; if ( pbuf >= buf + length8 ) break; tmp = buf + length8 - pbuf; if ( tmp > 8 ) tmp = 8; memset(hwrev, 0, sizeof(hwrev)); strncpy(hwrev, (char *)pbuf, tmp); if ( ! hwrevs[0] ) strcpy(hwrevs, hwrev); else { /* TODO: check if hwrevs has enought size */ strcat(hwrevs, ","); strcat(hwrevs, hwrev); } VERBOSE(" hw revision: %s\n", hwrev); pbuf += strlen(hwrev) + 1; } } else if ( byte == '3' ) { memset(layout, 0, sizeof(layout)); strncpy(layout, (char *)buf, length8); VERBOSE("layout\n"); } else { VERBOSE("unknown ('%c':%#x)\n", byte, byte); } --count8; } /* unknown */ READ_OR_RETURN(fiasco, buf, 1); offset = lseek(fiasco->fd, 0, SEEK_CUR); VERBOSE(" version: %s\n", version); VERBOSE(" device: %s\n", device); VERBOSE(" hwrevs: %s\n", hwrevs); VERBOSE(" data at: %#08x\n", (unsigned int)offset); image = image_alloc_from_shared_fd(fiasco->fd, length, offset, hash, type, device, hwrevs, version, layout); if ( ! image ) FIASCO_READ_ERROR(fiasco, "Cannot allocate image"); fiasco_add_image(fiasco, image); lseek(fiasco->fd, offset+length, SEEK_SET); } return fiasco; } void fiasco_free(struct fiasco * fiasco) { struct image_list * list = fiasco->first; while ( list ) { struct image_list * next = list->next; image_list_del(list); list = next; } if ( fiasco->fd >= 0 ) close(fiasco->fd); free(fiasco->orig_filename); free(fiasco); } void fiasco_add_image(struct fiasco * fiasco, struct image * image) { image_list_add(&fiasco->first, image); } int fiasco_write_to_file(struct fiasco * fiasco, const char * file) { int fd = -1; int i; int device_count; uint32_t size; uint32_t length; uint16_t hash; uint8_t length8; char ** device_hwrevs_bufs; const char * str; const char * type; struct image_list * image_list; struct image * image; unsigned char buf[4096]; if ( ! fiasco ) return -1; printf("Generating Fiasco image %s...\n", file); if ( ! fiasco->first ) FIASCO_WRITE_ERROR(file, fd, "Nothing to write"); if ( fiasco->name && strlen(fiasco->name)+1 > UINT8_MAX ) FIASCO_WRITE_ERROR(file, fd, "Fiasco name string is too long"); if ( fiasco->swver && strlen(fiasco->swver)+1 > UINT8_MAX ) FIASCO_WRITE_ERROR(file, fd, "SW version string is too long"); if ( ! simulate ) { fd = open(file, O_RDWR|O_CREAT|O_TRUNC, 0644); if ( fd < 0 ) { ERROR_INFO("Cannot create file"); return -1; } } printf("Writing Fiasco header...\n"); WRITE_OR_FAIL(file, fd, "\xb4", 1); /* signature */ if ( fiasco->name[0] ) str = fiasco->name; else str = "OSSO UART+USB"; length = 4 + strlen(str) + 3; if ( fiasco->swver[0] ) length += strlen(fiasco->swver) + 3; length = htonl(length); WRITE_OR_FAIL(file, fd, &length, 4); /* FW header length */ if ( fiasco->swver[0] ) length = htonl(2); else length = htonl(1); WRITE_OR_FAIL(file, fd, &length, 4); /* FW header blocks count */ /* Fiasco name */ length8 = strlen(str)+1; WRITE_OR_FAIL(file, fd, "\xe8", 1); WRITE_OR_FAIL(file, fd, &length8, 1); WRITE_OR_FAIL(file, fd, str, length8); /* SW version */ if ( fiasco->swver[0] ) { printf("Writing SW version: %s\n", fiasco->swver); length8 = strlen(fiasco->swver)+1; WRITE_OR_FAIL(file, fd, "\x31", 1); WRITE_OR_FAIL(file, fd, &length8, 1); WRITE_OR_FAIL(file, fd, fiasco->swver, length8); }; printf("\n"); image_list = fiasco->first; while ( image_list ) { image = image_list->image; if ( ! image ) FIASCO_WRITE_ERROR(file, fd, "Empty image"); printf("Writing image...\n"); image_print_info(image); type = image_type_to_string(image->type); device_hwrevs_bufs = device_list_alloc_to_bufs(image->devices); device_count = 0; if ( device_hwrevs_bufs && device_hwrevs_bufs[0] ) for ( ; device_hwrevs_bufs[device_count]; ++device_count ); if ( ! type ) FIASCO_WRITE_ERROR(file, fd, "Unknown image type"); if ( image->version && strlen(image->version) > UINT8_MAX ) FIASCO_WRITE_ERROR(file, fd, "Image version string is too long"); if ( image->layout && strlen(image->layout) > UINT8_MAX ) FIASCO_WRITE_ERROR(file, fd, "Image layout is too long"); printf("Writing image header...\n"); /* signature */ WRITE_OR_FAIL(file, fd, "T", 1); /* number of subsections */ length8 = device_count+1; if ( image->version ) ++length8; if ( image->layout ) ++length8; WRITE_OR_FAIL(file, fd, &length8, 1); /* unknown */ WRITE_OR_FAIL(file, fd, "\x2e\x19\x01\x01\x00", 5); /* checksum */ hash = htons(image->hash); WRITE_OR_FAIL(file, fd, &hash, 2); /* image type name */ memset(buf, 0, 12); strncpy((char *)buf, type, 12); WRITE_OR_FAIL(file, fd, buf, 12); /* image size */ size = htonl(image->size); WRITE_OR_FAIL(file, fd, &size, 4); /* unknown */ WRITE_OR_FAIL(file, fd, "\x00\x00\x00\x00", 4); /* append version subsection */ if ( image->version ) { WRITE_OR_FAIL(file, fd, "1", 1); /* 1 - version */ length8 = strlen(image->version)+1; WRITE_OR_FAIL(file, fd, &length8, 1); WRITE_OR_FAIL(file, fd, image->version, length8); } /* append device & hwrevs subsection */ for ( i = 0; i < device_count; ++i ) { WRITE_OR_FAIL(file, fd, "2", 1); /* 2 - device & hwrevs */ WRITE_OR_FAIL(file, fd, &device_hwrevs_bufs[i][0], 1); WRITE_OR_FAIL(file, fd, device_hwrevs_bufs[i]+1, ((uint8_t *)(device_hwrevs_bufs[i]))[0]); } free(device_hwrevs_bufs); /* append layout subsection */ if ( image->layout ) { length8 = strlen(image->layout); WRITE_OR_FAIL(file, fd, "3", 1); /* 3 - layout */ WRITE_OR_FAIL(file, fd, &length8, 1); WRITE_OR_FAIL(file, fd, image->layout, length8); } /* dummy byte - end of all subsections */ WRITE_OR_FAIL(file, fd, "\x00", 1); printf("Writing image data...\n"); image_seek(image, 0); while ( 1 ) { size = image_read(image, buf, sizeof(buf)); if ( size == 0 ) break; WRITE_OR_FAIL(file, fd, buf, size); } image_list = image_list->next; if ( image_list ) printf("\n"); } close(fd); printf("\nDone\n\n"); return 0; } int fiasco_unpack(struct fiasco * fiasco, const char * dir) { int fd = -1; char * name = NULL; char * layout_name = NULL; struct image * image; struct image_list * image_list; uint32_t size; char cwd[256]; unsigned char buf[4096]; if ( dir ) { memset(cwd, 0, sizeof(cwd)); if ( ! getcwd(cwd, sizeof(cwd)) ) { ERROR_INFO("Cannot store current directory"); return -1; } if ( chdir(dir) < 0 ) { ERROR_INFO("Cannot change current directory to %s", dir); return -1; } } fiasco_print_info(fiasco); image_list = fiasco->first; while ( image_list ) { image = image_list->image; name = image_name_alloc_from_values(image); if ( ! name ) return -1; printf("\n"); printf("Unpacking image...\n"); image_print_info(image); if ( image->layout ) { layout_name = calloc(1, strlen(name) + strlen(".layout") + 1); if ( ! layout_name ) ALLOC_ERROR_RETURN(-1); sprintf(layout_name, "%s.layout", name); printf(" Layout file: %s\n", layout_name); } printf(" Output file: %s\n", name); if ( ! simulate ) { fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0644); if ( fd < 0 ) { ERROR_INFO("Cannot create output file %s", name); return -1; } } free(name); image_seek(image, 0); while ( 1 ) { size = image_read(image, buf, sizeof(buf)); if ( size == 0 ) break; WRITE_OR_FAIL(name, fd, buf, size); } close(fd); if ( image->layout ) { if ( ! simulate ) { fd = open(layout_name, O_RDWR|O_CREAT|O_TRUNC, 0644); if ( fd < 0 ) { ERROR_INFO("Cannot create layout file %s", layout_name); return -1; } } free(layout_name); WRITE_OR_FAIL(layout_name, fd, image->layout, (int)strlen(image->layout)); close(fd); } image_list = image_list->next; } if ( dir ) { if ( chdir(cwd) < 0 ) { ERROR_INFO("Cannot change current directory back to %s", cwd); return -1; } } printf("\nDone\n\n"); return 0; } void fiasco_print_info(struct fiasco * fiasco) { if ( fiasco->orig_filename ) printf("File: %s\n", fiasco->orig_filename); if ( fiasco->name[0] ) printf(" Fiasco Name: %s\n", fiasco->name); if ( fiasco->swver[0] ) printf(" Fiasco Software release version: %s\n", fiasco->swver); } 0xffff-0.6~git20130406/src/fiasco.h000066400000000000000000000025671213002553000164650ustar00rootroot00000000000000/* 0xFFFF - Open Free Fiasco Firmware Flasher Copyright (C) 2007-2011 pancake Copyright (C) 2011-2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef FIASCO_H #define FIASCO_H #include "image.h" struct fiasco { char name[257]; char swver[257]; int fd; char * orig_filename; struct image_list * first; }; struct fiasco * fiasco_alloc_empty(void); struct fiasco * fiasco_alloc_from_file(const char * file); void fiasco_free(struct fiasco * fiasco); void fiasco_add_image(struct fiasco * fiasco, struct image * image); int fiasco_write_to_file(struct fiasco * fiasco, const char * file); int fiasco_unpack(struct fiasco * fiasco, const char * dir); void fiasco_print_info(struct fiasco * fiasco); #endif 0xffff-0.6~git20130406/src/global.h000066400000000000000000000021061213002553000164460ustar00rootroot00000000000000 #ifndef GLOBAL_H #define GLOBAL_H #include #include #include extern int simulate; extern int noverify; extern int verbose; #define VERBOSE(...) do { if ( verbose ) { fprintf(stderr, __VA_ARGS__); } } while (0) #define WARNING(...) do { fprintf(stderr, "Warning: "); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); } while (0) #define ERROR_INFO_STR(str, ...) do { if ( str[0] ) fprintf(stderr, "Error: %s: ", str); else fprintf(stderr, "Error: "); fprintf(stderr, __VA_ARGS__); if ( errno ) fprintf(stderr, ": %s\n", strerror(errno)); else fprintf(stderr, "\n"); } while (0) #define ERROR_STR(str, ...) do { errno = 0; ERROR_INFO_STR(str, __VA_ARGS__); } while (0) #define ERROR_INFO(...) do { ERROR_INFO_STR("", __VA_ARGS__); } while (0) #define ERROR(...) do { ERROR_STR("", __VA_ARGS__); } while (0) #define ERROR_RETURN(str, ...) do { ERROR("%s", str); return __VA_ARGS__; } while (0) #define ALLOC_ERROR() do { ERROR("Cannot allocate memory"); } while (0) #define ALLOC_ERROR_RETURN(...) do { ALLOC_ERROR(); return __VA_ARGS__; } while (0) #endif 0xffff-0.6~git20130406/src/image.c000066400000000000000000000327711213002553000162760ustar00rootroot00000000000000/* 0xFFFF - Open Free Fiasco Firmware Flasher Copyright (C) 2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include "global.h" #include "device.h" #include "image.h" #define IMAGE_STORE_CUR(image) do { if ( image->is_shared_fd ) { image->cur = lseek(image->fd, 0, SEEK_CUR) - image->offset; if ( image->cur > image->size ) image->cur = image->size; } } while (0) #define IMAGE_RESTORE_CUR(image) do { if ( image->is_shared_fd ) { if ( image->cur <= image->size ) lseek(image->fd, image->offset + image->cur, SEEK_SET); else lseek(image->fd, image->offset + image->size, SEEK_SET); } } while (0) /* format: type-device:hwrevs_version */ static void image_missing_values_from_name(struct image * image, const char * name) { char * str; char * ptr; char * ptr2; char * type = NULL; char * device = NULL; char * hwrevs = NULL; char * version = NULL; enum device new_device; str = strdup(name); if ( ! str ) return; ptr = strchr(str, '_'); if ( ptr ) { *ptr = 0; ++ptr; version = strdup(ptr); } ptr = strchr(str, '-'); if ( ptr ) { *ptr = 0; ++ptr; type = strdup(str); ptr2 = strchr(ptr, ':'); if ( ptr2 ) { *ptr2 = 0; ++ptr2; hwrevs = strdup(ptr2); } device = strdup(ptr); } else { type = strdup(str); } if ( ! image->type ) image->type = image_type_from_string(type); free(type); if ( ! image->devices || image->devices->device || image->devices->device == DEVICE_ANY ) { new_device = device_from_string(device); if ( new_device ) { if ( ! image->devices ) image->devices = calloc(1, sizeof(struct device_list)); if ( image->devices ) image->devices->device = new_device; } } free(device); if ( image->devices && image->devices->device && ! image->devices->hwrevs ) image->devices->hwrevs = hwrevs_alloc_from_string(hwrevs); else free(hwrevs); if ( ! image->version ) image->version = version; else free(version); free(str); } /* format: type-device:hwrevs_version */ char * image_name_alloc_from_values(struct image * image) { char * name; char * ptr; char * hwrevs; size_t length; const char * type; const char * device; type = image_type_to_string(image->type); if ( ! type ) type = "unknown"; if ( image->devices ) device = device_to_string(image->devices->device); else device = NULL; if ( image->devices && image->devices->hwrevs ) hwrevs = hwrevs_alloc_to_string(image->devices->hwrevs); else hwrevs = NULL; length = 1 + strlen(type); if ( device ) length += 1 + strlen(device); if ( hwrevs ) length += 1 + strlen(hwrevs); if ( image->version ) length += 1 + strlen(image->version); name = calloc(1, length); if ( ! name ) ALLOC_ERROR_RETURN(NULL); strcpy(name, type); ptr = name + strlen(name); if ( device ) ptr += sprintf(ptr, "-%s", device); if ( hwrevs ) ptr += sprintf(ptr, ":%s", hwrevs); if ( image->version ) ptr += sprintf(ptr, "_%s", image->version); free(hwrevs); return name; } static int image_append(struct image * image, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout) { enum image_type detected_type; image->hash = image_hash_from_data(image); image->devices = calloc(1, sizeof(struct device_list)); if ( ! image->devices ) return -1; image->devices->device = DEVICE_ANY; if ( device && device[0] ) { image->devices->device = device_from_string(device); if ( ! noverify && image->devices->device == DEVICE_UNKNOWN ) { ERROR("Specified Device %s is unknown", device); image_free(image); return -1; } } detected_type = image_type_from_data(image); image->type = detected_type; if ( type && type[0] ) { image->type = image_type_from_string(type); if ( ! noverify && image->type == IMAGE_UNKNOWN ) { ERROR("Specified Image type %s is unknown", type); image_free(image); return -1; } if ( ! noverify && detected_type != image->type && detected_type != IMAGE_UNKNOWN ) { ERROR("Image type mishmash (detected %s, got %s)", image_type_to_string(detected_type), type); image_free(image); return -1; } } if ( hwrevs && hwrevs[0] ) image->devices->hwrevs = hwrevs_alloc_from_string(hwrevs); else image->devices->hwrevs = NULL; if ( version && version[0] ) image->version = strdup(version); else image->version = NULL; if ( layout && layout[0] ) image->layout = strdup(layout); else image->layout = NULL; return 0; } static void image_align(struct image * image) { size_t align = 0; if ( image->type == IMAGE_MMC ) align = 8; else align = 7; if ( align == 0 ) return; if ( ( image->size & ( ( 1ULL << align ) - 1 ) ) == 0 ) return; align = ((image->size >> align) + 1) << align; image->align = align - image->size; image->size = align; image->hash = image_hash_from_data(image); } static struct image * image_alloc(void) { struct image * image = calloc(1, sizeof(struct image)); if ( ! image ) ALLOC_ERROR_RETURN(NULL); return image; } struct image * image_alloc_from_file(const char * file, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout) { struct image * image = image_alloc(); if ( ! image ) return NULL; image->is_shared_fd = 0; image->fd = open(file, O_RDONLY); if ( image->fd < 0 ) { ERROR_INFO("Cannot open image file %s", file); free(image); return NULL; } image->size = lseek(image->fd, 0, SEEK_END); image->offset = 0; image->cur = 0; image->orig_filename = strdup(file); lseek(image->fd, 0, SEEK_SET); if ( image_append(image, type, device, hwrevs, version, layout) < 0 ) return NULL; if ( ( ! type || ! type[0] ) && ( ! device || ! device[0] ) && ( ! hwrevs || ! hwrevs[0] ) && ( ! version || ! version[0] ) ) image_missing_values_from_name(image, file); image_align(image); return image; } struct image * image_alloc_from_shared_fd(int fd, size_t size, size_t offset, uint16_t hash, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout) { struct image * image = image_alloc(); if ( ! image ) return NULL; image->is_shared_fd = 1; image->fd = fd; image->size = size; image->offset = offset; image->cur = 0; if ( image_append(image, type, device, hwrevs, version, layout) < 0 ) return NULL; if ( ! noverify && image->hash != hash ) { ERROR("Image hash mishmash (counted %#04x, got %#04x)", image->hash, hash); image_free(image); return NULL; } image_align(image); return image; } void image_free(struct image * image) { if ( ! image ) return; if ( ! image->is_shared_fd ) { close(image->fd); image->fd = -1; } while ( image->devices ) { struct device_list * next = image->devices->next; free(image->devices->hwrevs); free(image->devices); image->devices = next; } free(image->version); free(image->layout); free(image->orig_filename); free(image); } void image_seek(struct image * image, size_t whence) { if ( whence > image->size ) return; if ( whence >= image->size - image->align ) { lseek(image->fd, image->size - image->align - 1, SEEK_SET); image->acur = whence - ( image->size - image->align ); } else { lseek(image->fd, image->offset + whence, SEEK_SET); image->acur = 0; } IMAGE_STORE_CUR(image); } size_t image_read(struct image * image, void * buf, size_t count) { size_t cur; ssize_t ret; size_t new_count = 0; size_t ret_count = 0; IMAGE_RESTORE_CUR(image); if ( ! image->is_shared_fd || image->cur < image->size - image->align ) { if ( image->is_shared_fd && image->cur + count > image->size - image->align ) new_count = image->size - image->align - image->cur; else new_count = count; ret = read(image->fd, buf, new_count); if ( ret > 0 ) ret_count += ret; IMAGE_STORE_CUR(image); if ( ret < 0 ) return ret; } if ( ret_count == count ) return ret_count; cur = lseek(image->fd, 0, SEEK_CUR) - image->offset; if ( image->align && cur == image->size - image->align && image->acur < image->align ) { if ( image->acur + count - ret_count > image->align ) new_count = image->align - image->acur; else new_count = count - ret_count; memset((unsigned char *)buf+ret_count, 0xFF, new_count); ret_count += new_count; image->acur += new_count; } return ret_count; } void image_list_add(struct image_list ** list, struct image * image) { struct image_list * last = calloc(1, sizeof(struct image_list)); if ( ! last ) ALLOC_ERROR_RETURN(); last->image = image; if ( ! *list ) { *list = last; return; } while ( (*list)->next ) list = &((*list)->next); last->prev = *list; (*list)->next = last; } void image_list_del(struct image_list * list) { if ( ! list ) return; image_list_unlink(list); image_free(list->image); free(list); } void image_list_unlink(struct image_list * list) { if ( ! list ) return; if ( list->prev ) list->prev->next = list->next; if ( list->next ) list->next->prev = list->prev; list->prev = NULL; list->next = NULL; } static uint16_t do_hash(uint16_t * b, int len) { uint16_t result = 0; for ( len >>= 1; len--; b = b+1 ) result^=b[0]; return result; } uint16_t image_hash_from_data(struct image * image) { unsigned char buf[0x20000]; uint16_t hash = 0; int ret; image_seek(image, 0); while ( ( ret = image_read(image, &buf, sizeof(buf)) ) ) hash ^= do_hash((uint16_t *)&buf, ret); return hash; } static const char * image_types[] = { [IMAGE_XLOADER] = "xloader", [IMAGE_2ND] = "2nd", [IMAGE_SECONDARY] = "secondary", [IMAGE_KERNEL] = "kernel", [IMAGE_INITFS] = "initfs", [IMAGE_ROOTFS] = "rootfs", [IMAGE_MMC] = "mmc", [IMAGE_CMT_2ND] = "cmt-2nd", [IMAGE_CMT_ALGO] = "cmt-algo", [IMAGE_CMT_MCUSW] = "cmt-mcusw", }; enum image_type image_type_from_data(struct image * image) { unsigned char buf[512]; memset(buf, 0, sizeof(buf)); image_seek(image, 0); image_read(image, buf, sizeof(buf)); if ( memcmp(buf+52, "2NDAPE", 6) == 0 ) return IMAGE_2ND; else if ( memcmp(buf+20, "2ND", 3) == 0 ) return IMAGE_2ND; else if ( memcmp(buf+4, "NOLOScnd", 8) == 0 ) return IMAGE_SECONDARY; else if ( memcmp(buf+20, "X-LOADER", 8) == 0 ) return IMAGE_XLOADER; else if ( memcmp(buf+12, "NOLOXldr", 8) == 0 ) return IMAGE_XLOADER; else if ( memcmp(buf+4, "NOLOXldr", 8) == 0 ) return IMAGE_2ND; else if ( memcmp(buf+36, "\x18\x28\x6f\x01", 4) == 0 ) /* ARM Linux kernel magic number */ return IMAGE_KERNEL; else if ( memcmp(buf, "\x14\x00\x00\xea", 4) == 0 ) /* ARM U-Boot - instruction branch +0x50 */ return IMAGE_KERNEL; else if ( memcmp(buf, "UBI#", 4) == 0 ) /* UBI EC header */ return IMAGE_ROOTFS; else if ( memcmp(buf+510, "\x55\xaa", 2) == 0 ) /* FAT boot sector signature */ return IMAGE_MMC; else if ( memcmp(buf, "\xb0\x00\x01\x03\x9d\x00\x00\x00", 8) == 0 ) return IMAGE_CMT_2ND; else if ( memcmp(buf, "\xb1\x00\x00\x00\x82\x00\x00\x00", 8) == 0 ) return IMAGE_CMT_ALGO; else if ( memcmp(buf, "\xb2\x00\x00\x01\x44\x00\x00\x00", 8) == 0 ) return IMAGE_CMT_MCUSW; else if ( memcmp(buf, "\x45\x3d\xcd\x28", 4) == 0 ) /* CRAMFS MAGIC */ return IMAGE_INITFS; else if ( memcmp(buf, "\x85\x19", 2) == 0 ) { /* JFFS2 MAGIC */ if ( image->size < 0x300000 ) return IMAGE_INITFS; else return IMAGE_ROOTFS; } return IMAGE_UNKNOWN; } enum image_type image_type_from_string(const char * type) { size_t i; if ( ! type ) return IMAGE_UNKNOWN; for ( i = 0; i < sizeof(image_types)/sizeof(image_types[0]); ++i ) if ( image_types[i] && strcmp(image_types[i], type) == 0 ) return i; return IMAGE_UNKNOWN; } const char * image_type_to_string(enum image_type type) { if ( type >= sizeof(image_types)/sizeof(image_types[0]) ) return NULL; return image_types[type]; } int image_hwrev_is_valid(struct image * image, int16_t hwrev) { struct device_list * device_ptr = image->devices; while ( device_ptr ) { if ( hwrev_is_valid(device_ptr->hwrevs, hwrev) ) return 1; device_ptr = device_ptr->next; } return 0; } void image_print_info(struct image * image) { const char * str; struct device_list * device = image->devices; if ( image->orig_filename ) printf("File: %s\n", image->orig_filename); str = image_type_to_string(image->type); printf(" Image type: %s\n", str ? str : "unknown"); printf(" Image size: %d bytes\n", image->size); if ( image->version ) printf(" Image version: %s\n", image->version); if ( image->layout ) printf(" Image layout: included\n"); while ( device ) { char * str2 = NULL; struct device_list * next = device->next; if ( device->device == DEVICE_UNKNOWN ) str = "unknown"; else str = device_to_string(device->device); if ( str ) printf(" Valid for: device %s", str); if ( str && device->hwrevs ) str2 = hwrevs_alloc_to_string(device->hwrevs); if ( str2 ) { printf(", HW revisions: %s\n", str2); free(str2); } else if ( str ) { printf("\n"); } device = next; } } 0xffff-0.6~git20130406/src/image.h000066400000000000000000000047251213002553000163010ustar00rootroot00000000000000/* 0xFFFF - Open Free Fiasco Firmware Flasher Copyright (C) 2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef IMAGE_H #define IMAGE_H #include #include #include "device.h" enum image_type { IMAGE_UNKNOWN = 0, IMAGE_XLOADER, IMAGE_2ND, IMAGE_SECONDARY, IMAGE_KERNEL, IMAGE_INITFS, IMAGE_ROOTFS, IMAGE_MMC, IMAGE_CMT_2ND, IMAGE_CMT_ALGO, IMAGE_CMT_MCUSW, IMAGE_COUNT, }; struct image { enum image_type type; struct device_list * devices; char * version; char * layout; uint16_t hash; uint32_t size; int fd; int is_shared_fd; uint32_t align; size_t offset; size_t cur; size_t acur; char * orig_filename; }; struct image_list { struct image * image; struct image_list * prev; struct image_list * next; }; struct image * image_alloc_from_file(const char * file, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout); struct image * image_alloc_from_shared_fd(int fd, size_t size, size_t offset, uint16_t hash, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout); void image_free(struct image * image); void image_seek(struct image * image, size_t whence); size_t image_read(struct image * image, void * buf, size_t count); void image_print_info(struct image * image); void image_list_add(struct image_list ** list, struct image * image); void image_list_del(struct image_list * list); void image_list_unlink(struct image_list * list); uint16_t image_hash_from_data(struct image * image); enum image_type image_type_from_data(struct image * image); char * image_name_alloc_from_values(struct image * image); enum image_type image_type_from_string(const char * type); const char * image_type_to_string(enum image_type type); int image_hwrev_is_valid(struct image * image, int16_t hwrev); #endif 0xffff-0.6~git20130406/src/libusb-sniff.c000066400000000000000000000127171213002553000175750ustar00rootroot00000000000000/* libusb-sniff.c - Library for usb sniffing nokia's flasher-3.5 Copyright (C) 2011-2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* compile: gcc libusb-sniff.c -o libusb-sniff.so -W -Wall -O2 -fPIC -ldl -shared -m32 */ /* usage: sudo USBSNIFF_WAIT=1 LD_PRELOAD=./libusb-sniff.so flasher-3.5 ... */ /* usage: sudo USBSNIFF_SKIP_READ=1 USBSNIFF_SKIP_WRITE=1 LD_PRELOAD=./libusb-sniff.so flasher-3.5 ... */ #define _GNU_SOURCE #include #include #include static char to_ascii(char c) { if ( c >= 32 && c <= 126 ) return c; return '.'; } static void dump_bytes(const char * buf, size_t size) { size_t i, ascii_cnt = 0; char ascii[17] = { 0, }; for ( i = 0; i < size; i++ ) { if ( i % 16 == 0 ) { if ( i != 0 ) { printf(" |%s|\n", ascii); ascii[0] = 0; ascii_cnt = 0; } printf("%04X:", (unsigned int)i); } printf(" %02X", buf[i] & 0xFF); ascii[ascii_cnt] = to_ascii(buf[i]); ascii[ascii_cnt + 1] = 0; ascii_cnt++; } if ( ascii[0] ) { if ( size % 16 ) for ( i = 0; i < 16 - (size % 16); i++ ) printf(" "); printf(" |%s|\n", ascii); } } int usb_bulk_write(usb_dev_handle * dev, int ep, const char * bytes, int size, int timeout) { static int (*real_usb_bulk_write)(usb_dev_handle * dev, int ep, const char * bytes, int size, int timeout) = NULL; if ( ! real_usb_bulk_write ) real_usb_bulk_write = dlsym(RTLD_NEXT, "usb_bulk_write"); if ( ! getenv("USBSNIFF_SKIP_WRITE") ) { printf("\n==== usb_bulk_write (ep=%d size=%d timeout=%d) ====\n", ep, size, timeout); dump_bytes(bytes, size); printf("====\n"); if ( getenv("USBSNIFF_WAIT") ) { printf("Press ENTER"); fflush(stdout); getchar(); } } return real_usb_bulk_write(dev, ep, bytes, size, timeout); } int usb_bulk_read(usb_dev_handle * dev, int ep, char * bytes, int size, int timeout) { static int (*real_usb_bulk_read)(usb_dev_handle * dev, int ep, char * bytes, int size, int timeout) = NULL; int ret; if ( ! real_usb_bulk_read ) real_usb_bulk_read = dlsym(RTLD_NEXT, "usb_bulk_read"); ret = real_usb_bulk_read(dev, ep, bytes, size, timeout); if ( ! getenv("USBSNIFF_SKIP_READ") ) { printf("\n==== usb_bulk_read (ep=%d size=%d timeout=%d) ret = %d ====\n", ep, size, timeout, ret); if ( ret > 0 ) { dump_bytes(bytes, ret); printf("====\n"); } if ( getenv("USBSNIFF_WAIT") ) { printf("Press ENTER"); fflush(stdout); getchar(); } } return ret; } int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout) { static int (*real_usb_control_msg)(usb_dev_handle *dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout) = NULL; int ret; if ( ! real_usb_control_msg ) real_usb_control_msg = dlsym(RTLD_NEXT, "usb_control_msg"); if ( requesttype == 64 && ! getenv("USBSNIFF_SKIP_CONTROL") ) { printf("\n==== usb_control_msg(requesttype=%d, request=%d, value=%d, index=%d, size=%d, timeout=%d) ====\n", requesttype, request, value, index, size, timeout); dump_bytes(bytes, size); printf("====\n"); if ( getenv("USBSNIFF_WAIT") ) { printf("Press ENTER"); fflush(stdout); getchar(); } } ret = real_usb_control_msg(dev, requesttype, request, value, index, bytes, size, timeout); if ( requesttype != 64 && ! getenv("USBSNIFF_SKIP_CONTROL") ) { printf("\n==== usb_control_msg(requesttype=%d, request=%d, value=%d, index=%d, size=%d, timeout=%d) ret = %d ====\n", requesttype, request, value, index, size, timeout, ret); if ( ret > 0 ) { dump_bytes(bytes, ret); printf("====\n"); } if ( getenv("USBSNIFF_WAIT") ) { printf("Press ENTER"); fflush(stdout); getchar(); } } return ret; } int usb_set_configuration(usb_dev_handle *dev, int configuration) { static int (*real_usb_set_configuration)(usb_dev_handle *dev, int configuration) = NULL; if ( ! real_usb_set_configuration ) real_usb_set_configuration = dlsym(RTLD_NEXT, "usb_set_configuration"); printf("\n==== usb_set_configuration (configuration=%d) ====\n", configuration); return real_usb_set_configuration(dev, configuration); } int usb_claim_interface(usb_dev_handle *dev, int interface) { static int (*real_usb_claim_interface)(usb_dev_handle *dev, int interface) = NULL; if ( ! real_usb_claim_interface ) real_usb_claim_interface = dlsym(RTLD_NEXT, "usb_claim_interface"); printf("\n==== usb_claim_interface (interface=%d) ====\n", interface); return real_usb_claim_interface(dev, interface); } int usb_set_altinterface(usb_dev_handle *dev, int alternate) { static int (*real_usb_set_altinterface)(usb_dev_handle *dev, int alternate) = NULL; if ( ! real_usb_set_altinterface ) real_usb_set_altinterface = dlsym(RTLD_NEXT, "usb_set_altinterface"); printf("\n==== usb_set_altinterface (alternate=%d) ====\n", alternate); return real_usb_set_altinterface(dev, alternate); } 0xffff-0.6~git20130406/src/local.c000066400000000000000000000267621213002553000163110ustar00rootroot00000000000000/* 0xFFFF - Open Free Fiasco Firmware Flasher Copyright (C) 2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include "local.h" #include "global.h" #include "device.h" #include "image.h" #include "cal.h" #include "disk.h" static int failed; static enum device device = DEVICE_UNKNOWN; static int16_t hwrev = -1; static char kernel_ver[256]; static char initfs_ver[256]; static char nolo_ver[256]; static char sw_ver[256]; static char content_ver[256]; static char rd_mode[256]; static int usb_host_mode = -1; static int root_device = -1; #define min(a, b) (a < b ? a : b) #define local_cal_copy(dest, from, len) strncpy(dest, from, min(len, sizeof(dest)-1)) #define local_cal_read(cal, str, ptr, len) ( cal_read_block(cal, str, &ptr, &len, 0) == 0 && ptr ) #define local_cal_store(cal, str, dest) do { void * ptr; unsigned long int len; if ( local_cal_read(cal, str, ptr, len) ) local_cal_copy(dest, ptr, len); } while ( 0 ) static void local_cal_parse(void) { struct cal * cal = NULL; char buf[128]; printf("Reading CAL...\n"); if ( cal_init(&cal) < 0 || ! cal ) return; local_cal_store(cal, "kernel-ver", kernel_ver); local_cal_store(cal, "initfs-ver", kernel_ver); local_cal_store(cal, "nolo-ver", nolo_ver); local_cal_store(cal, "sw-release-ver", sw_ver); local_cal_store(cal, "content-ver", content_ver); local_cal_store(cal, "r&d_mode", rd_mode); /* overwritten hw revision */ memset(buf, 0, sizeof(buf)); local_cal_store(cal, "hw-ver", buf); if ( buf[0] && sscanf(buf, "%hd", &hwrev) != 1 ) hwrev = -1; if ( hwrev == -1 ) { /* original hw revision */ memset(buf, 0, sizeof(buf)); local_cal_store(cal, "phone-info", buf); buf[4] = 0; if ( buf[0] && sscanf(buf, "%hd", &hwrev) != 1 ) hwrev = -1; } buf[0] = 0; local_cal_store(cal, "usb_host_mode", buf); usb_host_mode = buf[0]; memset(buf, 0, sizeof(buf)); local_cal_store(cal, "root_device", buf); if ( strcmp(buf, "mmc") == 0 ) root_device = 1; else if ( strcmp(buf, "usb") == 0 ) root_device = 2; else root_device = 0; cal_finish(cal); } int local_init(void) { char buf[1024]; char * ptr; char * ptr2; FILE * file; if ( failed ) return -1; file = fopen("/proc/cpuinfo", "r"); if ( ! file ) { failed = 1; return -1; } while ( fgets(buf, sizeof(buf), file) ) { if ( strncmp(buf, "Hardware", strlen("Hardware")) == 0 ) { ptr = buf + strlen("Hardware"); while ( ptr < buf + sizeof(buf) && *ptr > 0 && *ptr <= 32 ) ++ptr; if ( *ptr != ':' ) continue; ++ptr; while ( ptr < buf + sizeof(buf) && *ptr > 0 && *ptr <= 32 ) ++ptr; if ( ! *ptr ) continue; ptr2 = buf + strlen(buf); while ( *ptr2 <= 32 ) { *ptr2 = 0; --ptr2; } if ( strcmp(ptr, "Nokia 770") == 0 ) device = DEVICE_SU_18; else if ( strcmp(ptr, "Nokia N800") == 0 ) device = DEVICE_RX_34; else if ( strcmp(ptr, "Nokia N810") == 0 ) device = DEVICE_RX_44; else if ( strcmp(ptr, "Nokia N810 WiMAX") == 0 ) device = DEVICE_RX_48; else if ( strcmp(ptr, "Nokia RX-51 board") == 0 ) device = DEVICE_RX_51; if ( device ) { printf("Found local device: %s\n", device_to_long_string(device)); fclose(file); local_cal_parse(); return 0; } } } failed = 1; printf("Not a local device\n"); fclose(file); return -1; } enum device local_get_device(void) { return device; } int local_flash_image(struct image * image) { ERROR("Not implemented yet"); (void)image; return -1; } static int local_nanddump(const char * file, int mtd, int offset, int length) { struct statvfs buf; char * command; char * path; size_t size; int ret; path = strdup(file); if ( ! path ) return 1; ret = statvfs(dirname(path), &buf); free(path); if ( ret == 0 && buf.f_bsize * buf.f_bfree < (long unsigned int)length ) { ERROR("Not enought free space (have: %lu, need: %d)", buf.f_bsize * buf.f_bfree, length); return 1; } size = snprintf(NULL, 0, "nanddump -i -o -b -s %d -l %d -f %s /dev/mtd%dro", offset, length, file, mtd); command = malloc(size+1); if ( ! command ) return 1; snprintf(command, size+1, "nanddump -i -o -b -s %d -l %d -f %s /dev/mtd%dro", offset, length, file, mtd); ret = system(command); free(command); return ret; } struct nanddump_args { int valid; int mtd; int offset; int length; }; static struct nanddump_args nanddump_rx51[] = { [IMAGE_XLOADER] = { 1, 0, 0x00000000, 0x00004000 }, [IMAGE_SECONDARY] = { 1, 0, 0x00004000, 0x0001C000 }, [IMAGE_KERNEL] = { 1, 3, 0x00000800, 0x001FF800 }, [IMAGE_INITFS] = { 1, 4, 0x00000000, 0x00200000 }, [IMAGE_ROOTFS] = { 1, 5, 0x00000000, 0x0fb40000 }, }; /* FIXME: Is this table correct? */ static struct nanddump_args nanddump[] = { [IMAGE_XLOADER] = { 1, 0, 0x00000200, 0x00003E00 }, [IMAGE_SECONDARY] = { 1, 0, 0x00004000, 0x0001C000 }, [IMAGE_KERNEL] = { 1, 2, 0x00000800, 0x001FF800 }, [IMAGE_INITFS] = { 1, 3, 0x00000000, 0x00200000 }, [IMAGE_ROOTFS] = { 1, 4, 0x00000000, 0x0fb80000 }, }; int local_dump_image(enum image_type image, const char * file) { int ret = -1; int fd = -1; unsigned char * addr = NULL; off_t nlen, len; int align; DIR * dir; DIR * dir2; struct dirent * dirent; struct dirent * dirent2; char * ptr; int i; char buf[1024]; char blk[1024]; printf("Dump %s image to file %s...\n", image_type_to_string(image), file); if ( image == IMAGE_MMC ) { /* Find block device in /dev/ for MyDocs (mmc device, partition 1) */ dir = opendir("/sys/class/mmc_host/"); if ( ! dir ) { ERROR("Cannot find MyDocs mmc device"); goto clean; } blk[0] = 0; while ( ( dirent = readdir(dir) ) ) { snprintf(buf, sizeof(buf), "/sys/class/mmc_host/%s/slot_name", dirent->d_name); fd = open(buf, O_RDONLY); if ( fd < 0 ) continue; buf[0] = 0; read(fd, buf, sizeof(buf)); close(fd); if ( strncmp(buf, "internal", strlen("internal")) != 0 ) continue; snprintf(buf, sizeof(buf), "/sys/class/mmc_host/%s/%s:0001", dirent->d_name, dirent->d_name); dir2 = opendir(buf); if ( ! dir2 ) continue; while ( ( dirent2 = readdir(dir2) ) ) { if ( strncmp(dirent2->d_name, "block:mmcblk", strlen("block:mmcblk")) != 0 ) continue; snprintf(buf, sizeof(buf), "/sys/class/mmc_host/%s/%s:0001/%s", dirent->d_name, dirent->d_name, dirent2->d_name); blk[0] = 0; if ( readlink(buf, blk, sizeof(blk)) < 0 ) continue; ptr = strrchr(blk, '/'); if ( ! ptr ) { blk[0] = 0; continue; } strcpy(blk, "/dev/"); i = strlen("/dev/"); ++ptr; while ( *ptr ) blk[i++] = *(ptr++); strcpy(blk+i, "p1"); break; } closedir(dir2); if ( blk[0] ) break; } closedir(dir); if ( ! blk[0] ) { ERROR("Cannot find MyDocs mmc device"); goto clean; } ret = disk_dump_raw(blk, image_type_to_string(image)); } else { if ( device == DEVICE_RX_51 ) { if ( image >= sizeof(nanddump_rx51)/sizeof(nanddump_rx51[0]) || ! nanddump_rx51[image].valid ) { ERROR("Unsuported image type: %s", image_type_to_string(image)); goto clean; } ret = local_nanddump(file, nanddump_rx51[image].mtd, nanddump_rx51[image].offset, nanddump_rx51[image].length); } else { if ( image >= sizeof(nanddump)/sizeof(nanddump[0]) || ! nanddump[image].valid ) { ERROR("Unsuported image type: %s", image_type_to_string(image)); goto clean; } ret = local_nanddump(file, nanddump[image].mtd, nanddump[image].offset, nanddump[image].length); } } if ( ret != 0 ) { ret = -1; goto clean; } fd = open(file, O_RDWR); if ( fd < 0 ) goto clean; len = lseek(fd, 0, SEEK_END); if ( len == (off_t)-1 || len == 0 ) goto clean; addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); if ( addr == MAP_FAILED ) addr = NULL; if ( ! addr ) goto clean; for ( nlen = len; nlen > 0; --nlen ) if ( addr[nlen-1] != 0xFF ) break; if ( image == IMAGE_MMC ) align = 8; else align = 7; if ( ( nlen & ( ( 1ULL << align ) - 1 ) ) != 0 ) nlen = ((nlen >> align) + 1) << align; if ( nlen == 0 ) { printf("File %s is empty, removing it...\n", file); unlink(file); } else if ( nlen != len ) { printf("Truncating file %s to %d bytes...\n", file, (int)nlen); ftruncate(fd, nlen); } clean: if ( addr ) munmap(addr, len); if ( fd >= 0 ) close(fd); printf("\n"); return ret; } int local_check_badblocks(const char * device) { ERROR("Not implemented yet"); (void)device; return -1; } int local_reboot_device(void) { if ( system("dsmetool -b") == 0 ) return 0; return system("reboot"); } int local_get_root_device(void) { return root_device; } int local_set_root_device(int device) { ERROR("Not implemented yet"); (void)device; return -1; } int local_get_usb_host_mode(void) { return usb_host_mode; } int local_set_usb_host_mode(int enable) { ERROR("Not implemented yet"); (void)enable; return -1; } int local_get_rd_mode(void) { if ( strncmp(rd_mode, "master", strlen("master")) == 0 ) return 1; else return 0; } int local_set_rd_mode(int enable) { ERROR("Not implemented yet"); (void)enable; return -1; } int local_get_rd_flags(char * flags, size_t size) { const char * ptr; if ( strncmp(rd_mode, "master", strlen("master")) == 0 ) ptr = rd_mode + strlen("master"); else ptr = rd_mode; if ( *ptr == ',' ) ++ptr; if ( ! *ptr ) { flags[0] = 0; return 0; } strncpy(flags, ptr, size); flags[size-1] = 0; return 0; } int local_set_rd_flags(const char * flags) { ERROR("Not implemented yet"); (void)flags; return -1; } int16_t local_get_hwrev(void) { return hwrev; } int local_set_hwrev(int16_t hwrev) { ERROR("Not implemented yet"); (void)hwrev; return -1; } int local_get_kernel_ver(char * ver, size_t size) { strncpy(ver, kernel_ver, size); ver[size-1] = 0; return 0; } int local_set_kernel_ver(const char * ver) { ERROR("Not implemented yet"); (void)ver; return -1; } int local_get_initfs_ver(char * ver, size_t size) { strncpy(ver, initfs_ver, size); ver[size-1] = 0; return 0; } int local_set_initfs_ver(const char * ver) { ERROR("Not implemented yet"); (void)ver; return -1; } int local_get_nolo_ver(char * ver, size_t size) { strncpy(ver, nolo_ver, size); ver[size-1] = 0; return 0; } int local_set_nolo_ver(const char * ver) { ERROR("Not implemented yet"); (void)ver; return -1; } int local_get_sw_ver(char * ver, size_t size) { strncpy(ver, sw_ver, size); ver[size-1] = 0; return 0; } int local_set_sw_ver(const char * ver) { ERROR("Not implemented yet"); (void)ver; return -1; } int local_get_content_ver(char * ver, size_t size) { strncpy(ver, content_ver, size); ver[size-1] = 0; return 0; } int local_set_content_ver(const char * ver) { ERROR("Not implemented yet"); (void)ver; return -1; } 0xffff-0.6~git20130406/src/local.h000066400000000000000000000036321213002553000163050ustar00rootroot00000000000000/* 0xFFFF - Open Free Fiasco Firmware Flasher Copyright (C) 2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef LOCAL_H #define LOCAL_H #include "image.h" #include "device.h" int local_init(void); enum device local_get_device(void); int local_flash_image(struct image * image); int local_dump_image(enum image_type image, const char * file); int local_check_badblocks(const char * device); int local_reboot_device(void); int local_get_root_device(void); int local_set_root_device(int device); int local_get_usb_host_mode(void); int local_set_usb_host_mode(int enable); int local_get_rd_mode(void); int local_set_rd_mode(int enable); int local_get_rd_flags(char * flags, size_t size); int local_set_rd_flags(const char * flags); int16_t local_get_hwrev(void); int local_set_hwrev(int16_t hwrev); int local_get_kernel_ver(char * ver, size_t size); int local_set_kernel_ver(const char * ver); int local_get_initfs_ver(char * ver, size_t size); int local_set_initfs_ver(const char * ver); int local_get_nolo_ver(char * ver, size_t size); int local_set_nolo_ver(const char * ver); int local_get_sw_ver(char * ver, size_t size); int local_set_sw_ver(const char * ver); int local_get_content_ver(char * ver, size_t size); int local_set_content_ver(const char * ver); #endif 0xffff-0.6~git20130406/src/main.c000066400000000000000000000745321213002553000161410ustar00rootroot00000000000000/* 0xFFFF - Open Free Fiasco Firmware Flasher Copyright (C) 2007, 2008 pancake Copyright (C) 2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include "global.h" #include "image.h" #include "fiasco.h" #include "device.h" #include "operations.h" static void show_title(void) { printf("0xFFFF v%s // The Free Fiasco Firmware Flasher\n", VERSION); } static void show_usage(void) { int i; printf ("" "Operations:\n" " -b [cmdline] boot default or loaded kernel (default: no cmdline)\n" " -b update boot default or loaded kernel to Update mode\n" " -r reboot device\n" " -l load kernel and initfs images to RAM\n" " -f flash all specified images\n" " -c cold flash 2nd and secondary image\n" " -x [/dev/mtd] check for bad blocks on mtd device (default: all)\n" " -E file dump all device images to one fiasco image, see -t\n" " -e [dir] dump all device images to directory, see -t (default: current)\n" "\n" "Device configuration:\n" " -I identify, show all information about device\n" " -D 0|1|2 change root device: 0 - flash, 1 - mmc, 2 - usb\n" " -U 0|1 disable/enable USB host mode\n" " -R 0|1 disable/enable R&D mode\n" " -F flags change R&D flags, flags are comma separated list, can be empty\n" " -H rev change HW revision\n" " -N ver change NOLO version string\n" " -K ver change kernel version string\n" " -T ver change initfs version string\n" " -S ver change SW release version string\n" " -C ver change content eMMC version string\n" "\n" "Input image specification:\n" " -M file specify fiasco image\n" " -m arg specify normal image\n" " arg is [[[dev:[hw:]]ver:]type:]file[%%lay]\n" " dev is device name string (default: emtpy)\n" " hw are comma separated list of HW revisions (default: empty)\n" " ver is image version string (default: empty)\n" " type is image type (default: autodetect)\n" " file is image file name\n" " lay is layout file name (default: none)\n" "\n" "Image filters:\n" " -t types filter images by type\n" " -d dev filter images by device\n" " -w hw filter images by HW revision\n" "\n" "Fiasco image:\n" " -u [dir] unpack fiasco image to directory (default: current)\n" " -g file[%%sw] generate fiasco image with SW rel version (default: no version)\n" "\n" "Other options:\n" " -i identify images\n" " -s simulate, do not flash or write on disk\n" " -n disable hash, checksum and image type checking\n" " -v be verbose and noisy\n" " -h show this help message\n" "\n" "R&D flags:\n" " no-omap-wd disable auto reboot by OMAP watchdog\n" " no-ext-wd disable auto reboot by external watchdog\n" " no-lifeguard-reset disable auto reboot by software lifeguard\n" " serial-console enable serial console\n" " no-usb-timeout disable usb timeout for flashing\n" " sti-console enable sti console\n" " no-charging disable battery charging\n" " force-power-key force omap boot reason to power key\n" "\n" ); printf( "Supported devices:\n"); for ( i = 0; i < DEVICE_COUNT; ++i ) if ( device_to_string(i) && device_to_long_string(i) ) printf(" %-14s %s\n", device_to_string(i), device_to_long_string(i)); printf( "\n"); printf( "Supported image types:\n"); for ( i = 0; i < IMAGE_COUNT; ++i ) if ( image_type_to_string(i) ) printf(" %s\n", image_type_to_string(i)); printf( "\n"); printf( "Supported connection protocols:\n"); printf( " Local on device\n"); for ( i = 0; i < FLASH_COUNT; ++i ) if ( usb_flash_protocol_to_string(i) ) printf(" %s via USB\n", usb_flash_protocol_to_string(i)); printf( "\n"); } int simulate; int noverify; int verbose; /* arg = [[[dev:[hw:]]ver:]type:]file[%%lay] */ static void parse_image_arg(char * arg, struct image_list ** image_first) { struct stat st; struct image * image; char * file; char * type; char * device; char * hwrevs; char * version; char * layout; char * layout_file; /* Fisrt check if arg is file, then try to parse arg format */ if ( stat(arg, &st) == 0 ) { image = image_alloc_from_file(arg, NULL, NULL, NULL, NULL, NULL); if ( ! image ) { ERROR("Cannot load image file %s", arg); exit(1); } image_list_add(image_first, image); return; } layout_file = strchr(arg, '%'); if (layout_file) *(layout_file++) = 0; type = NULL; device = NULL; hwrevs = NULL; version = NULL; layout = NULL; file = strrchr(arg, ':'); if (file) { *(file++) = 0; type = strrchr(arg, ':'); if (type) { *(type++) = 0; version = strrchr(arg, ':'); if (version) { *(version++) = 0; hwrevs = strchr(arg, ':'); if (hwrevs) *(hwrevs++) = 0; device = arg; } else { version = arg; } } else { type = arg; } } else { file = arg; } if ( layout_file ) { off_t len; int fd = open(layout_file, O_RDONLY); if ( fd < 0 ) { ERROR_INFO("Cannot open layout file %s", layout_file); exit(1); } len = lseek(fd, 0, SEEK_END); if ( len == (off_t)-1 ) { ERROR_INFO("Cannot get size of file %s", layout_file); exit(1); } lseek(fd, 0, SEEK_SET); layout = malloc(len); if ( ! layout ) { ALLOC_ERROR(); exit(1); } if ( read(fd, layout, len) != len ) { ERROR_INFO("Cannot read %lu bytes from layout file %s", len, layout_file); exit(1); } } image = image_alloc_from_file(file, type, device, hwrevs, version, layout); if ( layout ) free(layout); if ( ! image ) { ERROR("Cannot load image file %s", file); exit(1); } image_list_add(image_first, image); } void filter_images_by_type(enum image_type type, struct image_list ** image_first) { struct image_list * image_ptr = *image_first; while ( image_ptr ) { struct image_list * next = image_ptr->next; if ( image_ptr->image->type != type ) { if ( image_ptr == *image_first ) *image_first = next; image_list_del(image_ptr); } image_ptr = next; } } void filter_images_by_device(enum device device, struct image_list ** image_first) { struct image_list * image_ptr = *image_first; while ( image_ptr ) { struct image_list * next = image_ptr->next; struct device_list * device_ptr = image_ptr->image->devices; int match = 0; while ( device_ptr ) { if ( device_ptr->device == device || device_ptr->device == DEVICE_ANY ) { match = 1; break; } device_ptr = device_ptr->next; } if ( ! match ) { if ( image_ptr == *image_first ) *image_first = next; image_list_del(image_ptr); } image_ptr = next; } } void filter_images_by_hwrev(int16_t hwrev, struct image_list ** image_first) { struct image_list * image_ptr = *image_first; while ( image_ptr ) { struct image_list * next = image_ptr->next; if ( ! image_hwrev_is_valid(image_ptr->image, hwrev) ) { if ( image_ptr == *image_first ) *image_first = next; image_list_del(image_ptr); } image_ptr = next; } } static const char * image_tmp[] = { [IMAGE_XLOADER] = "xloader_tmp", [IMAGE_SECONDARY] = "secondary_tmp", [IMAGE_KERNEL] = "kernel_tmp", [IMAGE_INITFS] = "initfs_tmp", [IMAGE_ROOTFS] = "rootfs_tmp", [IMAGE_MMC] = "mmc_tmp", }; static const char * image_tmp_name(enum image_type type) { if ( type >= sizeof(image_tmp)/sizeof(image_tmp[0]) ) return NULL; if ( ! image_tmp[type] || ! image_tmp[type][0] ) return NULL; return image_tmp[type]; } int main(int argc, char **argv) { const char * optstring = ":" "b:rlfcx:E:e:" "ID:U:R:F:H:K:T:N:S:C:" "M:m:" "t:d:w:" "u:g:" "i" "p" "Q" "snvh" ""; int c; int ret = 0; int do_something = 0; int do_device = 0; int dev_boot = 0; char * dev_boot_arg = NULL; int dev_load = 0; int dev_cold_flash = 0; int dev_check = 0; char * dev_check_arg = NULL; int dev_dump_fiasco = 0; char * dev_dump_fiasco_arg = NULL; int dev_dump = 0; char * dev_dump_arg = NULL; int dev_flash = 0; int dev_reboot = 0; int dev_ident = 0; int set_root = 0; char * set_root_arg = NULL; int set_usb = 0; char * set_usb_arg = NULL; int set_rd = 0; char * set_rd_arg = NULL; int set_rd_flags = 0; char * set_rd_flags_arg = NULL; int set_hw = 0; char * set_hw_arg = NULL; int set_kernel = 0; char * set_kernel_arg = NULL; int set_initfs = 0; char * set_initfs_arg = NULL; int set_nolo = 0; char * set_nolo_arg = NULL; int set_sw = 0; char * set_sw_arg = NULL; int set_emmc = 0; char * set_emmc_arg = NULL; int image_fiasco = 0; char * image_fiasco_arg = NULL; int filter_type = 0; char * filter_type_arg = NULL; int filter_device = 0; char * filter_device_arg = NULL; int filter_hwrev = 0; char * filter_hwrev_arg = NULL; int fiasco_un = 0; char * fiasco_un_arg = NULL; int fiasco_gen = 0; char * fiasco_gen_arg = NULL; int image_ident = 0; int help = 0; struct image_list * image_first = NULL; struct image_list * image_ptr = NULL; int have_2nd = 0; int have_secondary = 0; int have_kernel = 0; int have_initfs = 0; struct image * image_2nd = NULL; struct image * image_secondary = NULL; struct image_list * image_kernel = NULL; struct image_list * image_initfs = NULL; struct fiasco * fiasco_in = NULL; struct fiasco * fiasco_out = NULL; struct device_info * dev = NULL; enum device detected_device = DEVICE_UNKNOWN; int16_t detected_hwrev = -1; int i; char buf[512]; char * ptr = NULL; char * tmp = NULL; char nolo_ver[512]; char kernel_ver[512]; char initfs_ver[512]; char sw_ver[512]; char content_ver[512]; simulate = 0; noverify = 0; verbose = 0; show_title(); opterr = 0; while ( ( c = getopt(argc, argv, optstring) ) != -1 ) { switch (c) { default: ERROR("Unknown option '%c'", c); ret = 1; goto clean; case '?': ERROR("Unknown option '%c'", optopt); ret = 1; goto clean; case ':': if ( optopt == 'b' ) { dev_boot = 1; break; } if ( optopt == 'e' ) { dev_dump = 1; break; } if ( optopt == 'u' ) { fiasco_un = 1; break; } if ( optopt == 'x' ) { dev_check = 1; break; } ERROR("Option '%c' requires an argument", optopt); ret = 1; goto clean; case 'b': dev_boot = 1; if ( optarg[0] != '-' ) dev_boot_arg = optarg; else --optind; break; case 'l': dev_load = 1; break; case 'c': dev_cold_flash = 1; break; case 'x': dev_check = 1; if ( optarg[0] != '-' ) dev_check_arg = optarg; else --optind; break; case 'E': dev_dump_fiasco = 1; dev_dump_fiasco_arg = optarg; break; case 'e': dev_dump = 1; if ( optarg[0] != '-' ) dev_dump_arg = optarg; else --optind; break; case 'f': dev_flash = 1; break; case 'r': dev_reboot = 1; break; case 'I': dev_ident = 1; break; case 'D': set_root = 1; set_root_arg = optarg; break; case 'U': set_usb = 1; set_usb_arg = optarg; break; case 'R': set_rd = 1; set_rd_arg = optarg; break; case 'F': set_rd_flags = 1; set_rd_flags_arg = optarg; break; case 'H': set_hw = 1; set_hw_arg = optarg; break; case 'K': set_kernel = 1; set_kernel_arg = optarg; break; case 'T': set_initfs = 1; set_initfs_arg = optarg; break; case 'N': set_nolo = 1; set_nolo_arg = optarg; break; case 'S': set_sw = 1; set_sw_arg = optarg; break; case 'C': set_emmc = 1; set_emmc_arg = optarg; break; case 'M': image_fiasco = 1; image_fiasco_arg = optarg; break; case 'm': parse_image_arg(optarg, &image_first); break; case 't': filter_type = 1; filter_type_arg = optarg; break; case 'd': filter_device = 1; filter_device_arg = optarg; break; case 'w': filter_hwrev = 1; filter_hwrev_arg = optarg; break; case 'u': fiasco_un = 1; fiasco_un_arg = optarg; break; case 'g': fiasco_gen = 1; if ( optarg[0] != '-' ) fiasco_gen_arg = optarg; else --optind; break; case 'i': image_ident = 1; break; case 's': simulate = 1; break; case 'n': noverify = 1; break; case 'v': verbose = 1; break; case 'h': help = 1; break; } } if ( optind < argc ) { ERROR("Extra argument '%s'", argv[optind]); ret = 1; goto clean; } if ( dev_boot || dev_reboot || dev_load || dev_flash || dev_cold_flash || dev_ident || dev_check || dev_dump_fiasco || dev_dump || set_root || set_usb || set_rd || set_rd_flags || set_hw || set_kernel || set_initfs || set_nolo || set_sw || set_emmc ) do_device = 1; if ( dev_boot || dev_load || dev_cold_flash ) do_something = 1; if ( dev_check || dev_dump_fiasco || dev_dump ) do_something = 1; if ( dev_flash || dev_reboot || dev_ident || set_root || set_usb || set_rd || set_rd_flags || set_hw || set_kernel || set_initfs || set_nolo || set_sw || set_emmc ) do_something = 1; if ( fiasco_un || fiasco_gen || image_ident ) do_something = 1; if ( help ) do_something = 1; if ( ! do_something ) { ERROR("Nothing to do"); ret = 1; goto clean; } printf("\n"); /* help */ if ( help ) { show_usage(); ret = 0; goto clean; } /* load images from files */ if ( image_first && image_fiasco ) { ERROR("Cannot specify normal and fiasco images together"); ret = 1; goto clean; } /* load fiasco image */ if ( image_fiasco ) { fiasco_in = fiasco_alloc_from_file(image_fiasco_arg); if ( ! fiasco_in ) { ERROR("Cannot load fiasco image file %s", image_fiasco_arg); ret = 1; goto clean; } image_first = fiasco_in->first; } /* filter images by type */ if ( filter_type ) { enum image_type type = image_type_from_string(filter_type_arg); if ( ! type ) { ERROR("Specified unknown image type for filtering: %s", filter_type_arg); ret = 1; goto clean; } filter_images_by_type(type, &image_first); } /* filter images by device */ if ( filter_device ) { enum device device = device_from_string(filter_device_arg); if ( ! device ) { ERROR("Specified unknown device for filtering: %s", filter_device_arg); ret = 1; goto clean; } filter_images_by_device(device, &image_first); } /* filter images by hwrev */ if ( filter_hwrev ) filter_images_by_hwrev(atoi(filter_hwrev_arg), &image_first); /* reorder images for flashing (first x-loader, second secondary) */ /* set 2nd and secondary images for cold-flashing */ if ( dev_flash || dev_cold_flash ) { struct image_list * image_unorder_first; image_unorder_first = image_first; image_first = NULL; image_ptr = image_unorder_first; while ( image_ptr ) { struct image_list * next = image_ptr->next; if ( image_ptr->image->type == IMAGE_XLOADER ) { if ( image_ptr == image_unorder_first ) image_unorder_first = next; image_list_add(&image_first, image_ptr->image); image_list_unlink(image_ptr); free(image_ptr); } image_ptr = next; } image_ptr = image_unorder_first; while ( image_ptr ) { struct image_list * next = image_ptr->next; if ( image_ptr->image->type == IMAGE_SECONDARY ) { if ( have_secondary == 0 ) { image_secondary = image_ptr->image; have_secondary = 1; } else if ( have_secondary == 1 ) { image_secondary = NULL; have_secondary = 2; } if ( image_ptr == image_unorder_first ) image_unorder_first = next; image_list_add(&image_first, image_ptr->image); image_list_unlink(image_ptr); free(image_ptr); } image_ptr = next; } image_ptr = image_unorder_first; while ( image_ptr ) { struct image_list * next = image_ptr->next; if ( image_ptr->image->type == IMAGE_2ND ) { if ( have_2nd == 0 ) { image_2nd = image_ptr->image; have_2nd = 1; } else if ( have_2nd == 1 ) { image_2nd = NULL; have_2nd = 2; } } if ( image_ptr == image_unorder_first ) image_unorder_first = next; image_list_add(&image_first, image_ptr->image); image_list_unlink(image_ptr); free(image_ptr); image_ptr = next; } } /* make sure that fiasco_in has valid images*/ if ( fiasco_in ) fiasco_in->first = image_first; /* identificate images */ if ( image_ident ) { if ( fiasco_in ) { fiasco_print_info(fiasco_in); printf("\n"); } else if ( ! image_first ) { ERROR("No image specified"); ret = 1; goto clean; } for ( image_ptr = image_first; image_ptr; image_ptr = image_ptr->next ) { image_print_info(image_ptr->image); printf("\n"); } ret = 0; goto clean; } /* unpack fiasco */ if ( fiasco_un ) { if ( ! fiasco_in ) { ERROR("No fiasco image specified"); ret = 1; goto clean; } fiasco_unpack(fiasco_in, fiasco_un_arg); } /* remove unknown images */ image_ptr = image_first; while ( image_ptr ) { struct image_list * next = image_ptr->next; if ( image_ptr->image->type == IMAGE_UNKNOWN ) { WARNING("Removing unknown image (specified by %s %s)", image_ptr->image->orig_filename ? "file" : "fiasco", image_ptr->image->orig_filename ? image_ptr->image->orig_filename : "image"); if ( image_ptr == image_first ) image_first = next; image_list_unlink(image_ptr); free(image_ptr); } image_ptr = next; } /* make sure that fiasco_in has valid images */ if ( fiasco_in ) fiasco_in->first = image_first; /* generate fiasco */ if ( fiasco_gen ) { char * swver = strchr(fiasco_gen_arg, '%'); if ( swver ) *(swver++) = 0; fiasco_out = fiasco_alloc_empty(); if ( ! fiasco_out ) { ERROR("Cannot write images to fiasco file %s", fiasco_gen_arg); } else { if ( swver ) strcpy(fiasco_out->swver, swver); fiasco_out->first = image_first; fiasco_write_to_file(fiasco_out, fiasco_gen_arg); fiasco_out->first = NULL; fiasco_free(fiasco_out); } } if ( dev_cold_flash ) { if ( have_2nd == 0 ) { ERROR("2nd image for Cold Flashing was not specified"); ret = 1; goto clean; } else if ( have_2nd == 2 ) { ERROR("More 2nd images for Cold Flashing was specified"); ret = 1; goto clean; } if ( have_secondary == 0 ) { ERROR("Secondary image for Cold Flashing was not specified"); ret = 1; goto clean; } else if ( have_secondary == 2 ) { ERROR("More Secondary images for Cold Flashing was specified"); ret = 1; goto clean; } } if ( dev_load && dev_flash ) { ERROR("Options load and flash cannot de used together"); ret = 1; goto clean; } if ( dev_load && ! image_first ) { ERROR("No image specified for loading"); ret = 1; goto clean; } if ( dev_flash && ! image_first ) { ERROR("No image specified for flashing"); ret = 1; goto clean; } /* operations */ if ( do_device ) { int again = 1; while ( again ) { again = 0; if ( dev ) dev_free(dev); dev = dev_detect(); if ( ! dev ) { ERROR("No device detected"); break; } /* cold flash */ if ( dev_cold_flash ) { ret = dev_cold_flash_images(dev, image_2nd, image_secondary); dev_free(dev); dev = NULL; if ( ret == -EAGAIN ) { again = 1; continue; } if ( ret != 0 ) goto clean; if ( dev_flash ) { dev_cold_flash = 0; again = 1; continue; } break; } if ( ! dev->detected_device ) printf("Device: (not detected)\n"); else printf("Device: %s\n", device_to_string(dev->detected_device)); if ( dev->detected_hwrev <= 0 ) printf("HW revision: (not detected)\n"); else printf("HW revision: %d\n", dev->detected_hwrev); nolo_ver[0] = 0; dev_get_nolo_ver(dev, nolo_ver, sizeof(nolo_ver)); printf("NOLO version: %s\n", nolo_ver[0] ? nolo_ver : "(not detected)"); kernel_ver[0] = 0; dev_get_kernel_ver(dev, kernel_ver, sizeof(kernel_ver)); printf("Kernel version: %s\n", kernel_ver[0] ? kernel_ver : "(not detected)"); initfs_ver[0] = 0; dev_get_initfs_ver(dev, initfs_ver, sizeof(initfs_ver)); printf("Initfs version: %s\n", initfs_ver[0] ? initfs_ver : "(not detected)"); sw_ver[0] = 0; dev_get_sw_ver(dev, sw_ver, sizeof(sw_ver)); printf("Software release version: %s\n", sw_ver[0] ? sw_ver : "(not detected)"); content_ver[0] = 0; dev_get_content_ver(dev, content_ver, sizeof(content_ver)); printf("Content eMMC version: %s\n", content_ver[0] ? content_ver : "(not detected)"); ret = dev_get_root_device(dev); printf("Root device: "); if ( ret == 0 ) printf("flash"); else if ( ret == 1 ) printf("mmc"); else if ( ret == 2 ) printf("usb"); else printf("(not detected)"); printf("\n"); ret = dev_get_usb_host_mode(dev); printf("USB host mode: "); if ( ret == 0 ) printf("disabled"); else if ( ret == 1 ) printf("enabled"); else printf("(not detected)"); printf("\n"); ret = dev_get_rd_mode(dev); printf("R&D mode: "); if ( ret == 0 ) printf("disabled"); else if ( ret == 1 ) printf("enabled"); else printf("(not detected)"); printf("\n"); if ( ret == 1 ) { ret = dev_get_rd_flags(dev, buf, sizeof(buf)); printf("R&D flags: "); if ( ret < 0 ) printf("(not detected)"); else printf("%s", buf); printf("\n"); } /* device identify */ if ( dev_ident ) { if ( ! dev->detected_device ) { dev_reboot_device(dev); goto again; } dev_free(dev); dev = NULL; break; } printf("\n"); /* filter images by device & hwrev */ if ( detected_device ) filter_images_by_device(dev->detected_device, &image_first); if ( detected_hwrev ) filter_images_by_hwrev(dev->detected_hwrev, &image_first); /* set kernel and initfs images for loading */ if ( dev_load ) { image_ptr = image_first; while ( image_ptr ) { struct image_list * next = image_ptr->next; if ( image_ptr->image->type == IMAGE_KERNEL ) { if ( have_kernel == 0 ) { image_kernel = image_ptr; have_kernel = 1; } else if ( have_kernel == 1 && image_kernel != image_ptr ) { image_kernel = NULL; have_kernel = 2; } } image_ptr = next; } image_ptr = image_first; while ( image_ptr ) { struct image_list * next = image_ptr->next; if ( image_ptr->image->type == IMAGE_INITFS ) { if ( have_initfs == 0 ) { image_initfs = image_ptr; have_initfs = 1; } else if ( have_initfs == 1 && image_initfs != image_ptr ) { image_initfs = NULL; have_initfs = 2; } } image_ptr = next; } if ( have_kernel == 2 ) { ERROR("More Kernel images for loading was specified"); ret = 1; goto clean; } if ( have_initfs == 2 ) { ERROR("More Initfs images for loading was specified"); ret = 1; goto clean; } if ( have_kernel == 0 && have_initfs == 0 ) { ERROR("Kernel image or Initfs image for loading was not specified"); ret = 1; goto clean; } } /* load */ if ( dev_load ) { if ( image_kernel ) { ret = dev_load_image(dev, image_kernel->image); if ( ret < 0 ) goto again; if ( image_kernel == image_first ) image_first = image_first->next; if ( fiasco_in && image_kernel == fiasco_in->first ) fiasco_in->first = fiasco_in->first->next; image_list_unlink(image_kernel); free(image_kernel); image_kernel = NULL; } if ( image_initfs ) { ret = dev_load_image(dev, image_initfs->image); if ( ret < 0 ) goto again; if ( image_initfs == image_first ) image_first = image_first->next; if ( fiasco_in && image_kernel == fiasco_in->first ) fiasco_in->first = fiasco_in->first->next; image_list_unlink(image_initfs); free(image_initfs); image_initfs = NULL; } } /* flash */ if ( dev_flash ) { image_ptr = image_first; while ( image_ptr ) { struct image_list * next = image_ptr->next; ret = dev_flash_image(dev, image_ptr->image); if ( ret < 0 ) goto again; if ( image_ptr == image_first ) image_first = image_first->next; if ( fiasco_in && image_kernel == fiasco_in->first ) fiasco_in->first = fiasco_in->first->next; image_list_unlink(image_ptr); free(image_ptr); image_ptr = next; } } /* configuration */ ret = 0; if ( set_rd_flags ) { set_rd = 1; set_rd_arg = "1"; } if ( sw_ver[0] && dev_flash && ! set_sw && fiasco_in && fiasco_in->swver[0] && strcmp(fiasco_in->swver, sw_ver) != 0 ) { set_sw = 1; set_sw_arg = fiasco_in->swver; } if ( set_root ) ret = dev_set_root_device(dev, atoi(set_root_arg)); if ( ret == -EAGAIN ) goto again; if ( set_usb ) ret = dev_set_usb_host_mode(dev, atoi(set_usb_arg)); if ( ret == -EAGAIN ) goto again; if ( set_rd ) ret = dev_set_rd_mode(dev, atoi(set_rd_arg)); if ( ret == -EAGAIN ) goto again; if ( set_rd_flags ) ret = dev_set_rd_flags(dev, set_rd_flags_arg); if ( ret == -EAGAIN ) goto again; if ( set_hw ) ret = dev_set_hwrev(dev, atoi(set_hw_arg)); if ( ret == -EAGAIN ) goto again; if ( set_nolo ) ret = dev_set_nolo_ver(dev, set_nolo_arg); if ( ret == -EAGAIN ) goto again; if ( set_kernel ) ret = dev_set_kernel_ver(dev, set_kernel_arg); if ( ret == -EAGAIN ) goto again; if ( set_initfs ) ret = dev_set_initfs_ver(dev, set_initfs_arg); if ( ret == -EAGAIN ) goto again; if ( set_sw ) ret = dev_set_sw_ver(dev, set_sw_arg); if ( ret == -EAGAIN ) goto again; if ( set_emmc ) ret = dev_set_content_ver(dev, set_emmc_arg); if ( ret == -EAGAIN ) goto again; /* check */ if ( dev_check ) ret = dev_check_badblocks(dev, dev_check_arg); if ( ret == -EAGAIN ) goto again; /* dump */ if ( dev_dump_fiasco ) { dev_dump = 1; tmp = strdup(dev_dump_fiasco_arg); dev_dump_arg = dirname(tmp); } if ( dev_dump ) { buf[0] = 0; if ( dev_dump_arg ) { if ( ! getcwd(buf, sizeof(buf)) ) buf[0] = 0; if ( chdir(dev_dump_arg) < 0 ) buf[0] = 0; } for ( i = 0; i < IMAGE_COUNT; ++i ) if ( image_tmp_name(i) ) dev_dump_image(dev, i, image_tmp_name(i)); if ( buf[0] ) chdir(buf); } /* dump fiasco */ if ( dev_dump_fiasco ) { struct image_list * image_dump_first = NULL; struct image * image_dump = NULL; for ( i = 0; i < IMAGE_COUNT; ++i ) { if ( ! image_tmp_name(i) ) continue; sprintf(buf, "%hd", dev->detected_hwrev); switch ( i ) { case IMAGE_2ND: case IMAGE_XLOADER: case IMAGE_SECONDARY: ptr = nolo_ver; break; case IMAGE_KERNEL: ptr = kernel_ver; break; case IMAGE_INITFS: ptr = initfs_ver; break; case IMAGE_ROOTFS: ptr = sw_ver; break; case IMAGE_MMC: ptr = content_ver; break; default: ptr = NULL; break; } image_dump = image_alloc_from_file(image_tmp_name(i), image_type_to_string(i), device_to_string(dev->detected_device), buf, ptr, NULL); if ( ! image_dump ) continue; image_list_add(&image_dump_first, image_dump); } printf("\n"); fiasco_out = fiasco_alloc_empty(); if ( ! fiasco_out ) { ERROR("Cannot write images to fiasco file %s", dev_dump_fiasco_arg); } else { strncpy(fiasco_out->swver, sw_ver, sizeof(fiasco_out->swver)); fiasco_out->swver[sizeof(fiasco_out->swver)-1] = 0; fiasco_out->first = image_dump_first; fiasco_write_to_file(fiasco_out, dev_dump_fiasco_arg); fiasco_free(fiasco_out); /* this will also free list image_dump_first */ } for ( i = 0; i < IMAGE_COUNT; ++i ) if ( image_tmp_name(i) ) unlink(image_tmp_name(i)); free(tmp); tmp = NULL; dev_dump_arg = NULL; } if ( ! dev_dump_fiasco ) { for ( i = 0; i < IMAGE_COUNT; ++i ) { struct stat st; if ( ! image_tmp_name(i) ) continue; if ( stat(image_tmp_name(i), &st) != 0 ) continue; switch ( i ) { case IMAGE_2ND: case IMAGE_XLOADER: case IMAGE_SECONDARY: ptr = nolo_ver; break; case IMAGE_KERNEL: ptr = kernel_ver; break; case IMAGE_INITFS: ptr = initfs_ver; break; case IMAGE_ROOTFS: ptr = sw_ver; break; case IMAGE_MMC: ptr = content_ver; break; default: ptr = NULL; break; } sprintf(buf, "%s-%s:%hd_%s", image_type_to_string(i), device_to_string(dev->detected_device), dev->detected_hwrev, ptr); printf("Renaming %s image file to %s...\n", image_type_to_string(i), buf); if ( rename(image_tmp_name(i), buf) < 0 ) { ERROR_INFO("Renaming failed"); sprintf(buf, "%s-%s_%s", image_type_to_string(i), device_to_string(dev->detected_device), ptr); printf("Trying to rename %s image file to %s...\n", image_type_to_string(i), buf); if ( rename(image_tmp_name(i), buf) < 0 ) ERROR_INFO("Renaming failed"); } } } /* boot */ if ( dev_boot ) { dev_boot_device(dev, dev_boot_arg); break; } /* reboot */ if ( dev_reboot ) { dev_reboot_device(dev); break; } continue; again: dev_free(dev); dev = NULL; again = 1; } } ret = 0; /* clean */ clean: if ( ! image_fiasco ) { image_ptr = image_first; while ( image_ptr ) { struct image_list * next = image_ptr->next; image_list_del(image_ptr); image_ptr = next; } } if ( fiasco_in ) fiasco_free(fiasco_in); if ( dev ) dev_free(dev); return ret; } 0xffff-0.6~git20130406/src/mkii.c000066400000000000000000000103001213002553000161250ustar00rootroot00000000000000/* 0xFFFF - Open Free Fiasco Firmware Flasher Copyright (C) 2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "mkii.h" #include "global.h" #include "image.h" #include "device.h" #include "usb-device.h" int mkii_init(struct usb_device_info * dev) { ERROR("Mk II protocol is not implemented yet"); (void)dev; return -1; } enum device mkii_get_device(struct usb_device_info * dev) { ERROR("Not implemented yet"); (void)dev; return DEVICE_UNKNOWN; } int mkii_flash_image(struct usb_device_info * dev, struct image * image) { ERROR("Not implemented yet"); (void)dev; (void)image; return -1; } int mkii_reboot_device(struct usb_device_info * dev) { ERROR("Not implemented yet"); (void)dev; return -1; } int mkii_get_root_device(struct usb_device_info * dev) { ERROR("Not implemented yet"); (void)dev; return -1; } int mkii_set_root_device(struct usb_device_info * dev, int device) { ERROR("Not implemented yet"); (void)dev; (void)device; return -1; } int mkii_get_usb_host_mode(struct usb_device_info * dev) { ERROR("Not implemented yet"); (void)dev; return -1; } int mkii_set_usb_host_mode(struct usb_device_info * dev, int enable) { ERROR("Not implemented yet"); (void)dev; (void)enable; return -1; } int mkii_get_rd_mode(struct usb_device_info * dev) { ERROR("Not implemented yet"); (void)dev; return -1; } int mkii_set_rd_mode(struct usb_device_info * dev, int enable) { ERROR("Not implemented yet"); (void)dev; (void)enable; return -1; } int mkii_get_rd_flags(struct usb_device_info * dev, char * flags, size_t size) { ERROR("Not implemented yet"); (void)dev; (void)flags; (void)size; return -1; } int mkii_set_rd_flags(struct usb_device_info * dev, const char * flags) { ERROR("Not implemented yet"); (void)dev; (void)flags; return -1; } int16_t mkii_get_hwrev(struct usb_device_info * dev) { ERROR("Not implemented yet"); (void)dev; return -1; } int mkii_set_hwrev(struct usb_device_info * dev, int16_t hwrev) { ERROR("Not implemented yet"); (void)dev; (void)hwrev; return -1; } int mkii_get_kernel_ver(struct usb_device_info * dev, char * ver, size_t size) { ERROR("Not implemented yet"); (void)dev; (void)ver; (void)size; return -1; } int mkii_set_kernel_ver(struct usb_device_info * dev, const char * ver) { ERROR("Not implemented yet"); (void)dev; (void)ver; return -1; } int mkii_get_initfs_ver(struct usb_device_info * dev, char * ver, size_t size) { ERROR("Not implemented yet"); (void)dev; (void)ver; (void)size; return -1; } int mkii_set_initfs_ver(struct usb_device_info * dev, const char * ver) { ERROR("Not implemented yet"); (void)dev; (void)ver; return -1; } int mkii_get_nolo_ver(struct usb_device_info * dev, char * ver, size_t size) { ERROR("Not implemented yet"); (void)dev; (void)ver; (void)size; return -1; } int mkii_set_nolo_ver(struct usb_device_info * dev, const char * ver) { ERROR("Not implemented yet"); (void)dev; (void)ver; return -1; } int mkii_get_sw_ver(struct usb_device_info * dev, char * ver, size_t size) { ERROR("Not implemented yet"); (void)dev; (void)ver; (void)size; return -1; } int mkii_set_sw_ver(struct usb_device_info * dev, const char * ver) { ERROR("Not implemented yet"); (void)dev; (void)ver; return -1; } int mkii_get_content_ver(struct usb_device_info * dev, char * ver, size_t size) { ERROR("Not implemented yet"); (void)dev; (void)ver; (void)size; return -1; } int mkii_set_content_ver(struct usb_device_info * dev, const char * ver) { ERROR("Not implemented yet"); (void)dev; (void)ver; return -1; } 0xffff-0.6~git20130406/src/mkii.h000066400000000000000000000047151213002553000161470ustar00rootroot00000000000000/* 0xFFFF - Open Free Fiasco Firmware Flasher Copyright (C) 2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef MKII_H #define MKII_H #include "image.h" #include "device.h" #include "usb-device.h" int mkii_init(struct usb_device_info * dev); enum device mkii_get_device(struct usb_device_info * dev); int mkii_flash_image(struct usb_device_info * dev, struct image * image); int mkii_reboot_device(struct usb_device_info * dev); int mkii_get_root_device(struct usb_device_info * dev); int mkii_set_root_device(struct usb_device_info * dev, int device); int mkii_get_usb_host_mode(struct usb_device_info * dev); int mkii_set_usb_host_mode(struct usb_device_info * dev, int enable); int mkii_get_rd_mode(struct usb_device_info * dev); int mkii_set_rd_mode(struct usb_device_info * dev, int enable); int mkii_get_rd_flags(struct usb_device_info * dev, char * flags, size_t size); int mkii_set_rd_flags(struct usb_device_info * dev, const char * flags); int16_t mkii_get_hwrev(struct usb_device_info * dev); int mkii_set_hwrev(struct usb_device_info * dev, int16_t hwrev); int mkii_get_kernel_ver(struct usb_device_info * dev, char * ver, size_t size); int mkii_set_kernel_ver(struct usb_device_info * dev, const char * ver); int mkii_get_initfs_ver(struct usb_device_info * dev, char * ver, size_t size); int mkii_set_initfs_ver(struct usb_device_info * dev, const char * ver); int mkii_get_nolo_ver(struct usb_device_info * dev, char * ver, size_t size); int mkii_set_nolo_ver(struct usb_device_info * dev, const char * ver); int mkii_get_sw_ver(struct usb_device_info * dev, char * ver, size_t size); int mkii_set_sw_ver(struct usb_device_info * dev, const char * ver); int mkii_get_content_ver(struct usb_device_info * dev, char * ver, size_t size); int mkii_set_content_ver(struct usb_device_info * dev, const char * ver); #endif 0xffff-0.6~git20130406/src/nolo.c000066400000000000000000000517251213002553000161630ustar00rootroot00000000000000/* * 0xFFFF - Open Free Fiasco Firmware Flasher * Copyright (C) 2007-2009 pancake * Copyright (C) 2012 Pali Rohár * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "nolo.h" #include "image.h" #include "global.h" #include "printf-utils.h" /* Request type */ #define NOLO_WRITE 64 #define NOLO_QUERY 192 /* Request */ #define NOLO_STATUS 1 #define NOLO_GET_NOLO_VERSION 3 #define NOLO_IDENTIFY 4 #define NOLO_ERROR_LOG 5 #define NOLO_SET 16 #define NOLO_GET 17 #define NOLO_STRING 18 #define NOLO_SET_STRING 19 #define NOLO_GET_STRING 20 #define NOLO_SEND_IMAGE 66 #define NOLO_SET_SW_RELEASE 67 #define NOLO_FLASH_IMAGE 80 #define NOLO_SEND_FLASH_FINISH 82 #define NOLO_SEND_FLASH_IMAGE 84 #define NOLO_BOOT 130 #define NOLO_REBOOT 131 /* Indexes - Flash image */ #define NOLO_IMAGE_BOOTLOADER 1 #define NOLO_IMAGE_KERNEL 3 #define NOLO_IMAGE_INITFS 4 #define NOLO_IMAGE_CMT 66 /* Indexes - Set & Get */ #define NOLO_RD_MODE 0 #define NOLO_ROOT_DEVICE 1 #define NOLO_USB_HOST_MODE 2 #define NOLO_ADD_RD_FLAGS 3 #define NOLO_DEL_RD_FLAGS 4 /* Values - R&D flags */ #define NOLO_RD_FLAG_NO_OMAP_WD 0x002 #define NOLO_RD_FLAG_NO_EXT_WD 0x004 #define NOLO_RD_FLAG_NO_LIFEGUARD 0x008 #define NOLO_RD_FLAG_SERIAL_CONSOLE 0x010 #define NOLO_RD_FLAG_NO_USB_TIMEOUT 0x020 #define NOLO_RD_FLAG_STI_CONSOLE 0x040 #define NOLO_RD_FLAG_NO_CHARGING 0x080 #define NOLO_RD_FLAG_FORCE_POWER_KEY 0x100 /* Values - Boot mode */ #define NOLO_BOOT_MODE_NORMAL 0 #define NOLO_BOOT_MODE_UPDATE 1 #define NOLO_ERROR_RETURN(str, ...) do { nolo_error_log(dev, str == NULL); ERROR_RETURN(str, __VA_ARGS__); } while (0) static void nolo_error_log(struct usb_device_info * dev, int only_clear) { char buf[2048]; size_t i, count; for ( count = 0; count < 20; ++count ) { memset(buf, 0, sizeof(buf)); if ( usb_control_msg(dev->udev, NOLO_QUERY, NOLO_ERROR_LOG, 0, 0, buf, sizeof(buf), 2000) <= 0 ) break; if ( ! only_clear ) { for ( i = 0; i < sizeof(buf)-2; ++i ) if ( buf[i] == 0 && buf[i+1] != 0 ) buf[i] = '\n'; buf[sizeof(buf)-1] = 0; puts(buf); } } } static int nolo_identify_string(struct usb_device_info * dev, const char * str, char * out, size_t size) { char buf[512]; char * ptr; int ret; memset(buf, 0, sizeof(buf)); ret = usb_control_msg(dev->udev, NOLO_QUERY, NOLO_IDENTIFY, 0, 0, (char *)buf, sizeof(buf), 2000); if ( ret < 0 ) NOLO_ERROR_RETURN("NOLO_IDENTIFY failed", -1); ptr = memmem(buf, ret, str, strlen(str)); if ( ! ptr ) ERROR_RETURN("Substring was not found", -1); ptr += strlen(str) + 1; while ( ptr-buf < ret && *ptr < 32 ) ++ptr; if ( ! *ptr ) return -1; strncpy(out, ptr, size-1); out[size-1] = 0; return strlen(out); } static int nolo_set_string(struct usb_device_info * dev, char * str, char * arg) { if ( simulate ) return 0; if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_STRING, 0, 0, str, strlen(str), 2000) < 0 ) NOLO_ERROR_RETURN("NOLO_STRING failed", -1); if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_SET_STRING, 0, 0, arg, strlen(arg), 2000) < 0 ) NOLO_ERROR_RETURN("NOLO_SET_STRING failed", -1); return 0; } static int nolo_get_string(struct usb_device_info * dev, char * str, char * out, size_t size) { int ret = 0; if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_STRING, 0, 0, str, strlen(str), 2000) < 0 ) return -1; if ( ( ret = usb_control_msg(dev->udev, NOLO_QUERY, NOLO_GET_STRING, 0, 0, out, size-1, 2000) ) < 0 ) return -1; out[size-1] = 0; out[ret] = 0; return strlen(out); } static int nolo_get_version_string(struct usb_device_info * dev, const char * str, char * out, size_t size) { int ret; char buf[512]; if ( strlen(str) > 500 ) return -1; sprintf(buf, "version:%s", str); ret = nolo_get_string(dev, buf, out, size); nolo_error_log(dev, 1); if ( ret < 0 ) return ret; if ( ! out[0] ) return -1; return ret; } int nolo_init(struct usb_device_info * dev) { uint32_t val = 1; enum device device; printf("Initializing NOLO...\n"); while ( val != 0 ) if ( usb_control_msg(dev->udev, NOLO_QUERY, NOLO_STATUS, 0, 0, (char *)&val, 4, 2000) == -1 ) NOLO_ERROR_RETURN("NOLO_STATUS failed", -1); /* clear error log */ nolo_error_log(dev, 1); device = nolo_get_device(dev); if ( ! dev->device ) dev->device = device; if ( dev->device && device && dev->device != device ) { ERROR("Device mishmash, expected %s, got %s", device_to_string(dev->device), device_to_string(device)); return -1; } dev->hwrev = nolo_get_hwrev(dev); return 0; } enum device nolo_get_device(struct usb_device_info * dev) { char buf[20]; if ( nolo_identify_string(dev, "prod_code", buf, sizeof(buf)) < 0 ) return DEVICE_UNKNOWN; else if ( buf[0] ) return device_from_string(buf); else return DEVICE_UNKNOWN; } static int nolo_send_image(struct usb_device_info * dev, struct image * image, int flash) { char buf[0x20000]; char * ptr; const char * type; uint8_t len; uint16_t hash; uint32_t size; uint32_t need; uint32_t readed; int request; int ret; if ( flash ) printf("Send and flash image:\n"); else printf("Load image:\n"); image_print_info(image); if ( image->type == IMAGE_2ND || image->type == IMAGE_MMC ) ERROR_RETURN("Sending 2nd and mmc images are not supported", -1); if ( ! flash && image->type == IMAGE_ROOTFS ) ERROR_RETURN("Rootfs image must be sent in flash mode", -1); ptr = buf; /* Signature */ memcpy(ptr, "\x2E\x19\x01\x01", 4); ptr += 4; /* Space */ memcpy(ptr, "\x00", 1); ptr += 1; /* Hash */ hash = htons(image->hash); memcpy(ptr, &hash, 2); ptr += 2; /* Type */ type = image_type_to_string(image->type); if ( ! type ) ERROR_RETURN("Unknown image type", -1); memset(ptr, 0, 12); strncpy(ptr, type, 12); ptr += 12; /* Size */ size = htonl(image->size); memcpy(ptr, &size, 4); ptr += 4; /* Space */ memcpy(ptr, "\x00\x00\x00\x00", 4); ptr += 4; /* Device & hwrev */ if ( image->devices ) { int i; uint8_t len; char buf[9]; char ** bufs = NULL; struct device_list * device = image->devices; while ( device ) { if ( device->device == dev->device && hwrev_is_valid(device->hwrevs, dev->hwrev) ) break; device = device->next; } if ( device ) bufs = device_list_alloc_to_bufs(device); if ( bufs ) { memset(buf, 0, sizeof(buf)); snprintf(buf, 8, "%d", dev->hwrev); for ( i = 0; bufs[i]; ++i ) { len = ((uint8_t*)bufs[i])[0]; if ( memmem(bufs[i]+1, len, buf, strlen(buf)) ) break; } if ( bufs[i] ) { /* Device & hwrev string header */ memcpy(ptr, "\x32", 1); ptr += 1; /* Device & hwrev string size */ memcpy(ptr, &len, 1); ptr += 1; /* Device & hwrev string */ memcpy(ptr, bufs[i]+1, len); ptr += len; } free(bufs); } } /* Version */ if ( image->version ) { len = strnlen(image->version, 255) + 1; /* Version string header */ memcpy(ptr, "\x31", 1); ptr += 1; /* Version string size */ memcpy(ptr, &len, 1); ptr += 1; /* Version string */ memcpy(ptr, image->version, len); ptr += len; } if ( flash ) request = NOLO_SEND_FLASH_IMAGE; else request = NOLO_SEND_IMAGE; printf("Sending image header...\n"); if ( ! simulate ) { if ( usb_control_msg(dev->udev, NOLO_WRITE, request, 0, 0, buf, ptr-buf, 2000) < 0 ) NOLO_ERROR_RETURN("Sending image header failed", -1); } if ( flash ) printf("Sending and flashing image...\n"); else printf("Sending image...\n"); printf_progressbar(0, image->size); image_seek(image, 0); readed = 0; while ( readed < image->size ) { need = image->size - readed; if ( need > sizeof(buf) ) need = sizeof(buf); ret = image_read(image, buf, need); if ( ret == 0 ) break; if ( ! simulate ) { if ( usb_bulk_write(dev->udev, 2, buf, ret, 5000) != ret ) { PRINTF_END(); NOLO_ERROR_RETURN("Sending image failed", -1); } } readed += ret; printf_progressbar(readed, image->size); } if ( flash ) { printf("Finishing flashing...\n"); if ( ! simulate ) { if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_SEND_FLASH_FINISH, 0, 0, NULL, 0, 30000) < 0 ) NOLO_ERROR_RETURN("Finishing failed", -1); } } printf("Done\n"); return 0; } int nolo_load_image(struct usb_device_info * dev, struct image * image) { if ( image->type != IMAGE_KERNEL && image->type != IMAGE_INITFS ) ERROR_RETURN("Only kernel or initfs image can be loaded", -1); return nolo_send_image(dev, image, 0); } int nolo_flash_image(struct usb_device_info * dev, struct image * image) { int ret; int flash; int index; unsigned long long int part; unsigned long long int total; unsigned long long int last_total; char status[20]; char buf[128]; if ( image->type == IMAGE_ROOTFS ) flash = 1; else flash = 0; ret = nolo_send_image(dev, image, flash); if ( ret < 0 ) return ret; if ( image->type == IMAGE_SECONDARY ) index = NOLO_IMAGE_BOOTLOADER; else if ( image->type == IMAGE_KERNEL ) index = NOLO_IMAGE_KERNEL; else if ( image->type == IMAGE_CMT_MCUSW ) index = NOLO_IMAGE_CMT; else index = -1; if ( image->type == IMAGE_CMT_MCUSW ) nolo_set_string(dev, "cmt:verify", "1"); if ( ! flash && index >= 0 ) { printf("Flashing image...\n"); if ( ! simulate ) { if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_FLASH_IMAGE, 0, index, NULL, 0, 10000) ) NOLO_ERROR_RETURN("Flashing failed", -1); } printf("Done\n"); } if ( image->type == IMAGE_CMT_MCUSW ) { int state = 0; last_total = 0; if ( nolo_get_string(dev, "cmt:status", buf, sizeof(buf)) < 0 ) NOLO_ERROR_RETURN("cmt:status failed", -1); if ( strncmp(buf, "idle", strlen("idle")) == 0 ) state = 4; else printf("Erasing CMT...\n"); while ( state != 4 ) { if ( nolo_get_string(dev, "cmt:status", buf, sizeof(buf)) < 0 ) { PRINTF_END(); NOLO_ERROR_RETURN("cmt:status failed", -1); } if ( strncmp(buf, "finished", strlen("finished")) == 0 ) { if ( state <= 0 ) { printf_progressbar(last_total, last_total); printf("Done\n"); } if ( state <= 1 ) printf("Programming CMT...\n"); if ( state <= 2 ) { printf_progressbar(last_total, last_total); printf("Done\n"); } state = 4; } else { if ( sscanf(buf, "%s:%llu/%llu", status, &part, &total) != 3 ) PRINTF_ERROR_RETURN("cmt:status unknown", -1); if ( strcmp(status, "program") == 0 && state <= 0 ) { printf_progressbar(last_total, last_total); printf("Done\n"); state = 1; } if ( strcmp(status, "program") == 0 && state <= 1 ) { printf("Programming CMT...\n"); state = 2; } printf_progressbar(part, total); last_total = total; if ( strcmp(status, "erase") == 0 && state <= 0 && part == total ) { printf("Done\n"); state = 1; } if ( strcmp(status, "program") == 0 && state <= 2 && part == total ) { printf("Done\n"); state = 3; } } usleep(0xc350); // 0.5s } } return 0; } int nolo_boot_device(struct usb_device_info * dev, const char * cmdline) { int size = 0; int mode = NOLO_BOOT_MODE_NORMAL; if ( cmdline && strncmp(cmdline, "update", strlen("update")) == 0 && cmdline[strlen("update")] <= 32 ) { mode = NOLO_BOOT_MODE_UPDATE; cmdline += strlen("update"); if ( *cmdline ) ++cmdline; while ( *cmdline && *cmdline <= 32 ) ++cmdline; if ( *cmdline ) { printf("Booting kernel to update mode with cmdline: %s...\n", cmdline); size = strlen(cmdline); } else { printf("Booting kernel to update mode with default cmdline...\n"); cmdline = NULL; } } else if ( cmdline && cmdline[0] ) { printf("Booting kernel with cmdline: '%s'...\n", cmdline); size = strlen(cmdline)+1; } else { printf("Booting kernel with default cmdline...\n"); cmdline = NULL; } if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_BOOT, mode, 0, (char *)cmdline, size, 2000) < 0 ) NOLO_ERROR_RETURN("Booting failed", -1); return 0; } int nolo_reboot_device(struct usb_device_info * dev) { printf("Rebooting device...\n"); if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_REBOOT, 0, 0, NULL, 0, 2000) < 0 ) NOLO_ERROR_RETURN("NOLO_REBOOT failed", -1); return 0; } int nolo_get_root_device(struct usb_device_info * dev) { uint8_t device = 0; if ( usb_control_msg(dev->udev, NOLO_QUERY, NOLO_GET, 0, NOLO_ROOT_DEVICE, (char *)&device, 1, 2000) < 0 ) NOLO_ERROR_RETURN("Cannot get root device", -1); return device; } int nolo_set_root_device(struct usb_device_info * dev, int device) { printf("Setting root device to %d...\n", device); if ( simulate ) return 0; if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_SET, device, NOLO_ROOT_DEVICE, NULL, 0, 2000) < 0 ) NOLO_ERROR_RETURN("Cannot set root device", -1); return 0; } int nolo_get_usb_host_mode(struct usb_device_info * dev) { uint32_t enabled = 0; if ( usb_control_msg(dev->udev, NOLO_QUERY, NOLO_GET, 0, NOLO_USB_HOST_MODE, (void *)&enabled, 4, 2000) < 0 ) NOLO_ERROR_RETURN("Cannot get USB host mode status", -1); return enabled ? 1 : 0; } int nolo_set_usb_host_mode(struct usb_device_info * dev, int enable) { printf("%s USB host mode...\n", enable ? "Enabling" : "Disabling"); if ( simulate ) return 0; if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_SET, enable, NOLO_USB_HOST_MODE, NULL, 0, 2000) < 0 ) NOLO_ERROR_RETURN("Cannot change USB host mode status", -1); return 0; } int nolo_get_rd_mode(struct usb_device_info * dev) { uint8_t enabled = 0; if ( usb_control_msg(dev->udev, NOLO_QUERY, NOLO_GET, 0, NOLO_RD_MODE, (char *)&enabled, 1, 2000) < 0 ) NOLO_ERROR_RETURN("Cannot get R&D mode status", -1); return enabled ? 1 : 0; } int nolo_set_rd_mode(struct usb_device_info * dev, int enable) { printf("%s R&D mode...\n", enable ? "Enabling" : "Disabling"); if ( simulate ) return 0; if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_SET, enable, NOLO_RD_MODE, NULL, 0, 2000) < 0 ) NOLO_ERROR_RETURN("Cannot change R&D mode status", -1); return 0; } #define APPEND_STRING(ptr, buf, size, string) do { if ( (int)size > ptr-buf ) ptr += snprintf(ptr, size-(ptr-buf), "%s,", string); } while (0) int nolo_get_rd_flags(struct usb_device_info * dev, char * flags, size_t size) { uint16_t add_flags = 0; char * ptr = flags; if ( usb_control_msg(dev->udev, NOLO_QUERY, NOLO_GET, 0, NOLO_ADD_RD_FLAGS, (char *)&add_flags, 2, 2000) < 0 ) NOLO_ERROR_RETURN("Cannot get R&D flags", -1); if ( add_flags & NOLO_RD_FLAG_NO_OMAP_WD ) APPEND_STRING(ptr, flags, size, "no-omap-wd"); if ( add_flags & NOLO_RD_FLAG_NO_EXT_WD ) APPEND_STRING(ptr, flags, size, "no-ext-wd"); if ( add_flags & NOLO_RD_FLAG_NO_LIFEGUARD ) APPEND_STRING(ptr, flags, size, "no-lifeguard-reset"); if ( add_flags & NOLO_RD_FLAG_SERIAL_CONSOLE ) APPEND_STRING(ptr, flags, size, "serial-console"); if ( add_flags & NOLO_RD_FLAG_NO_USB_TIMEOUT ) APPEND_STRING(ptr, flags, size, "no-usb-timeout"); if ( add_flags & NOLO_RD_FLAG_STI_CONSOLE ) APPEND_STRING(ptr, flags, size, "sti-console"); if ( add_flags & NOLO_RD_FLAG_NO_CHARGING ) APPEND_STRING(ptr, flags, size, "no-charging"); if ( add_flags & NOLO_RD_FLAG_FORCE_POWER_KEY ) APPEND_STRING(ptr, flags, size, "force-power-key"); if ( ptr != flags && *(ptr-1) == ',' ) *(--ptr) = 0; return ptr-flags; } #undef APPEND_STRING int nolo_set_rd_flags(struct usb_device_info * dev, const char * flags) { const char * ptr = flags; const char * endptr = ptr; int add_flags = 0; int del_flags = 0; if ( flags && flags[0] ) printf("Setting R&D flags to: %s...\n", flags); else printf("Clearing all R&D flags...\n"); while ( ptr && *ptr ) { while ( *ptr <= 32 ) ++ptr; if ( ! *ptr ) break; endptr = strchr(ptr, ','); if ( endptr ) endptr -= 1; else endptr = ptr+strlen(ptr); if ( strncmp("no-omap-wd", ptr, endptr-ptr) == 0 ) add_flags |= NOLO_RD_FLAG_NO_OMAP_WD; if ( strncmp("no-ext-wd", ptr, endptr-ptr) == 0 ) add_flags |= NOLO_RD_FLAG_NO_EXT_WD; if ( strncmp("no-lifeguard-reset", ptr, endptr-ptr) == 0 ) add_flags |= NOLO_RD_FLAG_NO_LIFEGUARD; if ( strncmp("serial-console", ptr, endptr-ptr) == 0 ) add_flags |= NOLO_RD_FLAG_SERIAL_CONSOLE; if ( strncmp("no-usb-timeout", ptr, endptr-ptr) == 0 ) add_flags |= NOLO_RD_FLAG_NO_USB_TIMEOUT; if ( strncmp("sti-console", ptr, endptr-ptr) == 0 ) add_flags |= NOLO_RD_FLAG_STI_CONSOLE; if ( strncmp("no-charging", ptr, endptr-ptr) == 0 ) add_flags |= NOLO_RD_FLAG_NO_CHARGING; if ( strncmp("force-power-key", ptr, endptr-ptr) == 0 ) add_flags |= NOLO_RD_FLAG_FORCE_POWER_KEY; if ( *(endptr+1) ) ptr = endptr+2; else break; } if ( ! ( add_flags & NOLO_RD_FLAG_NO_OMAP_WD ) ) del_flags |= NOLO_RD_FLAG_NO_OMAP_WD; if ( ! ( add_flags & NOLO_RD_FLAG_NO_EXT_WD ) ) del_flags |= NOLO_RD_FLAG_NO_EXT_WD; if ( ! ( add_flags & NOLO_RD_FLAG_NO_LIFEGUARD ) ) del_flags |= NOLO_RD_FLAG_NO_LIFEGUARD; if ( ! ( add_flags & NOLO_RD_FLAG_SERIAL_CONSOLE ) ) del_flags |= NOLO_RD_FLAG_SERIAL_CONSOLE; if ( ! ( add_flags & NOLO_RD_FLAG_NO_USB_TIMEOUT ) ) del_flags |= NOLO_RD_FLAG_NO_USB_TIMEOUT; if ( ! ( add_flags & NOLO_RD_FLAG_STI_CONSOLE ) ) del_flags |= NOLO_RD_FLAG_STI_CONSOLE; if ( ! ( add_flags & NOLO_RD_FLAG_NO_CHARGING ) ) del_flags |= NOLO_RD_FLAG_NO_CHARGING; if ( ! ( add_flags & NOLO_RD_FLAG_FORCE_POWER_KEY ) ) del_flags |= NOLO_RD_FLAG_FORCE_POWER_KEY; if ( simulate ) return 0; if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_SET, add_flags, NOLO_ADD_RD_FLAGS, NULL, 0, 2000) < 0 ) NOLO_ERROR_RETURN("Cannot add R&D flags", -1); if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_SET, del_flags, NOLO_DEL_RD_FLAGS, NULL, 0, 2000) < 0 ) NOLO_ERROR_RETURN("Cannot del R&D flags", -1); return 0; } int16_t nolo_get_hwrev(struct usb_device_info * dev) { char buf[10]; if ( nolo_identify_string(dev, "hw_rev", buf, sizeof(buf)) <= 0 ) return -1; return atoi(buf); } int nolo_set_hwrev(struct usb_device_info * dev, int16_t hwrev) { char buf[9]; memset(buf, 0, sizeof(buf)); snprintf(buf, 8, "%d", hwrev); printf("Setting HW revision to: %s\n", buf); return nolo_set_string(dev, "hw_rev", buf); } int nolo_get_kernel_ver(struct usb_device_info * dev, char * ver, size_t size) { return nolo_get_version_string(dev, "kernel", ver, size); } int nolo_set_kernel_ver(struct usb_device_info * dev, const char * ver) { printf("nolo_set_kernel_ver is not implemented yet\n"); (void)dev; (void)ver; return -1; } int nolo_get_initfs_ver(struct usb_device_info * dev, char * ver, size_t size) { return nolo_get_version_string(dev, "initfs", ver, size); } int nolo_set_initfs_ver(struct usb_device_info * dev, const char * ver) { printf("nolo_set_initfs_ver is not implemented yet\n"); (void)dev; (void)ver; return -1; } int nolo_get_nolo_ver(struct usb_device_info * dev, char * ver, size_t size) { uint32_t version = 0; if ( usb_control_msg(dev->udev, NOLO_QUERY, NOLO_GET_NOLO_VERSION, 0, 0, (char *)&version, 4, 2000) < 0 ) NOLO_ERROR_RETURN("Cannot get NOLO version", -1); if ( (version & 255) > 1 ) NOLO_ERROR_RETURN("Invalid NOLO version", -1); return snprintf(ver, size, "%d.%d.%d", version >> 20 & 15, version >> 16 & 15, version >> 8 & 255); } int nolo_set_nolo_ver(struct usb_device_info * dev, const char * ver) { printf("nolo_set_nolo_ver is not implemented yet\n"); (void)dev; (void)ver; return -1; } int nolo_get_sw_ver(struct usb_device_info * dev, char * ver, size_t size) { return nolo_get_version_string(dev, "sw-release", ver, size); } int nolo_set_sw_ver(struct usb_device_info * dev, const char * ver) { char buf[512]; char * ptr; uint8_t len; const char * str = "OSSO UART+USB"; printf("Setting Software release string to: %s\n", ver); if ( strlen(ver) > UINT8_MAX ) NOLO_ERROR_RETURN("Software release string is too long", -1); ptr = buf; memcpy(ptr, "\xe8", 1); ptr += 1; len = strlen(str)+1; memcpy(ptr, &len, 1); ptr += 1; memcpy(ptr, str, len); ptr += len; memcpy(ptr, "\x31", 1); ptr += 1; len = strlen(ver)+1; memcpy(ptr, &len, 1); ptr += 1; memcpy(ptr, ver, len); ptr += len; if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_SET_SW_RELEASE, 0, 0, buf, ptr-buf, 2000) < 0 ) NOLO_ERROR_RETURN("NOLO_SET_SW_RELEASE failed", -1); return 0; } int nolo_get_content_ver(struct usb_device_info * dev, char * ver, size_t size) { return nolo_get_version_string(dev, "content", ver, size); } int nolo_set_content_ver(struct usb_device_info * dev, const char * ver) { printf("nolo_set_content_ver is not implemented yet\n"); (void)dev; (void)ver; return -1; } 0xffff-0.6~git20130406/src/nolo.h000066400000000000000000000052101213002553000161540ustar00rootroot00000000000000/* * 0xFFFF - Open Free Fiasco Firmware Flasher * Copyright (C) 2007 pancake * Copyright (C) 2012 Pali Rohár * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef NOLO_H #define NOLO_H #include "image.h" #include "usb-device.h" int nolo_init(struct usb_device_info * dev); enum device nolo_get_device(struct usb_device_info * dev); int nolo_load_image(struct usb_device_info * dev, struct image * image); int nolo_flash_image(struct usb_device_info * dev, struct image * image); int nolo_boot_device(struct usb_device_info * dev, const char * cmdline); int nolo_reboot_device(struct usb_device_info * dev); int nolo_get_root_device(struct usb_device_info * dev); int nolo_set_root_device(struct usb_device_info * dev, int device); int nolo_get_usb_host_mode(struct usb_device_info * dev); int nolo_set_usb_host_mode(struct usb_device_info * dev, int enable); int nolo_get_rd_mode(struct usb_device_info * dev); int nolo_set_rd_mode(struct usb_device_info * dev, int enable); int nolo_get_rd_flags(struct usb_device_info * dev, char * flags, size_t size); int nolo_set_rd_flags(struct usb_device_info * dev, const char * flags); int16_t nolo_get_hwrev(struct usb_device_info * dev); int nolo_set_hwrev(struct usb_device_info * dev, int16_t hwrev); int nolo_get_kernel_ver(struct usb_device_info * dev, char * ver, size_t size); int nolo_set_kernel_ver(struct usb_device_info * dev, const char * ver); int nolo_get_initfs_ver(struct usb_device_info * dev, char * ver, size_t size); int nolo_set_initfs_ver(struct usb_device_info * dev, const char * ver); int nolo_get_nolo_ver(struct usb_device_info * dev, char * ver, size_t size); int nolo_set_nolo_ver(struct usb_device_info * dev, const char * ver); int nolo_get_sw_ver(struct usb_device_info * dev, char * ver, size_t size); int nolo_set_sw_ver(struct usb_device_info * dev, const char * ver); int nolo_get_content_ver(struct usb_device_info * dev, char * ver, size_t size); int nolo_set_content_ver(struct usb_device_info * dev, const char * ver); #endif 0xffff-0.6~git20130406/src/operations.c000066400000000000000000000315741213002553000173770ustar00rootroot00000000000000/* 0xFFFF - Open Free Fiasco Firmware Flasher Copyright (C) 2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "global.h" #include "device.h" #include "usb-device.h" #include "cold-flash.h" #include "nolo.h" #include "mkii.h" #include "disk.h" #include "local.h" #include "operations.h" struct device_info * dev_detect(void) { int ret = 0; struct device_info * dev = NULL; struct usb_device_info * usb = NULL; dev = calloc(1, sizeof(struct device_info)); if ( ! dev ) goto clean; /* LOCAL */ if ( local_init() == 0 ) { dev->method = METHOD_LOCAL; dev->detected_device = local_get_device(); dev->detected_hwrev = local_get_hwrev(); return dev; } /* USB */ usb = usb_open_and_wait_for_device(); if ( usb ) { dev->method = METHOD_USB; dev->usb = usb; if ( dev->usb->flash_device->protocol == FLASH_NOLO ) ret = nolo_init(dev->usb); else if ( dev->usb->flash_device->protocol == FLASH_COLD ) ret = init_cold_flash(dev->usb); else if ( dev->usb->flash_device->protocol == FLASH_MKII ) ret = mkii_init(dev->usb); else if ( dev->usb->flash_device->protocol == FLASH_DISK ) ret = disk_init(dev->usb); else { ERROR("Unknown USB mode"); goto clean; } if ( ret < 0 ) goto clean; dev->detected_device = dev_get_device(dev); dev->detected_hwrev = dev_get_hwrev(dev); if ( dev->detected_device && dev->usb->device && dev->detected_device != dev->usb->device ) { ERROR("Bad device, expected %s, got %s", device_to_string(dev->usb->device), device_to_string(dev->detected_device)); goto clean; } return dev; } clean: usb_close_device(usb); free(dev); return NULL; } void dev_free(struct device_info * dev) { if ( dev->usb ) usb_close_device(dev->usb); free(dev); } enum device dev_get_device(struct device_info * dev) { if ( dev->method == METHOD_LOCAL ) return local_get_device(); if ( dev->method == METHOD_USB ) { enum usb_flash_protocol protocol = dev->usb->flash_device->protocol; if ( protocol == FLASH_COLD ) return DEVICE_UNKNOWN; else if ( protocol == FLASH_NOLO ) return nolo_get_device(dev->usb); else if ( protocol == FLASH_MKII ) return mkii_get_device(dev->usb); /* else if ( protocol == FLASH_DISK ) return disk_get_device(dev->usb);*/ } return DEVICE_UNKNOWN; } int dev_load_image(struct device_info * dev, struct image * image) { if ( dev->method == METHOD_LOCAL ) { ERROR("Loading image on local device is not supported"); return -1; } if ( dev->method == METHOD_USB ) { enum usb_flash_protocol protocol = dev->usb->flash_device->protocol; if ( protocol == FLASH_NOLO ) return nolo_load_image(dev->usb, image); usb_switch_to_nolo(dev->usb); return -EAGAIN; } return -1; } int dev_cold_flash_images(struct device_info * dev, struct image * x2nd, struct image * secondary) { if ( dev->method == METHOD_LOCAL ) { ERROR("Cold Flashing on local device is not supported"); return -1; } if ( dev->method == METHOD_USB ) { enum usb_flash_protocol protocol = dev->usb->flash_device->protocol; if ( protocol == FLASH_COLD ) return cold_flash(dev->usb, x2nd, secondary); usb_switch_to_cold(dev->usb); return -EAGAIN; } return -1; } int dev_flash_image(struct device_info * dev, struct image * image) { if ( dev->method == METHOD_LOCAL ) return local_flash_image(image); if ( dev->method == METHOD_USB ) { enum usb_flash_protocol protocol = dev->usb->flash_device->protocol; if ( protocol == FLASH_NOLO ) return nolo_flash_image(dev->usb, image); else if ( protocol == FLASH_MKII ) return mkii_flash_image(dev->usb, image); else { usb_switch_to_nolo(dev->usb); return -EAGAIN; } } return -1; } int dev_dump_image(struct device_info * dev, enum image_type image, const char * file) { if ( dev->method == METHOD_LOCAL ) return local_dump_image(image, file); if ( dev->method == METHOD_USB ) { ERROR("Dump image via USB is not supported"); return -1; } return -1; } int dev_check_badblocks(struct device_info * dev, const char * device) { if ( dev->method == METHOD_LOCAL ) return local_check_badblocks(device); if ( dev->method == METHOD_USB ) { ERROR("Check for badblocks via USB is not supported"); return -1; } return -1; } int dev_boot_device(struct device_info * dev, const char * cmdline) { if ( dev->method == METHOD_LOCAL ) { ERROR("Booting device on local device does not make sense"); return -1; } if ( dev->method == METHOD_USB ) { enum usb_flash_protocol protocol = dev->usb->flash_device->protocol; if ( protocol == FLASH_NOLO ) return nolo_boot_device(dev->usb, cmdline); else { usb_switch_to_nolo(dev->usb); return 0; } } return -1; } int dev_reboot_device(struct device_info * dev) { if ( dev->method == METHOD_LOCAL ) return local_reboot_device(); if ( dev->method == METHOD_USB ) { enum usb_flash_protocol protocol = dev->usb->flash_device->protocol; if ( protocol == FLASH_COLD ) return leave_cold_flash(dev->usb); else if ( protocol == FLASH_NOLO ) return nolo_reboot_device(dev->usb); else if ( protocol == FLASH_MKII ) return mkii_reboot_device(dev->usb); else { ERROR("Rebooting device in RAW disk mode is not supported"); return -1; } } return -1; } int dev_get_root_device(struct device_info * dev) { if ( dev->method == METHOD_LOCAL ) return local_get_root_device(); if ( dev->method == METHOD_USB ) { enum usb_flash_protocol protocol = dev->usb->flash_device->protocol; if ( protocol == FLASH_NOLO ) return nolo_get_root_device(dev->usb); } return -1; } int dev_set_root_device(struct device_info * dev, int device) { if ( dev->method == METHOD_LOCAL ) return local_set_root_device(device); if ( dev->method == METHOD_USB ) { if ( dev->usb->flash_device->protocol == FLASH_NOLO ) return nolo_set_root_device(dev->usb, device); if ( dev->usb->flash_device->protocol == FLASH_COLD ) { usb_switch_to_nolo(dev->usb); return -EAGAIN; } } return -1; } int dev_get_usb_host_mode(struct device_info * dev) { if ( dev->method == METHOD_LOCAL ) return local_get_usb_host_mode(); if ( dev->method == METHOD_USB ) { if ( dev->usb->flash_device->protocol == FLASH_NOLO ) return nolo_get_usb_host_mode(dev->usb); } return -1; } int dev_set_usb_host_mode(struct device_info * dev, int enable) { if ( dev->method == METHOD_LOCAL ) return local_set_usb_host_mode(enable); if ( dev->method == METHOD_USB ) { if ( dev->usb->flash_device->protocol == FLASH_NOLO ) return nolo_set_usb_host_mode(dev->usb, enable); if ( dev->usb->flash_device->protocol == FLASH_COLD ) { usb_switch_to_nolo(dev->usb); return -EAGAIN; } } return -1; } int dev_get_rd_mode(struct device_info * dev) { if ( dev->method == METHOD_LOCAL ) return local_get_rd_mode(); if ( dev->method == METHOD_USB ) { if ( dev->usb->flash_device->protocol == FLASH_NOLO ) return nolo_get_rd_mode(dev->usb); } return -1; } int dev_set_rd_mode(struct device_info * dev, int enable) { if ( dev->method == METHOD_LOCAL ) return local_set_rd_mode(enable); if ( dev->method == METHOD_USB ) { if ( dev->usb->flash_device->protocol == FLASH_NOLO ) return nolo_set_rd_mode(dev->usb, enable); if ( dev->usb->flash_device->protocol == FLASH_COLD ) { usb_switch_to_nolo(dev->usb); return -EAGAIN; } } return -1; } int dev_get_rd_flags(struct device_info * dev, char * flags, size_t size) { if ( dev->method == METHOD_LOCAL ) return local_get_rd_flags(flags, size); if ( dev->method == METHOD_USB ) { if ( dev->usb->flash_device->protocol == FLASH_NOLO ) return nolo_get_rd_flags(dev->usb, flags, size); } return -1; } int dev_set_rd_flags(struct device_info * dev, const char * flags) { if ( dev->method == METHOD_LOCAL ) return local_set_rd_flags(flags); if ( dev->method == METHOD_USB ) { if ( dev->usb->flash_device->protocol == FLASH_NOLO ) return nolo_set_rd_flags(dev->usb, flags); if ( dev->usb->flash_device->protocol == FLASH_COLD ) { usb_switch_to_nolo(dev->usb); return -EAGAIN; } } return -1; } int16_t dev_get_hwrev(struct device_info * dev) { if ( dev->method == METHOD_LOCAL ) return local_get_hwrev(); if ( dev->method == METHOD_USB ) { if ( dev->usb->flash_device->protocol == FLASH_NOLO ) return nolo_get_hwrev(dev->usb); } return -1; } int dev_set_hwrev(struct device_info * dev, int16_t hwrev) { if ( dev->method == METHOD_LOCAL ) return local_set_hwrev(hwrev); if ( dev->method == METHOD_USB ) { if ( dev->usb->flash_device->protocol == FLASH_NOLO ) return nolo_set_hwrev(dev->usb, hwrev); if ( dev->usb->flash_device->protocol == FLASH_COLD ) { usb_switch_to_nolo(dev->usb); return -EAGAIN; } } return -1; } int dev_get_kernel_ver(struct device_info * dev, char * ver, size_t size) { if ( dev->method == METHOD_LOCAL ) return local_get_kernel_ver(ver, size); if ( dev->method == METHOD_USB ) { if ( dev->usb->flash_device->protocol == FLASH_NOLO ) return nolo_get_kernel_ver(dev->usb, ver, size); } return -1; } int dev_set_kernel_ver(struct device_info * dev, const char * ver) { if ( dev->method == METHOD_LOCAL ) return local_set_kernel_ver(ver); if ( dev->method == METHOD_USB ) { if ( dev->usb->flash_device->protocol == FLASH_NOLO ) return nolo_set_kernel_ver(dev->usb, ver); if ( dev->usb->flash_device->protocol == FLASH_COLD ) { usb_switch_to_nolo(dev->usb); return -EAGAIN; } } return -1; } int dev_get_initfs_ver(struct device_info * dev, char * ver, size_t size) { if ( dev->method == METHOD_LOCAL ) return local_get_initfs_ver(ver, size); if ( dev->method == METHOD_USB ) { if ( dev->usb->flash_device->protocol == FLASH_NOLO ) return nolo_get_initfs_ver(dev->usb, ver, size); } return -1; } int dev_set_initfs_ver(struct device_info * dev, const char * ver) { if ( dev->method == METHOD_LOCAL ) return local_set_initfs_ver(ver); if ( dev->method == METHOD_USB ) { if ( dev->usb->flash_device->protocol == FLASH_NOLO ) return nolo_set_initfs_ver(dev->usb, ver); if ( dev->usb->flash_device->protocol == FLASH_COLD ) { usb_switch_to_nolo(dev->usb); return -EAGAIN; } } return -1; } int dev_get_nolo_ver(struct device_info * dev, char * ver, size_t size) { if ( dev->method == METHOD_LOCAL ) return local_get_nolo_ver(ver, size); if ( dev->method == METHOD_USB ) { if ( dev->usb->flash_device->protocol == FLASH_NOLO ) return nolo_get_nolo_ver(dev->usb, ver, size); } return -1; } int dev_set_nolo_ver(struct device_info * dev, const char * ver) { if ( dev->method == METHOD_LOCAL ) return local_set_nolo_ver(ver); if ( dev->method == METHOD_USB ) { if ( dev->usb->flash_device->protocol == FLASH_NOLO ) return nolo_set_nolo_ver(dev->usb, ver); if ( dev->usb->flash_device->protocol == FLASH_COLD ) { usb_switch_to_nolo(dev->usb); return -EAGAIN; } } return -1; } int dev_get_sw_ver(struct device_info * dev, char * ver, size_t size) { if ( dev->method == METHOD_LOCAL ) return local_get_sw_ver(ver, size); if ( dev->method == METHOD_USB ) { if ( dev->usb->flash_device->protocol == FLASH_NOLO ) return nolo_get_sw_ver(dev->usb, ver, size); } return -1; } int dev_set_sw_ver(struct device_info * dev, const char * ver) { if ( dev->method == METHOD_LOCAL ) return local_set_sw_ver(ver); if ( dev->method == METHOD_USB ) { if ( dev->usb->flash_device->protocol == FLASH_NOLO ) return nolo_set_sw_ver(dev->usb, ver); if ( dev->usb->flash_device->protocol == FLASH_COLD ) { usb_switch_to_nolo(dev->usb); return -EAGAIN; } } return -1; } int dev_get_content_ver(struct device_info * dev, char * ver, size_t size) { if ( dev->method == METHOD_LOCAL ) return local_get_content_ver(ver, size); if ( dev->method == METHOD_USB ) { if ( dev->usb->flash_device->protocol == FLASH_NOLO ) return nolo_get_content_ver(dev->usb, ver, size); } return -1; } int dev_set_content_ver(struct device_info * dev, const char * ver) { if ( dev->method == METHOD_LOCAL ) return local_set_content_ver(ver); if ( dev->method == METHOD_USB ) { if ( dev->usb->flash_device->protocol == FLASH_NOLO ) return nolo_set_content_ver(dev->usb, ver); if ( dev->usb->flash_device->protocol == FLASH_COLD ) { usb_switch_to_nolo(dev->usb); return -EAGAIN; } } return -1; } 0xffff-0.6~git20130406/src/operations.h000066400000000000000000000057401213002553000174000ustar00rootroot00000000000000/* 0xFFFF - Open Free Fiasco Firmware Flasher Copyright (C) 2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef OPERATIONS_H #define OPERATIONS_H #include "image.h" #include "usb-device.h" enum connection_method { METHOD_UNKNOWN = 0, METHOD_USB, METHOD_LOCAL, }; struct device_info { enum connection_method method; enum device detected_device; int16_t detected_hwrev; struct usb_device_info * usb; }; struct device_info * dev_detect(void); void dev_free(struct device_info * dev); enum device dev_get_device(struct device_info * dev); int dev_cold_flash_images(struct device_info * dev, struct image * x2nd, struct image * secondary); int dev_load_image(struct device_info * dev, struct image * image); int dev_flash_image(struct device_info * dev, struct image * image); int dev_dump_image(struct device_info * dev, enum image_type image, const char * file); int dev_check_badblocks(struct device_info * dev, const char * device); int dev_boot_device(struct device_info * dev, const char * cmdline); int dev_reboot_device(struct device_info * dev); int dev_get_root_device(struct device_info * dev); int dev_set_root_device(struct device_info * dev, int device); int dev_get_usb_host_mode(struct device_info * dev); int dev_set_usb_host_mode(struct device_info * dev, int enable); int dev_get_rd_mode(struct device_info * dev); int dev_set_rd_mode(struct device_info * dev, int enable); int dev_get_rd_flags(struct device_info * dev, char * flags, size_t size); int dev_set_rd_flags(struct device_info * dev, const char * flags); int16_t dev_get_hwrev(struct device_info * dev); int dev_set_hwrev(struct device_info * dev, int16_t hwrev); int dev_get_kernel_ver(struct device_info * dev, char * ver, size_t size); int dev_set_kernel_ver(struct device_info * dev, const char * ver); int dev_get_initfs_ver(struct device_info * dev, char * ver, size_t size); int dev_set_initfs_ver(struct device_info * dev, const char * ver); int dev_get_nolo_ver(struct device_info * dev, char * ver, size_t size); int dev_set_nolo_ver(struct device_info * dev, const char * ver); int dev_get_sw_ver(struct device_info * dev, char * ver, size_t size); int dev_set_sw_ver(struct device_info * dev, const char * ver); int dev_get_content_ver(struct device_info * dev, char * ver, size_t size); int dev_set_content_ver(struct device_info * dev, const char * ver); #endif 0xffff-0.6~git20130406/src/printf-utils.c000066400000000000000000000041521213002553000176440ustar00rootroot00000000000000/* * 0xFFFF - Open Free Fiasco Firmware Flasher * Copyright (C) 2007 pancake * Copyright (C) 2012 Pali Rohár * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include "global.h" #include "printf-utils.h" int printf_prev = 0; void printf_progressbar(unsigned long long part, unsigned long long total) { char *columns = getenv("COLUMNS"); int pc; int tmp, cols = 80; /* percentage calculation */ pc = (int)(part*100/total); (pc<0)?pc=0:(pc>100)?pc=100:0; #if HAVE_SQUEUE if (qmode) { char msg[128]; sprintf(msg, "%d%%", pc); squeue_push2(p, "bar", msg, 0); } else { #endif PRINTF_BACK(); PRINTF_ADD("\x1b[K %3d%% [", pc); if (columns) cols = atoi(columns); if (cols > 115) cols = 115; cols-=15; for(tmp=cols*pc/100;tmp;tmp--) PRINTF_ADD("#"); for(tmp=cols-(cols*pc/100);tmp;tmp--) PRINTF_ADD("-"); PRINTF_ADD("]"); if (part == total) PRINTF_END(); fflush(stdout); #if HAVE_SQUEUE } #endif } void printf_and_wait(const char * format, ...) { va_list ap; char c; fd_set rfds; struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO(&rfds); FD_SET(0, &rfds); while ( select(1, &rfds, NULL, NULL, &tv) == 1 ) read(0, &c, 1); va_start(ap, format); vprintf(format, ap); va_end(ap); fflush(stdout); FD_ZERO(&rfds); FD_SET(0, &rfds); while ( select(1, &rfds, NULL, NULL, NULL) == 1 ) { read(0, &c, 1); if ( c == '\n' ) break; } } 0xffff-0.6~git20130406/src/printf-utils.h000066400000000000000000000031221213002553000176450ustar00rootroot00000000000000/* * 0xFFFF - Open Free Fiasco Firmware Flasher * Copyright (C) 2007 pancake * Copyright (C) 2012 Pali Rohár * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef PRINTF_UTILS_H #define PRINTF_UTILS_H #include "global.h" extern int printf_prev; #define PRINTF_BACK() do { if ( printf_prev ) { printf("\r%-*s\r", printf_prev, ""); printf_prev = 0; } } while (0) #define PRINTF_ADD(...) do { printf_prev += printf(__VA_ARGS__); } while (0) #define PRINTF_LINE(...) do { PRINTF_BACK(); PRINTF_ADD(__VA_ARGS__); fflush(stdout); } while (0) #define PRINTF_END() do { if ( printf_prev ) { printf("\n"); printf_prev = 0; } } while (0) #define PRINTF_ERROR(...) do { PRINTF_END(); ERROR_INFO(__VA_ARGS__); } while (0) #define PRINTF_ERROR_RETURN(str, ...) do { PRINTF_ERROR("%s", str); return __VA_ARGS__; } while (0) void printf_progressbar(unsigned long long part, unsigned long long total); void printf_and_wait(const char * format, ...); #endif 0xffff-0.6~git20130406/src/usb-device.c000066400000000000000000000212401213002553000172270ustar00rootroot00000000000000/* 0xFFFF - Open Free Fiasco Firmware Flasher Copyright (C) 2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include "global.h" #include "device.h" #include "usb-device.h" #include "printf-utils.h" #include "nolo.h" #include "cold-flash.h" #include "mkii.h" static struct usb_flash_device usb_devices[] = { { 0x0421, 0x0105, 2, 1, -1, FLASH_NOLO, { DEVICE_SU_18, DEVICE_RX_44, DEVICE_RX_48, DEVICE_RX_51, 0 } }, { 0x0421, 0x0106, 0, -1, -1, FLASH_COLD, { DEVICE_RX_51, 0 } }, /* { 0x0421, 0x01c7, 0, -1, -1, FLASH_DISK, { DEVICE_RX_51, 0 } }, */ /* { 0x0421, 0x01c8, 1, 1, -1, FLASH_MKII, { DEVICE_RX_51, 0 } }, */ /* { 0x0421, 0x0431, 0, -1, -1, FLASH_DISK, { DEVICE_SU_18, DEVICE_RX_34, 0 } }, */ { 0x0421, 0x3f00, 2, 1, -1, FLASH_NOLO, { DEVICE_RX_34, 0 } }, }; static const char * usb_flash_protocols[] = { [FLASH_NOLO] = "NOLO", [FLASH_COLD] = "Cold flashing", [FLASH_MKII] = "Mk II protocol", [FLASH_DISK] = "RAW disk", }; const char * usb_flash_protocol_to_string(enum usb_flash_protocol protocol) { if ( protocol > sizeof(usb_flash_protocols) ) return NULL; return usb_flash_protocols[protocol]; } static void usb_flash_device_info_print(const struct usb_flash_device * dev) { int i; PRINTF_ADD("USB device: %s", device_to_string(dev->devices[0])); for ( i = 1; dev->devices[i]; ++i ) PRINTF_ADD("/%s", device_to_string(dev->devices[i])); PRINTF_ADD(" (%#04x:%#04x) in %s mode", dev->vendor, dev->product, usb_flash_protocol_to_string(dev->protocol)); } static void usb_descriptor_info_print(usb_dev_handle * udev, struct usb_device * dev, char * product, size_t size) { char buf[1024]; char buf2[1024]; unsigned int x; int ret; int i; memset(buf, 0, sizeof(buf)); usb_get_string_simple(udev, dev->descriptor.iProduct, buf, sizeof(buf)); PRINTF_LINE("USB device product string: %s", buf[0] ? buf : "(not detected)"); PRINTF_END(); if ( product && buf[0] ) strncpy(product, buf, size); memset(buf, 0, sizeof(buf)); memset(buf2, 0, sizeof(buf2)); ret = usb_get_string_simple(udev, dev->descriptor.iSerialNumber, buf, sizeof(buf)); if ( ! isalnum(buf[0]) ) buf[0] = 0; for ( i = 0; i < ret; i+=2 ) { sscanf(buf+i, "%2x", &x); if ( x > 32 && x < 128 ) buf2[i/2] = x; else { buf2[0] = 0; break; } } if ( ! isalnum(buf2[0]) ) buf2[0] = 0; PRINTF_LINE("USB device serial number string: %s", buf2[0] ? buf2 : ( buf[0] ? buf : "(not detected)" )); PRINTF_END(); } static struct usb_device_info * usb_device_is_valid(struct usb_device * dev) { int i; char product[1024]; struct usb_device_info * ret = NULL; for ( i = 0; usb_devices[i].vendor; ++i ) { if ( dev->descriptor.idVendor == usb_devices[i].vendor && dev->descriptor.idProduct == usb_devices[i].product ) { printf("\b\b "); PRINTF_END(); PRINTF_ADD("Found "); usb_flash_device_info_print(&usb_devices[i]); PRINTF_END(); PRINTF_LINE("Opening USB..."); usb_dev_handle * udev = usb_open(dev); if ( ! udev ) { PRINTF_ERROR("usb_open failed"); fprintf(stderr, "\n"); return NULL; } usb_descriptor_info_print(udev, dev, product, sizeof(product)); #if defined(LIBUSB_HAS_GET_DRIVER_NP) && defined(LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP) PRINTF_LINE("Detaching kernel from USB interface..."); usb_detach_kernel_driver_np(udev, usb_devices[i].interface); #endif PRINTF_LINE("Claiming USB interface..."); if ( usb_claim_interface(udev, usb_devices[i].interface) < 0 ) { PRINTF_ERROR("usb_claim_interface failed"); fprintf(stderr, "\n"); usb_close(udev); return NULL; } if ( usb_devices[i].alternate >= 0 ) { PRINTF_LINE("Setting alternate USB interface..."); if ( usb_set_altinterface(udev, usb_devices[i].alternate) < 0 ) { PRINTF_ERROR("usb_claim_interface failed"); fprintf(stderr, "\n"); usb_close(udev); return NULL; } } if ( usb_devices[i].configuration >= 0 ) { PRINTF_LINE("Setting USB configuration..."); if ( usb_set_configuration(udev, usb_devices[i].configuration) < 0 ) { PRINTF_ERROR("usb_set_configuration failed"); fprintf(stderr, "\n"); usb_close(udev); return NULL; } } ret = calloc(1, sizeof(struct usb_device_info)); if ( ! ret ) { ALLOC_ERROR(); usb_close(udev); return NULL; } if ( strstr(product, "N900") ) ret->device = DEVICE_RX_51; else ret->device = DEVICE_UNKNOWN; /* TODO: Autodetect more devices */ if ( device_to_string(ret->device) ) PRINTF_LINE("Detected USB device: %s", device_to_string(ret->device)); else PRINTF_LINE("Detected USB device: (not detected)"); PRINTF_END(); if ( ret->device ) { enum device * device; for ( device = usb_devices[i].devices; *device; ++device ) if ( *device == ret->device ) break; if ( ! *device ) { ERROR("Device mishmash"); fprintf(stderr, "\n"); usb_close(udev); return NULL; } } ret->hwrev = -1; ret->flash_device = &usb_devices[i]; ret->udev = udev; break; } } return ret; } static struct usb_device_info * usb_search_device(struct usb_device * dev, int level) { int i; struct usb_device_info * ret = NULL; if ( ! dev ) return NULL; ret = usb_device_is_valid(dev); if ( ret ) return ret; for ( i = 0; i < dev->num_children; i++ ) { ret = usb_search_device(dev->children[i], level + 1); if ( ret ) break; } return ret; } struct usb_device_info * usb_open_and_wait_for_device(void) { struct usb_bus * bus; struct usb_device_info * ret = NULL; int i = 0; static char progress[] = {'/','-','\\', '|'}; usb_init(); usb_find_busses(); PRINTF_BACK(); printf("\n"); while ( 1 ) { PRINTF_LINE("Waiting for USB device... %c", progress[++i%sizeof(progress)]); usb_find_devices(); for ( bus = usb_get_busses(); bus; bus = bus->next ) { if ( bus->root_dev ) ret = usb_search_device(bus->root_dev, 0); else { struct usb_device *dev; for ( dev = bus->devices; dev; dev = dev->next ) { ret = usb_search_device(dev, 0); if ( ret ) break; } } if ( ret ) break; } if ( ret ) break; usleep(0xc350); // 0.5s } PRINTF_BACK(); printf("\n"); if ( ! ret ) return NULL; return ret; } void usb_close_device(struct usb_device_info * dev) { usb_close(dev->udev); free(dev); } void usb_switch_to_nolo(struct usb_device_info * dev) { printf("\nSwitching to NOLO mode...\n"); if ( dev->flash_device->protocol == FLASH_COLD ) leave_cold_flash(dev); else if ( dev->flash_device->protocol == FLASH_MKII ) mkii_reboot_device(dev); else if ( dev->flash_device->protocol == FLASH_DISK ) printf_and_wait("Unplug USB cable, turn device off, press ENTER and plug USB cable again"); } void usb_switch_to_cold(struct usb_device_info * dev) { printf("\nSwitching to Cold Flash mode...\n"); if ( dev->flash_device->protocol == FLASH_NOLO ) nolo_reboot_device(dev); else if ( dev->flash_device->protocol == FLASH_MKII ) mkii_reboot_device(dev); else if ( dev->flash_device->protocol == FLASH_DISK ) printf_and_wait("Unplug USB cable, turn device off, press ENTER and plug USB cable again"); } void usb_switch_to_mkii(struct usb_device_info * dev) { printf("\nSwitching to Update mode...\n"); if ( dev->flash_device->protocol == FLASH_COLD ) leave_cold_flash(dev); else if ( dev->flash_device->protocol == FLASH_NOLO ) nolo_boot_device(dev, "update"); else if ( dev->flash_device->protocol == FLASH_DISK ) printf_and_wait("Unplug USB cable, turn device off, press ENTER and plug USB cable again"); } void usb_switch_to_disk(struct usb_device_info * dev) { printf("\nSwitching to RAW disk mode...\n"); if ( dev->flash_device->protocol == FLASH_COLD ) leave_cold_flash(dev); else if ( dev->flash_device->protocol == FLASH_NOLO ) { nolo_boot_device(dev, NULL); printf_and_wait("Wait until device start, choose USB Mass Storage Mode and press ENTER"); } else if ( dev->flash_device->protocol == FLASH_MKII ) mkii_reboot_device(dev); } 0xffff-0.6~git20130406/src/usb-device.h000066400000000000000000000032551213002553000172420ustar00rootroot00000000000000/* 0xFFFF - Open Free Fiasco Firmware Flasher Copyright (C) 2012 Pali Rohár This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef USB_DEVICE_H #define USB_DEVICE_H #include #include "device.h" enum usb_flash_protocol { FLASH_UNKN = 0, FLASH_NOLO, FLASH_COLD, FLASH_MKII, FLASH_DISK, FLASH_COUNT, }; struct usb_flash_device { uint16_t vendor; uint16_t product; int interface; int alternate; int configuration; enum usb_flash_protocol protocol; enum device devices[DEVICE_COUNT]; }; struct usb_device_info { enum device device; int16_t hwrev; const struct usb_flash_device * flash_device; usb_dev_handle * udev; }; const char * usb_flash_protocol_to_string(enum usb_flash_protocol protocol); struct usb_device_info * usb_open_and_wait_for_device(void); void usb_close_device(struct usb_device_info * dev); void usb_switch_to_nolo(struct usb_device_info * dev); void usb_switch_to_cold(struct usb_device_info * dev); void usb_switch_to_mkii(struct usb_device_info * dev); void usb_switch_to_disk(struct usb_device_info * dev); #endif