diff --git a/jzboot/.gitignore b/jzboot/.gitignore new file mode 100644 index 0000000..53c644c --- /dev/null +++ b/jzboot/.gitignore @@ -0,0 +1,6 @@ +.deps +Makefile +Makefile.in +jzboot +*.o +*.d diff --git a/jzboot/COPYING b/jzboot/COPYING new file mode 100644 index 0000000..e4cc176 --- /dev/null +++ b/jzboot/COPYING @@ -0,0 +1,4 @@ +firmware/spl_stage1.bin, firmware/spl_stage2_usb.bin are (c) Ingenic Semiconductor Co.,Ltd. +ingenic.h is based on code by Ingenic Semiconductor Co.,Ltd. + +All other files have their authors and licenses described at their beginning. diff --git a/jzboot/COPYING.GPL3 b/jzboot/COPYING.GPL3 new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/jzboot/COPYING.GPL3 @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/jzboot/Makefile.am b/jzboot/Makefile.am new file mode 100644 index 0000000..f963eff --- /dev/null +++ b/jzboot/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src \ No newline at end of file diff --git a/jzboot/README b/jzboot/README new file mode 100644 index 0000000..e16acdd --- /dev/null +++ b/jzboot/README @@ -0,0 +1,5 @@ +Needs libusb-1.0 (not 0.1!) to work. Readline is optional. +To build: + make -C src +If you have readline (recommended): + make -C src READLINE=1 diff --git a/jzboot/config/boot.cfg b/jzboot/config/boot.cfg new file mode 100644 index 0000000..15993e7 --- /dev/null +++ b/jzboot/config/boot.cfg @@ -0,0 +1,4 @@ +source config/initial.cfg + +boot + diff --git a/jzboot/config/initial.cfg b/jzboot/config/initial.cfg new file mode 100644 index 0000000..a2c9370 --- /dev/null +++ b/jzboot/config/initial.cfg @@ -0,0 +1,34 @@ +# Configuration variables: +# STAGE1_FILE, STAGE2_FILE + +set STAGE1_FILE firmware/spl_stage1.bin +set STAGE2_FILE firmware/spl_stage2_usb.bin + +set EXTCLK 12 # Define the external crystal in MHz +set CPUSPEED 252 # Define the PLL output frequency +set PHMDIV 3 # Define the frequency divider ratio of PLL=CCLK:PCLK=HCLK=MCLK +set BAUDRATE 57600 # Define the uart baudrate +set USEUART 0 # UART number + +set SDRAM_BUSWIDTH 16 # The bus width of the SDRAM in bits (16|32) +set SDRAM_BANKS 4 # The bank number (2|4) +set SDRAM_ROWADDR 13 # Row address width in bits (11-13) +set SDRAM_COLADDR 9 # Column address width in bits (8-12) +set SDRAM_ISMOBILE 0 # Define whether SDRAM is mobile SDRAM (only or Jz4750), 1: yes 0: no +set SDRAM_ISBUSSHARE 1 # Define whether SDRAM bus share with NAND 1:shared 0:unshared + +set NAND_BUSWIDTH 8 # The width of the NAND flash chip in bits (8|16|32) +set NAND_ROWCYCLES 3 # The row address cycles (2|3) +set NAND_PAGESIZE 2048 # The page size of the NAND chip in bytes(512|2048|4096) +set NAND_PAGEPERBLOCK 128 # The page number per block +set NAND_FORCEERASE 1 # The force to erase flag (0|1) +set NAND_OOBSIZE 64 # OOB size in byte +set NAND_ECCPOS 3 # Specify the ECC offset inside the oob data (0-[oobsize-1]) +set NAND_BADBLOCKPOS 0 # Specify the badblock flag offset inside the oob (0-[oobsize-1]) +set NAND_BADBLOCKPAGE 0 # Specify the page number of badblock flag inside a block(0-[PAGEPERBLOCK-1]) +set NAND_PLANENUM 1 # The planes number of target nand flash +set NAND_BCHBIT 8 # Specify the hardware BCH algorithm for 4750 (4|8) +set NAND_WPPIN 0 # Specify the write protect pin number +set NAND_BLOCKPERCHIP 4096 # Specify the block number per chip,0 means ignore + +rebuildcfg diff --git a/jzboot/firmware/spl_stage1.bin b/jzboot/firmware/spl_stage1.bin new file mode 100644 index 0000000..cfdcd02 Binary files /dev/null and b/jzboot/firmware/spl_stage1.bin differ diff --git a/jzboot/firmware/spl_stage2_usb.bin b/jzboot/firmware/spl_stage2_usb.bin new file mode 100644 index 0000000..8f11c6f Binary files /dev/null and b/jzboot/firmware/spl_stage2_usb.bin differ diff --git a/jzboot/include/app_config.h b/jzboot/include/app_config.h new file mode 100644 index 0000000..dd4307b --- /dev/null +++ b/jzboot/include/app_config.h @@ -0,0 +1,28 @@ +/* + * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. + * Copyright (C) 2010 Sergey Gridassov + * + * 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 __CONFIG__H__ +#define __CONFIG__H__ + +char *cfg_getenv(const char *variable); +void cfg_setenv(const char *variable, const char *newval); +void cfg_unsetenv(const char *variable); + +extern char **cfg_environ; + +#endif diff --git a/jzboot/include/debug.h b/jzboot/include/debug.h new file mode 100644 index 0000000..c5eabbd --- /dev/null +++ b/jzboot/include/debug.h @@ -0,0 +1,34 @@ +/* + * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. + * Copyright (C) 2010 Sergey Gridassov + * + * 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 __DEBUG__H__ +#define __DEBUG__H__ + +void set_debug_level(int level); +int get_debug_level(); +void hexdump(const void *data, size_t size); + +void debug(int level, const char *fmt, ...); + +#define LEVEL_SILENT 0 +#define LEVEL_ERROR 1 +#define LEVEL_WARNING 2 +#define LEVEL_INFO 3 +#define LEVEL_DEBUG 4 + +#endif diff --git a/jzboot/include/devmgr.h b/jzboot/include/devmgr.h new file mode 100644 index 0000000..49a92c4 --- /dev/null +++ b/jzboot/include/devmgr.h @@ -0,0 +1,34 @@ +/* + * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. + * Copyright (C) 2010 Sergey Gridassov + * + * 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 __DEVMGR__H__ +#define __DEVMGR__H__ + +#include + +#define INTERFACE_BOOT 0 +#define ENDPOINT_OUT 0x01 +#define ENDPOINT_IN 0x81 + +int is_ingenic(uint16_t vid, uint16_t pid); + +void add_device(uint16_t vid, uint16_t pid, void *data); +void enum_devices(void (*handler)(int idx, uint16_t vid, uint16_t pid, void *data)); +void *get_device(int idx); + +#endif diff --git a/jzboot/include/elf.h b/jzboot/include/elf.h new file mode 100644 index 0000000..591047c --- /dev/null +++ b/jzboot/include/elf.h @@ -0,0 +1,78 @@ +#ifndef __ELF__H__ +#define __ELF__H__ + +#include + +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Word; +typedef uint32_t Elf32_Addr; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; + +#define EI_NIDENT 16 +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_PAD 7 + +#define ELFMAG0 0x7F +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' + +#define ELFCLASSNONE 0 +#define ELFCLASS32 1 +#define ELFCLASS64 2 + +#define ELFDATANONE 0 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 + +#define EM_MIPS 8 + +#define EV_NONE 0 +#define EV_CURRENT 1 + +#define PT_NULL 0 +#define PT_LOAD 1 + +typedef struct { + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; + +typedef struct { + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +#endif + diff --git a/jzboot/include/elfldr.h b/jzboot/include/elfldr.h new file mode 100644 index 0000000..b4a0b9a --- /dev/null +++ b/jzboot/include/elfldr.h @@ -0,0 +1,10 @@ +#ifndef __ELFLDR__H__ +#define __ELFLDR__H__ + +int load_elf(void *ingenic, + const char *filename, + const char *args, + const char *initrd); + +#endif + diff --git a/jzboot/include/ingenic.h b/jzboot/include/ingenic.h new file mode 100644 index 0000000..8c09d5f --- /dev/null +++ b/jzboot/include/ingenic.h @@ -0,0 +1,149 @@ +/* This file is based on code by Ingenic Semiconductor Co., Ltd. */ + +#ifndef __INGENIC__H__ +#define __INGENIC__H__ + +#include + +#define VR_GET_CPU_INFO 0x00 +#define VR_SET_DATA_ADDRESS 0x01 +#define VR_SET_DATA_LENGTH 0x02 +#define VR_FLUSH_CACHES 0x03 +#define VR_PROGRAM_START1 0x04 +#define VR_PROGRAM_START2 0x05 +#define VR_NOR_OPS 0x06 +#define VR_NAND_OPS 0x07 +#define VR_SDRAM_OPS 0x08 +#define VR_CONFIGRATION 0x09 +#define VR_GET_NUM 0x0a + +#define CMDSET_SPL 1 +#define CMDSET_USBBOOT 2 + +#define INGENIC_STAGE1 1 +#define INGENIC_STAGE2 2 + +#define STAGE1_DEBUG_BOOT 0 +#define STAGE1_DEBUG_MEMTEST 1 +#define STAGE1_DEBUG_GPIO_SET 2 +#define STAGE1_DEBUG_GPIO_CLEAR 3 + +#define STAGE1_BASE 0x2000 +#define STAGE2_CODESIZE 0x400000 +#define SDRAM_BASE 0x80000000 + +#define STAGE2_IOBUF (2048 * 128) + +#define DS_flash_info 0 +#define DS_hand 1 + +#define SDRAM_LOAD 0 + +#define NAND_QUERY 0 +#define NAND_INIT 1 +#define NAND_MARK_BAD 2 +#define NAND_READ_OOB 3 +#define NAND_READ_RAW 4 +#define NAND_ERASE 5 +#define NAND_READ 6 +#define NAND_PROGRAM 7 +#define NAND_READ_TO_RAM 8 + +#define OOB_ECC 0 +#define OOB_NO_ECC 1 +#define NO_OOB 2 +#define NAND_RAW (1 << 7) + +#define PROGRESS_INIT 0 +#define PROGRESS_UPDATE 1 +#define PROGRESS_FINI 2 + +typedef struct { + /* debug args */ + uint8_t debug_ops; + uint8_t pin_num; + uint32_t start; + uint32_t size; +} __attribute__((packed)) ingenic_stage1_debug_t; + +typedef struct { + /* CPU ID */ + uint32_t cpu_id; + + /* PLL args */ + uint8_t ext_clk; + uint8_t cpu_speed; + uint8_t phm_div; + uint8_t use_uart; + uint32_t baudrate; + + /* SDRAM args */ + uint8_t bus_width; + uint8_t bank_num; + uint8_t row_addr; + uint8_t col_addr; + uint8_t is_mobile; + uint8_t is_busshare; + + ingenic_stage1_debug_t debug; +} __attribute__((packed)) firmware_config_t; + +typedef struct { + /* nand flash info */ + uint32_t cpuid; /* cpu type */ + uint32_t nand_bw; /* bus width */ + uint32_t nand_rc; /* row cycle */ + uint32_t nand_ps; /* page size */ + uint32_t nand_ppb; /* page number per block */ + uint32_t nand_force_erase; + uint32_t nand_pn; /* page number in total */ + uint32_t nand_os; /* oob size */ + uint32_t nand_eccpos; + uint32_t nand_bbpage; + uint32_t nand_bbpos; + uint32_t nand_plane; + uint32_t nand_bchbit; + uint32_t nand_wppin; + uint32_t nand_bpc; /* block number per chip */ +} nand_config_t; + +typedef struct { + uint8_t vid; + uint8_t pid; + uint8_t chip; + uint8_t page; + uint8_t plane; +} nand_info_t; + + +typedef struct { + void (*cmdset_change)(uint32_t cmdset, void *arg); + void (*progress)(int action, int value, int max, void *arg); +} ingenic_callbacks_t; + +void *ingenic_open(void *usb_hndl); +void ingenic_close(void *hndl); +void ingenic_set_callbacks(void *hndl, const ingenic_callbacks_t *callbacks, void *arg); + +int ingenic_redetect(void *hndl); +int ingenic_cmdset(void *hndl); +int ingenic_type(void *hndl); +uint32_t ingenic_sdram_size(void *hndl); + +int ingenic_rebuild(void *hndl); +int ingenic_loadstage(void *hndl, int id, const char *filename); +int ingenic_stage1_debugop(void *device, const char *filename, uint32_t op, uint32_t pin, uint32_t base, uint32_t size); +int ingenic_memtest(void *hndl, const char *filename, uint32_t base, uint32_t size, uint32_t *fail); + +int ingenic_configure_stage2(void *hndl); +int ingenic_load_sdram(void *hndl, void *data, uint32_t base, uint32_t size); +int ingenic_load_sdram_file(void *hndl, uint32_t base, const char *filename); +int ingenic_go(void *hndl, uint32_t address); + +int ingenic_query_nand(void *hndl, int cs, nand_info_t *info); +int ingenic_dump_nand(void *hndl, int cs, int start, int pages, int type, const char *filename); +int ingenic_program_nand(void *hndl, int cs, int start, int type, const char *filename); +int ingenic_erase_nand(void *hndl, int cs, int start, int blocks); +int ingenic_load_nand(void *hndl, int cs, int start, int pages, uint32_t base); + +#endif diff --git a/jzboot/include/shell.h b/jzboot/include/shell.h new file mode 100644 index 0000000..f9255a4 --- /dev/null +++ b/jzboot/include/shell.h @@ -0,0 +1,49 @@ +/* + * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. + * Copyright (C) 2010 Sergey Gridassov + * + * 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 __SHELL__H__ +#define __SHELL__H__ + +#ifndef SHELL_INTERNALS +typedef void shell_context_t; +#endif + +typedef struct shell_command { + const char *cmd; + const char *description; + int (*handler)(shell_context_t *ctx, int argc, char *argv[]); + const char *args; +} shell_command_t; + +shell_context_t *shell_init(void *ingenic); +void shell_fini(shell_context_t *context); + +void shell_interactive(shell_context_t *ctx); +int shell_source(shell_context_t *ctx, const char *filename); +int shell_execute(shell_context_t *ctx, const char *input); +void *shell_device(shell_context_t *ctx); +int shell_run(shell_context_t *ctx, int argc, char *argv[]); + +void shell_exit(shell_context_t *ctx, int val); +int shell_enumerate_commands(shell_context_t *ctx, int (*callback)(shell_context_t *ctx, const shell_command_t *cmd, void *arg), void *arg); + +extern const shell_command_t spl_cmdset[]; +extern const shell_command_t usbboot_cmdset[]; +extern const shell_command_t builtin_cmdset[]; + +#endif diff --git a/jzboot/include/shell_internal.h b/jzboot/include/shell_internal.h new file mode 100644 index 0000000..0378e26 --- /dev/null +++ b/jzboot/include/shell_internal.h @@ -0,0 +1,63 @@ +/* + * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. + * Copyright (C) 2010 Sergey Gridassov + * + * 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 __SHELL_INTERNAL__H__ +#define __SHELL_INTERNAL__H__ + +#define SHELL_INTERNALS +#define STATE_WANTSTR 0 +#define STATE_WANTSPACE 1 + +#define TOK_SEPARATOR 1 +#define TOK_STRING 2 +#define TOK_SPACE 3 +#define TOK_COMMENT 4 + +typedef struct { + void *device; + char linebuf[512]; + char *strval; + char *line; + const struct shell_command *set_cmds; + int shell_exit; + int prev_progress; +} shell_context_t; + + +typedef struct { + int argc; + char **argv; +} shell_run_data_t; + +int shell_pull(shell_context_t *ctx, char *buf, int maxlen); + +#ifndef FLEX_SCANNER +typedef void *yyscan_t; +int yylex_init(yyscan_t *ptr_yy_globals); +int yylex_init_extra(shell_context_t *user_defined, yyscan_t *ptr_yy_globals); +int yylex(yyscan_t yyscanner) ; +int yylex_destroy (yyscan_t yyscanner) ; +#else +#define YY_EXTRA_TYPE shell_context_t * +#define YY_INPUT(buf, result, max_size) result = shell_pull(yyextra, buf, max_size); +#endif + +#include "shell.h" + +#endif + diff --git a/jzboot/include/usbdev.h b/jzboot/include/usbdev.h new file mode 100644 index 0000000..6bc24d1 --- /dev/null +++ b/jzboot/include/usbdev.h @@ -0,0 +1,38 @@ +/* + * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. + * Copyright (C) 2010 Sergey Gridassov , + * Peter Zotov + * + * 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 __USBDEV__H__ +#define __USBDEV__H__ + +#include + +int usbdev_init(); +void usbdev_fini(); + +#define USBDEV_FROMDEV 0 +#define USBDEV_TODEV 1 + +int usbdev_enumerate(); +void *usbdev_open(void *dev); +void usbdev_close(void *hndl); +int usbdev_vendor(void *hndl, int direction, uint8_t req, uint16_t value, uint16_t index, void *data, uint16_t size); +int usbdev_sendbulk(void *hndl, void *data, int size); +int usbdev_recvbulk(void *hndl, void *data, int size); + +#endif diff --git a/jzboot/script/dump_minios.scr b/jzboot/script/dump_minios.scr new file mode 100644 index 0000000..d5a027a --- /dev/null +++ b/jzboot/script/dump_minios.scr @@ -0,0 +1,25 @@ +echo "Dumping script" +nquery 0 + +#set NAND_RAW 1 +set NAND_ECCPOS 3 +rebuildcfg +boot + +echo "Configured for bootloader IO!" + +ndump_oob 0 0 128 "dump/nand.bin" + +set NAND_RAW +set NAND_ECCPOS 8 +rebuildcfg +boot + +echo "Configuration restored" + +ndump 0 128 66 "dump/loader.bin" +ndump 0 256 1 "dump/def_boot.bin" +ndump 0 512 3061 "dump/img_boot.bin" +ndump 0 8192 8192 "dump/minios.bin" +ndump 0 32768 32768 "dump/res.bin" + diff --git a/jzboot/script/ecc_boot.scr b/jzboot/script/ecc_boot.scr new file mode 100644 index 0000000..a895357 --- /dev/null +++ b/jzboot/script/ecc_boot.scr @@ -0,0 +1,3 @@ +set NAND_ECCPOS 3 +rebuildcfg +boot diff --git a/jzboot/script/ecc_normal.scr b/jzboot/script/ecc_normal.scr new file mode 100644 index 0000000..7f54054 --- /dev/null +++ b/jzboot/script/ecc_normal.scr @@ -0,0 +1,3 @@ +set NAND_ECCPOS 8 +rebuildcfg +boot diff --git a/jzboot/script/flash_xz0032_linux.scr b/jzboot/script/flash_xz0032_linux.scr new file mode 100644 index 0000000..0c55582 --- /dev/null +++ b/jzboot/script/flash_xz0032_linux.scr @@ -0,0 +1,27 @@ +#11.12.2010 --rzk +# orig from http://pastie.org/1368585 +# fixes by whitequark + +echo "---- Linux kernel+loader+rootfs flashing script ----" + +echo "Including initial config for 4750 XZ0032 board" +source config/boot.cfg +echo "jzboot successfully configured for XZ0032" + +echo "Erasing all flash" +nerase 0 0 4096 +echo "Erased all flash" + +echo "Flashing loader" +nprogram 0 0 u-boot-nand.bin +echo "Flashed loader" + +echo "Flashing kernel" +nprogram 0 512 uImage +echo "Flashed kernel" + +echo "Flashing rootfs" +nprogram_oob 0 8192 rootfs.ubifs +echo "Flashed rootfs" + +echo "---- All done ----" diff --git a/jzboot/script/restore_minios.scr b/jzboot/script/restore_minios.scr new file mode 100644 index 0000000..cb8f369 --- /dev/null +++ b/jzboot/script/restore_minios.scr @@ -0,0 +1,42 @@ +#11.12.2010 --rzk +# orig from http://pastie.org/1368586 +# fixes by whitequark + +echo "---- Restore MINIOS script ----" +echo "Including initial config for 4750 XZ0032 board" +source config/boot.cfg +echo "jzboot successfully configured for XZ0032" + +echo "Erasing all flash" +nerase 0 0 4096 +echo "Erased all flash" + +echo "Configuring for bootloader IO" +source script/ecc_boot.scr +echo "Configured for bootloader IO" + +echo "Flashing SPL (nand.bin)" +nprogram 0 0 nand.bin +echo "Flashed SPL (nand.bin)" + +echo "Configuring for standard IO" +source script/ecc_normal.scr +echo "Configured for standard IO" + +echo "Flashing loader.bin" +nprogram 0 128 dump/loader.bin +echo "Flashed loader.bin" +echo "Flashing def_boot.bin" +nprogram 0 256 dump/def_boot.bin +echo "Flashed def_boot.bin" +echo "Flashing img_boot.bin" +nprogram 0 512 dump/img_boot.bin +echo "Flashed img_boot.bin" +echo "Flashing minios.bin" +nprogram 0 8192 dump/minios.bin +echo "Flashed minios.bin" +echo "Flashing res.bin" +nprogram 0 32768 dump/res.bin +echo "Flashed res.bin" + +echo "---- All done ----" diff --git a/jzboot/src/Makefile.am b/jzboot/src/Makefile.am new file mode 100644 index 0000000..cee8e39 --- /dev/null +++ b/jzboot/src/Makefile.am @@ -0,0 +1,6 @@ +AM_CFLAGS = --std=gnu99 -Wall -I../include + +bin_PROGRAMS = jzboot +jzboot_SOURCES = debug.c devmgr.c ingenic.c main.c shell_lex.c \ + usbdev.c shell.c shell_builtins.c config.c spl_cmdset.c \ + usbboot_cmdset.c elfldr.c \ No newline at end of file diff --git a/jzboot/src/config.c b/jzboot/src/config.c new file mode 100644 index 0000000..d58294c --- /dev/null +++ b/jzboot/src/config.c @@ -0,0 +1,110 @@ +/* + * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. + * Copyright (C) 2010 Sergey Gridassov + * + * 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 "app_config.h" +#include "debug.h" + +char **cfg_environ = NULL; + +static int env_size() { + int size = 0; + + if(cfg_environ == NULL) + return 0; + + for(int i = 0; cfg_environ[i] != NULL; i++) + size++; + + return size; +} + +char *cfg_getenv(const char *variable) { + if(cfg_environ == NULL) + return NULL; + + size_t len = strlen(variable); + + for(int i = 0; cfg_environ[i] != NULL; i++) { + char *str = cfg_environ[i], *sep = strchr(str, '='); + + if(sep - str == len && memcmp(str, variable, len) == 0) { + return sep + 1; + } + } + + return NULL; +} + +void cfg_unsetenv(const char *variable) { + int size = env_size(); + + if(size == 0) + return; + + size_t len = strlen(variable); + + for(int i = 0; cfg_environ[i] != NULL; i++) { + char *str = cfg_environ[i], *sep = strchr(str, '='); + + if(sep - str == len && memcmp(str, variable, len) == 0) { + free(str); + + memcpy(cfg_environ + i, cfg_environ + i + 1, sizeof(char *) * (size - i)); + + cfg_environ = realloc(cfg_environ, sizeof(char *) * size); + + return; + } + } +} + +void cfg_setenv(const char *variable, const char *newval) { + int size = env_size(); + + size_t len = strlen(variable); + + char *newstr = malloc(len + 1 + strlen(newval) + 1); + + strcpy(newstr, variable); + strcat(newstr, "="); + strcat(newstr, newval); + + if(size > 0) { + for(int i = 0; cfg_environ[i] != NULL; i++) { + char *str = cfg_environ[i], *sep = strchr(str, '='); + + if(sep - str == len && memcmp(str, variable, len) == 0) { + free(str); + + cfg_environ[i] = newstr; + + return; + } + } + } + + cfg_environ = realloc(cfg_environ, sizeof(char *) * (size + 2)); + + cfg_environ[size] = newstr; + cfg_environ[size + 1] = NULL; +} diff --git a/jzboot/src/debug.c b/jzboot/src/debug.c new file mode 100644 index 0000000..d9fa13b --- /dev/null +++ b/jzboot/src/debug.c @@ -0,0 +1,82 @@ +/* + * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. + * Copyright (C) 2010 Sergey Gridassov + * + * 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 "debug.h" + +static int debug_level = LEVEL_ERROR; + +void set_debug_level(int level) { + debug_level = level; +} + +int get_debug_level() { + return debug_level; +} + +void debug(int level, const char *fmt, ...) { + va_list list; + + va_start(list, fmt); + + if(level <= debug_level) { + if(level <= LEVEL_ERROR) + vfprintf(stderr, fmt, list); + else + vprintf(fmt, list); + } + + va_end(list); +} + +void hexdump(const void *data, size_t size) { + const unsigned char *bytes = data; + + for(int i = 0; i < size; i+= 16) { + debug(LEVEL_DEBUG, "%04X ", i); + + int chunk_size = size - i; + if(chunk_size > 16) + chunk_size = 16; + + for(int j = 0; j < chunk_size; j++) { + debug(LEVEL_DEBUG, "%02X ", bytes[i + j]); + + if(j == 7) + debug(LEVEL_DEBUG, " "); + } + + for(int j = 0; j < 16 - chunk_size; j++) { + debug(LEVEL_DEBUG, " "); + + if(j == 8) + debug(LEVEL_DEBUG, " "); + } + + debug(LEVEL_DEBUG, "|"); + + for(int j = 0; j < chunk_size; j++) { + debug(LEVEL_DEBUG, "%c", isprint(bytes[i + j]) ? bytes[i + j] : '.'); + } + + debug(LEVEL_DEBUG, "|\n"); + } +} + diff --git a/jzboot/src/devmgr.c b/jzboot/src/devmgr.c new file mode 100644 index 0000000..6e83ac4 --- /dev/null +++ b/jzboot/src/devmgr.c @@ -0,0 +1,77 @@ +/* + * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. + * Copyright (C) 2010 Sergey Gridassov + * + * 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 "devmgr.h" +#include "debug.h" + +typedef struct device { + struct device *next; + uint16_t vid; + uint16_t pid; + void *data; +} usb_device_t; + +static const struct { + uint16_t vid; + uint16_t pid; +} devices[] = { + { 0x601a, 0x4740 }, + { 0x601a, 0x4750 }, + { 0x601a, 0x4760 }, + { 0, 0 } +}; + +static usb_device_t *list = NULL; + +int is_ingenic(uint16_t vid, uint16_t pid) { + for(int i = 0; devices[i].vid != 0; i++) + if(devices[i].vid == vid && devices[i].pid == pid) + return 1; + + return 0; +} + +void add_device(uint16_t vid, uint16_t pid, void *data) { + usb_device_t *newdev = malloc(sizeof(usb_device_t)); + + newdev->next = list; + newdev->vid = vid; + newdev->pid = pid; + newdev->data = data; + + list = newdev; + + debug(LEVEL_DEBUG, "Device manager: registered %04hX:%04hX with data %p\n", vid, pid, data); +} + +void enum_devices(void (*handler)(int idx, uint16_t vid, uint16_t pid, void *data)) { + int idx = 0; + + for(usb_device_t *dev = list; dev; dev = dev->next) + handler(idx++, dev->vid, dev->pid, dev->data); +} + +void *get_device(int idx) { + for(usb_device_t *dev = list; dev; dev = dev->next) + if(idx-- == 0) + return dev->data; + + return NULL; +} diff --git a/jzboot/src/elfldr.c b/jzboot/src/elfldr.c new file mode 100644 index 0000000..fc72573 --- /dev/null +++ b/jzboot/src/elfldr.c @@ -0,0 +1,318 @@ +#include +#include +#include +#include +#include +#include "debug.h" +#include "elfldr.h" +#include "elf.h" +#include "ingenic.h" + +#define max(a, b) ((a) > (b) ? (a) : (b)) +#define ALIGN(a) ((a + 4095) & ~4095) + +#define TRAMP_ARGC 0 // command line argument count +#define TRAMP_ARGV 1 // command line argument array +#define TRAMP_ARG2 2 +#define TRAMP_ARG3 3 +#define TRAMP_ENTRY 4 // Kernel entry point + +static const uint32_t trampoline_template[] = { + 0x3c04ffff, // lui a0, 0xffff + 0x3484ffff, // ori a0,a0,0xffff + + 0x3c05ffff, // lui a1, 0xffff + 0x34a5ffff, // ori a1,a1,0xffff + + 0x3c06ffff, // lui a2, 0xffff + 0x34c6ffff, // ori a2,a2,0xffff + + 0x3c07ffff, // lui a3, 0xffff + 0x34e7ffff, // ori a3,a3,0xffff + + 0x3c08ffff, // lui t0, 0xffff + 0x3508ffff, // ori t0,t0,0xffff + 0x01000008, // jr t0 + 0x00000000, // nop +}; + +static const unsigned char valid_ident[EI_PAD] = { + [EI_MAG0] = ELFMAG0, + [EI_MAG1] = ELFMAG1, + [EI_MAG2] = ELFMAG2, + [EI_MAG3] = ELFMAG3, + [EI_CLASS] = ELFCLASS32, + [EI_DATA] = ELFDATA2LSB, + [EI_VERSION] = EV_CURRENT +}; + +static int load_segment(void *ingenic, void *data, uint32_t base, uint32_t filesz, uint32_t memsz) { + uint32_t end = base + memsz, tail = memsz - filesz; + int ret = 0; + + printf("Loading segment: base 0x%08X, file 0x%08X, mem 0x%08X\n", base, filesz, memsz); + + if(end > ingenic_sdram_size(ingenic) + SDRAM_BASE - STAGE2_CODESIZE) { + fputs(" Segment doesn't fit into SDRAM\n", stderr); + + return -1; + } + + if(filesz && ingenic_load_sdram(ingenic, data, base, filesz) == -1) + return -1; + + if(tail) { + char *dummy_data = malloc(tail); + + if(dummy_data == NULL) + return -1; + + memset(dummy_data, 0, tail); + + ret = ingenic_load_sdram(ingenic, dummy_data, base + filesz, tail); + + free(dummy_data); + } + + return ret; +} + +static int load_elf_image(FILE *elf, void *ingenic, uint32_t *entry, uint32_t *end) { + Elf32_Ehdr ehdr; + Elf32_Phdr phdr; + int i, ret; + char *data; + + if(fread(&ehdr, 1, sizeof(Elf32_Ehdr), elf) != sizeof(Elf32_Ehdr)) { + if(feof(elf)) + errno = EINVAL; + + return -1; + } + + *entry = ehdr.e_entry; + + if(memcmp(ehdr.e_ident, valid_ident, EI_PAD) != 0 || ehdr.e_type != ET_EXEC || ehdr.e_machine != EM_MIPS || ehdr.e_version != EV_CURRENT + || ehdr.e_phoff == 0 || ehdr.e_phentsize != sizeof(Elf32_Phdr)) { + + fputs("Bad ELF identification\n", stderr); + + errno = EINVAL; + + return -1; + } + + fseek(elf, ehdr.e_phoff, SEEK_SET); + + *end = 0; + + for(i = 0; i < ehdr.e_phnum; i++) { + if(fread(&phdr, 1, sizeof(Elf32_Phdr), elf) != sizeof(Elf32_Phdr)) { + if(feof(elf)) + errno = EINVAL; + + return -1; + } + + if(phdr.p_type == PT_LOAD) { + data = malloc(phdr.p_filesz); + + if(data == NULL) + return -1; + + long save = ftell(elf); + fseek(elf, phdr.p_offset, SEEK_SET); + ret = fread(data, 1, phdr.p_filesz, elf); + fseek(elf, save, SEEK_SET); + + if(ret != phdr.p_filesz) { + free(data); + + if(feof(elf)) + errno = EINVAL; + + return -1; + } + + ret = load_segment(ingenic, data, phdr.p_paddr, phdr.p_filesz, phdr.p_memsz); + + free(data); + + if(ret == -1) + return -1; + + *end = max(phdr.p_paddr + phdr.p_memsz, *end); + } + } + + return 0; +} + + +static void trampoline_set(uint32_t *trampoline, int index, + uint32_t value) { + index *= 2; + + trampoline[index] = (trampoline[index] & 0xFFFF0000) | ((value & 0xFFFF0000) >> 16); + trampoline[index + 1] = (trampoline[index + 1] & 0xFFFF0000) | (value & 0x0000FFFF); +} + +static int load_args(void *ingenic, uint32_t base, const char *filename, + const char *const *args, int *pargc, uint32_t *end) { + + size_t total_len = 0; + int argc = 0; + + for(int i = 0; args[i]; i++) { + size_t len = strlen(args[i]); + total_len += len + 1; + + for(int j = 0; j < len; j++) + if(args[i][j] == ' ') + argc++; + + argc++; + } + + *pargc = argc; + *end = base + total_len + sizeof(uint32_t) * argc; + + uint32_t *buf = malloc(sizeof(uint32_t) * argc + total_len); + if(buf == NULL) + return -1; + + char *cmdline = (char *)(buf + argc); + size_t off = 0; + + for(int i = 0; args[i]; i++) { + size_t len = strlen(args[i]); + memcpy(cmdline + off, args[i], len + 1); + + if(args[i + 1]) + cmdline[off + len] = ' '; + + off += len + 1; + } + + printf("Compiled cmdline: '%s'\n", cmdline); + + uint32_t offset = 0; + char *ptr = cmdline; + + for(int i = 0; i < argc; i++) { + buf[i] = base + argc * sizeof(uint32_t) + offset; + + ptr = strchr(ptr, ' '); + + if(ptr == NULL) + break; + + *ptr++ = 0; + offset = ptr - cmdline; + } + + int ret = load_segment(ingenic, + buf, + base, + sizeof(uint32_t) * argc + total_len, + sizeof(uint32_t) * argc + total_len); + free(buf); + + return ret; +} + +int load_elf(void *ingenic, + const char *filename, + const char *args, + const char *initrd) { + + uint32_t entry, end, trampoline_base, args_base; + uint32_t initrd_base, initrd_size; + + int argc; + const char *all_args[4] = { filename, args, NULL, NULL }; + char initrd_args[64]; + + printf( + "Loading kernel %s:\n" + " Command line: '%s'\n", + filename, + args + ); + + FILE *elf = fopen(filename, "rb"); + + if(elf == NULL) + return -1; + + int ret = load_elf_image(elf, ingenic, &entry, &end); + + fclose(elf); + + if(ret == -1) + return -1; + + if(initrd) { + struct stat statbuf; + + initrd_base = ALIGN(end); + + if(stat(initrd, &statbuf) == -1) + return -1; + + initrd_size = statbuf.st_size; + + printf("Loading initrd to 0x%08X, size 0x%08X\n", + initrd_base, initrd_size); + + + end = initrd_base + initrd_size; + + if(end > ingenic_sdram_size(ingenic) + SDRAM_BASE - STAGE2_CODESIZE) { + fputs(" Initrd doesn't fit into SDRAM\n", stderr); + + return -1; + } + + if(ingenic_load_sdram_file(ingenic, initrd_base, initrd) == -1) + return -1; + + snprintf(initrd_args, sizeof(initrd_args), + "rd_start=0x%08X rd_size=0x%08X", + initrd_base, initrd_size); + + all_args[2] = initrd_args; + } + + args_base = ALIGN(end); + + if(load_args(ingenic, args_base, filename, all_args, &argc, &end) == -1) + return -1; + + trampoline_base = ALIGN(end); + end = trampoline_base + sizeof(trampoline_template); + + uint32_t *trampoline = malloc(sizeof(trampoline_template)); + if(trampoline == NULL) + return -1; + + memcpy(trampoline, trampoline_template, sizeof(trampoline_template)); + trampoline_set(trampoline, TRAMP_ARGC, argc); + trampoline_set(trampoline, TRAMP_ARGV, args_base); + trampoline_set(trampoline, TRAMP_ARG2, 0); + trampoline_set(trampoline, TRAMP_ARG3, 0); + trampoline_set(trampoline, TRAMP_ENTRY, entry); + + ret = load_segment(ingenic, trampoline, trampoline_base, sizeof(trampoline_template), sizeof(trampoline_template)); + + free(trampoline); + + if(ret == -1) + return -1; + + printf("Image end: 0x%08X, entry: 0x%08X\n", end, entry); + + //return 0; + return ingenic_go(ingenic, trampoline_base); +} + diff --git a/jzboot/src/ingenic.c b/jzboot/src/ingenic.c new file mode 100644 index 0000000..2be21ed --- /dev/null +++ b/jzboot/src/ingenic.c @@ -0,0 +1,733 @@ +/* + * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. + * Copyright (C) 2010 Sergey Gridassov , + * Peter Zotov + * + * 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 "ingenic.h" +#include "usbdev.h" +#include "debug.h" +#include "app_config.h" + +#define HANDLE ingenic_handle_t *handle = hndl +#define BUILDTYPE(cmdset, id) (((cmdset) << 16) | (0x##id & 0xFFFF)) +#define CPUID(id) ((id) & 0xFFFF) +#define CMDSET(id) (((id) & 0xFFFF0000) >> 16) + +#define CFGOPT(name, var, exp) { \ + char *str = cfg_getenv(name); \ + if(str == NULL) { \ + debug(LEVEL_ERROR, "%s is not set\n", name); errno = EINVAL; return -1; }; \ + int v = atoi(str); \ + if(!(exp)) { debug(LEVEL_ERROR, "%s must be in %s\n", name, #exp); return -1; }; \ + var = v; \ + } + +#define NOPT(name, var, exp) { \ + char *str = cfg_getenv("NAND_" name); \ + if(str == NULL) { debug(LEVEL_ERROR, "%s is not set\n", "NAND_" name); errno = EINVAL; return -1; }; \ + int v = atoi(str); \ + if(!(exp)) { debug(LEVEL_ERROR, "%s must be in %s\n", "NAND_" name, #exp); return -1; }; \ + var = v; \ +} + +#define CALLBACK(function, ...) if(handle->callbacks && handle->callbacks->function) handle->callbacks->function(__VA_ARGS__, handle->callbacks_data) + +typedef struct { + void *usb; + uint32_t type; + uint32_t total_sdram_size; + + const ingenic_callbacks_t *callbacks; + void *callbacks_data; + + firmware_config_t cfg; + nand_config_t nand; +} ingenic_handle_t; + +static const struct { + const char * const magic; + uint32_t id; +} magic_list[] = { + { "JZ4740V1", BUILDTYPE(CMDSET_SPL, 4740) }, + { "JZ4750V1", BUILDTYPE(CMDSET_SPL, 4750) }, + { "JZ4760V1", BUILDTYPE(CMDSET_SPL, 4760) }, + + { "Boot4740", BUILDTYPE(CMDSET_USBBOOT, 4740) }, + { "Boot4750", BUILDTYPE(CMDSET_USBBOOT, 4750) }, + { "Boot4760", BUILDTYPE(CMDSET_USBBOOT, 4760) }, + + { NULL, 0 } +}; + +static uint32_t ingenic_probe(void *usb_hndl) { + char magic[9]; + + if(usbdev_vendor(usb_hndl, USBDEV_FROMDEV, VR_GET_CPU_INFO, 0, 0, magic, 8) == -1) + return 0; + + magic[8] = 0; + + for(int i = 0; magic_list[i].magic != NULL; i++) + if(strcmp(magic_list[i].magic, magic) == 0) + return magic_list[i].id; + + debug(LEVEL_ERROR, "Unknown CPU: '%s'\n", magic); + errno = EINVAL; + return 0; +} + +void *ingenic_open(void *usb_hndl) { + uint32_t type = ingenic_probe(usb_hndl); + + if(type == 0) + return NULL; + + ingenic_handle_t *ret = malloc(sizeof(ingenic_handle_t)); + ret->usb = usb_hndl; + ret->type = type; + ret->callbacks = NULL; + + return ret; +} + +int ingenic_redetect(void *hndl) { + HANDLE; + + uint32_t type = ingenic_probe(handle->usb); + + if(type == 0) + return -1; + + uint32_t prev = handle->type; + + handle->type = type; + + if(CMDSET(prev) != CMDSET(type)) { + CALLBACK(cmdset_change, CMDSET(type)); + } + + return 0; +} + +void ingenic_set_callbacks(void *hndl, const ingenic_callbacks_t *callbacks, void *arg) { + HANDLE; + + handle->callbacks = callbacks; + handle->callbacks_data = arg; +} + +int ingenic_cmdset(void *hndl) { + HANDLE; + + return CMDSET(handle->type); +} + +int ingenic_type(void *hndl) { + HANDLE; + + return CPUID(handle->type); +} + +void ingenic_close(void *hndl) { + HANDLE; + + free(handle); +} + +int ingenic_rebuild(void *hndl) { + HANDLE; + unsigned int cpu_speed; /* the uint8_t in handle structure won't do for values > 255 */ + + handle->cfg.cpu_id = CPUID(handle->type); + + CFGOPT("EXTCLK", handle->cfg.ext_clk, v <= 27 && v >= 12); + CFGOPT("CPUSPEED", cpu_speed, (v % 12) == 0); + handle->cfg.cpu_speed = cpu_speed / handle->cfg.ext_clk; + CFGOPT("PHMDIV", handle->cfg.phm_div, v <= 32 && v >= 2); + CFGOPT("USEUART", handle->cfg.use_uart, 1); + CFGOPT("BAUDRATE", handle->cfg.baudrate, 1); + + CFGOPT("SDRAM_BUSWIDTH", handle->cfg.bus_width, (v == 16) || (v == 32)); + handle->cfg.bus_width = handle->cfg.bus_width == 16 ? 1 : 0; + CFGOPT("SDRAM_BANKS", handle->cfg.bank_num, (v >= 4) && ((v % 4) == 0)); + handle->cfg.bank_num /= 4; + CFGOPT("SDRAM_ROWADDR", handle->cfg.row_addr, 1); + CFGOPT("SDRAM_COLADDR", handle->cfg.col_addr, 1); + CFGOPT("SDRAM_ISMOBILE", handle->cfg.is_mobile, v == 0 || v == 1); + CFGOPT("SDRAM_ISBUSSHARE", handle->cfg.is_busshare, v == 0 || v == 1); + + memset(&handle->cfg.debug, 0, sizeof(ingenic_stage1_debug_t)); + + handle->total_sdram_size = (uint32_t) + (2 << (handle->cfg.row_addr + handle->cfg.col_addr - 1)) * 2 + * (handle->cfg.bank_num + 1) * 2 + * (2 - handle->cfg.bus_width); + + handle->nand.cpuid = CPUID(handle->type); + + NOPT("BUSWIDTH", handle->nand.nand_bw, 1); + NOPT("ROWCYCLES", handle->nand.nand_rc, 1); + NOPT("PAGESIZE", handle->nand.nand_ps, 1); + NOPT("PAGEPERBLOCK", handle->nand.nand_ppb, 1); + NOPT("FORCEERASE", handle->nand.nand_force_erase, 1); +// FIXME: pn is not set by xburst-tools usbboot. Is this intended? + NOPT("OOBSIZE", handle->nand.nand_os, 1); + NOPT("ECCPOS", handle->nand.nand_eccpos, 1); + NOPT("BADBLOCKPOS", handle->nand.nand_bbpos, 1); + NOPT("BADBLOCKPAGE", handle->nand.nand_bbpage, 1); + NOPT("PLANENUM", handle->nand.nand_plane, 1); + NOPT("BCHBIT", handle->nand.nand_bchbit, 1); + NOPT("WPPIN", handle->nand.nand_wppin, 1); + NOPT("BLOCKPERCHIP", handle->nand.nand_bpc, 1); + + return 0; +} + +uint32_t ingenic_sdram_size(void *hndl) { + HANDLE; + + return handle->total_sdram_size; +} + +static int ingenic_wordop(void *usb, int op, uint32_t base) { + return usbdev_vendor(usb, USBDEV_TODEV, op, (base >> 16), base & 0xFFFF, 0, 0); +} + +int ingenic_stage1_debugop(void *hndl, const char *filename, uint32_t op, uint32_t pin, uint32_t base, uint32_t size) { + HANDLE; + + handle->cfg.debug.debug_ops = op; + handle->cfg.debug.pin_num = pin; + handle->cfg.debug.start = base; + handle->cfg.debug.size = size; + + int ret = ingenic_loadstage(handle, INGENIC_STAGE1, filename); + + memset(&handle->cfg.debug, 0, sizeof(ingenic_stage1_debug_t)); + + return ret; +} + +int ingenic_loadstage(void *hndl, int id, const char *file) { + HANDLE; + + if(file == NULL) { + errno = EINVAL; + + return -1; + } + + uint32_t base; + int cmd; + + switch(id) { + case INGENIC_STAGE1: + base = SDRAM_BASE + STAGE1_BASE; + cmd = VR_PROGRAM_START1; + + break; + + case INGENIC_STAGE2: + base = SDRAM_BASE + handle->total_sdram_size - STAGE2_CODESIZE; + cmd = VR_PROGRAM_START2; + + break; + + default: + errno = EINVAL; + + return -1; + } + + FILE *fd = fopen(file, "rb"); + + if(fd == NULL) + return -1; + + fseek(fd, 0, SEEK_END); + int size = ftell(fd); + fseek(fd, 0, SEEK_SET); + + void *data = malloc(size); + size_t read_bytes = fread(data, 1, size, fd); + + fclose(fd); + + if(read_bytes != size) { + free(data); + + errno = EIO; + + return -1; + } + + memcpy(data + 8, &handle->cfg, sizeof(firmware_config_t)); + + if(ingenic_wordop(handle->usb, VR_SET_DATA_ADDRESS, base) == -1) { + free(data); + + return -1; + } + + int ret = usbdev_sendbulk(handle->usb, data, size); + + free(data); + + if(ret == -1) + return -1; + + if(id == INGENIC_STAGE2) { + ret = usbdev_vendor(handle->usb, USBDEV_TODEV, VR_FLUSH_CACHES, 0, 0, 0, 0); + + if(ret == -1) + return -1; + } + + ret = usbdev_vendor(handle->usb, USBDEV_TODEV, cmd, (base >> 16), base & 0xFFFF, 0, 0); + + if(ret == -1) + return -1; + + usleep(250); + + if(id == INGENIC_STAGE2) + return ingenic_redetect(hndl); + else + return 0; +} + +int ingenic_memtest(void *hndl, const char *filename, uint32_t base, uint32_t size, uint32_t *fail) { + HANDLE; + + int ret = ingenic_stage1_debugop(handle, filename, STAGE1_DEBUG_MEMTEST, 0, base, size); + + if(ret == -1) + return -1; + + uint32_t data[2]; + + ret = usbdev_recvbulk(handle->usb, &data, sizeof(data)); + + if(ret == -1) + return -1; + + hexdump(data, ret); + + if(ret < 4) { + errno = EIO; + + return -1; + } + + if(data[0] != 0) { + errno = EFAULT; + + *fail = data[0]; + + return -1; + } + + return 0; +} + +int ingenic_configure_stage2(void *hndl) { + HANDLE; + +// DS_flash_info (nand_config_t only) is not implemented in stage2, so using DS_hand (nand_config_t + firmware_config_t) + uint8_t *hand = malloc(sizeof(nand_config_t) + sizeof(firmware_config_t)); + + memcpy(hand, &handle->nand, sizeof(nand_config_t)); + memcpy(hand + sizeof(nand_config_t), &handle->cfg, sizeof(firmware_config_t)); + + int ret = usbdev_sendbulk(handle->usb, hand, sizeof(nand_config_t) + sizeof(firmware_config_t)); + + free(hand); + + if(ret == -1) + return -1; + + if(usbdev_vendor(handle->usb, USBDEV_TODEV, VR_CONFIGRATION, DS_hand, 0, 0, 0) == -1) + return -1; + + uint32_t result[8]; + + ret = usbdev_recvbulk(handle->usb, result, sizeof(result)); + + if(ret == -1) + return -1; + + return 0; +} + +int ingenic_load_sdram(void *hndl, void *data, uint32_t base, uint32_t size) { + HANDLE; + + int max = size, value = 0; + + CALLBACK(progress, PROGRESS_INIT, 0, max); + + while(size) { + int block = size > STAGE2_IOBUF ? STAGE2_IOBUF : size; + + debug(LEVEL_DEBUG, "Loading %d bytes from %p to 0x%08X\n", block, data, base); + + if(usbdev_sendbulk(handle->usb, data, block) == -1) + return -1; + + if(ingenic_wordop(handle->usb, VR_SET_DATA_ADDRESS, base) == -1) + return -1; + + if(ingenic_wordop(handle->usb, VR_SET_DATA_LENGTH, block) == -1) + return -1; + + + if(usbdev_vendor(handle->usb, USBDEV_TODEV, VR_SDRAM_OPS, SDRAM_LOAD, 0, 0, 0) == -1) + return -1; + + uint32_t result[8]; + + int ret = usbdev_recvbulk(handle->usb, result, sizeof(result)); + if(ret == -1) + return -1; + + hexdump(result, ret); + + data += block; + base += block; + size -= block; + value += block; + + CALLBACK(progress, PROGRESS_UPDATE, value, max); + + } + + CALLBACK(progress, PROGRESS_FINI, 0, 0); + + debug(LEVEL_DEBUG, "Load done\n"); + + return 0; +} + +int ingenic_load_sdram_file(void *hndl, uint32_t base, const char *file) { + HANDLE; + + FILE *fd = fopen(file, "rb"); + + if(fd == NULL) + return -1; + + fseek(fd, 0, SEEK_END); + int size = ftell(fd); + fseek(fd, 0, SEEK_SET); + + void *data = malloc(size); + size_t bytes = fread(data, 1, size, fd); + + fclose(fd); + + if(bytes != size) { + free(data); + + errno = EIO; + + return -1; + } + + int ret = ingenic_load_sdram(handle, data, base, size); + + free(data); + + return ret; +} + +int ingenic_go(void *hndl, uint32_t address) { + HANDLE; + + debug(LEVEL_DEBUG, "Go to 0x%08X\n", address); + + return ingenic_wordop(handle->usb, VR_PROGRAM_START2, address); +} + +static inline int ingenic_nandop(void *usb, uint8_t cs, uint8_t request, uint8_t param) { + return usbdev_vendor(usb, USBDEV_TODEV, VR_NAND_OPS, (param << 12) | (cs << 4) | (request & 0x0F), 0, 0, 0); +} + +int ingenic_query_nand(void *hndl, int cs, nand_info_t *info) { + HANDLE; + + if(ingenic_nandop(handle->usb, cs, NAND_QUERY, 0) == -1) + return -1; + + uint32_t dummy[8]; + + int ret = usbdev_recvbulk(handle->usb, dummy, sizeof(dummy)); + + if(ret == -1) + return -1; + + if(ret < sizeof(nand_info_t)) { + errno = EIO; + + return -1; + } + + memcpy(info, dummy, sizeof(nand_info_t)); + + if(usbdev_recvbulk(handle->usb, dummy, sizeof(dummy)) == -1) + return -1; + + return 0; +} + +int ingenic_dump_nand(void *hndl, int cs, int start, int pages, int type, const char *filename) { + HANDLE; + + int raw = type & NAND_RAW; + type &= ~NAND_RAW; + + int page_size = (handle->nand.nand_ps + (type == NO_OOB ? 0 : handle->nand.nand_os)); + int chunk_pages = STAGE2_IOBUF / page_size; + + FILE *dest = fopen(filename, "wb"); + + if(dest == NULL) + return -1; + + void *iobuf = malloc(chunk_pages * page_size); + + int ret = 0; + int value = 0, max = pages; + + CALLBACK(progress, PROGRESS_INIT, 0, max); + + while(pages > 0) { + int chunk = pages < chunk_pages ? pages : chunk_pages; + int bytes = chunk * page_size; + + ret = ingenic_wordop(handle->usb, VR_SET_DATA_ADDRESS, start); + + if(ret == -1) + break; + + ret = ingenic_wordop(handle->usb, VR_SET_DATA_LENGTH, chunk); + + if(ret == -1) + break; + + ret = ingenic_nandop(handle->usb, cs, raw ? NAND_READ_RAW : NAND_READ, type); + + if(ret == -1) + break; + + int ret = usbdev_recvbulk(handle->usb, iobuf, bytes); + + if(ret == -1) + return -1; + + if(ret != bytes) { + debug(LEVEL_ERROR, "Ingenic: NAND dump truncated: expected %d bytes, received %d\n", bytes, ret); + + errno = EIO; + + break; + } + + uint16_t result[4]; + + + ret = usbdev_recvbulk(handle->usb, result, sizeof(result)); + + if(ret == -1) + return -1; + + if(result[3] != 0 && !raw) { + debug(LEVEL_ERROR, "Ingenic: ECC failure while reading NAND. See UART output for details\n"); + + errno = EIO; + + break; + } + + fwrite(iobuf, bytes, 1, dest); + + start += chunk; + pages -= chunk; + + value += chunk; + + CALLBACK(progress, PROGRESS_UPDATE, value, max); + } + + free(iobuf); + fclose(dest); + + CALLBACK(progress, PROGRESS_FINI, 0, 0); + + return ret; +} + +int ingenic_erase_nand(void *hndl, int cs, int start, int blocks) { + HANDLE; + + if(ingenic_wordop(handle->usb, VR_SET_DATA_ADDRESS, start) == -1) + return -1; + + if(ingenic_wordop(handle->usb, VR_SET_DATA_LENGTH, blocks) == -1) + return -1; + + if(ingenic_nandop(handle->usb, cs, NAND_ERASE, 0) == -1) + return -1; + + uint16_t result[4]; + + int ret = usbdev_recvbulk(handle->usb, result, sizeof(result)); + + if(ret == -1) + return -1; + + hexdump(result, ret); + + return 0; +} + +int ingenic_program_nand(void *hndl, int cs, int start, int type, const char *filename) { + HANDLE; + + int page_size = (handle->nand.nand_ps + (type == NO_OOB ? 0 : handle->nand.nand_os)); + int chunk_pages = STAGE2_IOBUF / page_size; + + FILE *in = fopen(filename, "rb"); + + if(in == NULL) + return -1; + + fseek(in, 0, SEEK_END); + int file_size = ftell(in); + fseek(in, 0, SEEK_SET); + + int tail = file_size % page_size; + + if(tail) { + tail = page_size - tail; + + file_size += tail; + } + + int pages = file_size / page_size; + int ret = 0; + + void *iobuf = malloc(chunk_pages * page_size); + + debug(LEVEL_INFO, "Programming %d pages from %d (%d bytes, %d bytes/page)\n", pages, start, file_size, page_size); + + int value = 0, max = pages; + + CALLBACK(progress, PROGRESS_INIT, 0, max); + + while(pages > 0) { + int chunk = pages < chunk_pages ? pages : chunk_pages; + int bytes = chunk * page_size; + + ret = fread(iobuf, 1, bytes, in); + + if(pages < chunk_pages && tail) { + memset(iobuf + ret, 0xFF, tail); + + ret += tail; + } + + if(ret != bytes) { + debug(LEVEL_ERROR, "fread: %d\n", ret); + + ret = -1; + errno = EIO; + + break; + } + + if(usbdev_sendbulk(handle->usb, iobuf, bytes) == -1) + return -1; + + ret = ingenic_wordop(handle->usb, VR_SET_DATA_ADDRESS, start); + + if(ret == -1) + break; + + ret = ingenic_wordop(handle->usb, VR_SET_DATA_LENGTH, chunk); + + if(ret == -1) + break; + + ret = ingenic_nandop(handle->usb, cs, NAND_PROGRAM, type); + + if(ret == -1) + break; + + uint16_t result[4]; + + ret = usbdev_recvbulk(handle->usb, result, sizeof(result)); + + if(ret == -1) + return -1; + + hexdump(result, ret); + + start += chunk; + pages -= chunk; + value += chunk; + + CALLBACK(progress, PROGRESS_UPDATE, value, max); + } + + free(iobuf); + fclose(in); + + CALLBACK(progress, PROGRESS_FINI, 0, 0); + + return ret; +} + +int ingenic_load_nand(void *hndl, int cs, int start, int pages, uint32_t base) { + HANDLE; + + if(ingenic_wordop(handle->usb, VR_PROGRAM_START1, base) == -1) + return -1; + + if(ingenic_wordop(handle->usb, VR_SET_DATA_ADDRESS, start) == -1) + return -1; + + if(ingenic_wordop(handle->usb, VR_SET_DATA_LENGTH, pages) == -1) + return -1; + + if(ingenic_nandop(handle->usb, cs, NAND_READ_TO_RAM, 0) == -1) + return -1; + + uint16_t result[4]; + + if(usbdev_recvbulk(handle->usb, result, sizeof(result)) == -1) + return -1; + + return 0; +} + diff --git a/jzboot/src/main.c b/jzboot/src/main.c new file mode 100644 index 0000000..0d9c151 --- /dev/null +++ b/jzboot/src/main.c @@ -0,0 +1,202 @@ +/* + * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. + * Copyright (C) 2010 Sergey Gridassov + * + * 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 "usbdev.h" +#include "debug.h" +#include "devmgr.h" +#include "ingenic.h" +#include "shell.h" +#include "xburst-tools-config.h" + +static void usage(const char *app) { + printf( + "Usage: \n" + " Enumeration: %1$s -e\n" + " Interactive mode: %1$s -i \n" + " Batch mode (with script): %1$s -i -b \n" + " Batch mode (command list): %1$s -i -c \n\n" + + "USB loader tool for Ingenic Semiconductor XBurst-based SoC\n\n" + " -e Enumerate devices only\n" + " -i Open device with index INDEX in interactive or batch mode\n" + " -c Run semicolon-separated commands and exit\n" + " -d Set output level (0 - no reporting, 4 - max reporting), default = 1 (errors only)\n" + " -C Execute configuration script FILE before anything else\n" + " -b Execute script in FILE\n" + " -v Print program version\n\n", app); +} + +static void dev_handler(int idx, uint16_t vid, uint16_t pid, void *data) { + printf(" Device %d: %04hX:%04hX\n", idx, vid, pid); +} + +int main(int argc, char *argv[]) { + int ch; + int idx = -1, enumerate = 0; + char *cmd = NULL, *script = NULL, *config = NULL; + + while((ch = getopt(argc, argv, "b:i:ec:d:C:v")) != -1) { + switch(ch) { + case 'e': + enumerate = 1; + + break; + + case 'i': + idx = atoi(optarg); + + break; + + case 'c': + cmd = optarg; + + break; + + case 'b': + script = optarg; + + break; + + case 'C': + config = optarg; + + break; + + case 'd': + set_debug_level(atoi(optarg)); + + break; + + case 'v': + printf("JZboot version %s\n", PACKAGE_VERSION); + + return 0; + + default: + usage(argv[0]); + + return 1; + } + } + + if(!enumerate && idx < 0) { + usage(argv[0]); + + return 1; + } + + if(usbdev_init() == -1) { + perror("usbdev_init"); + + return 1; + } + + atexit(usbdev_fini); + + if(usbdev_enumerate() == -1) { + perror("usbdev_enumerate"); + + return 1; + } + + if(enumerate) { + printf("Ingenic devices list:\n"); + + enum_devices(dev_handler); + + return 0; + } + + void *data = get_device(idx); + + if(data == NULL) { + fprintf(stderr, "Device with index %d not found\n", idx); + + return 1; + } + + void *hndl = usbdev_open(data); + + if(hndl == NULL) { + perror("usbdev_open"); + + return 1; + } + + int ret = 0; + + void *ingenic = ingenic_open(hndl); + + if(ingenic == NULL) { + perror("ingenic_open"); + + ret = 1; + + goto exit_usb; + } + + shell_context_t *shell = shell_init(ingenic); + + if(shell == NULL) { + perror("shell_init"); + + ret = 1; + + goto exit_ingenic; + } + + if(config) { + if(shell_source(shell, config) == -1) { + perror("shell_source"); + + ret = 1; + + goto exit_shell; + } + } + + if(cmd != NULL) { + if(shell_execute(shell, cmd) == -1) { + perror("shell_execute"); + + ret = 1; + } + + } else if(script != NULL) { + if(shell_source(shell, script) == -1) { + perror("shell_source"); + + ret = 1; + } + } else + shell_interactive(shell); + +exit_shell: + shell_fini(shell); + +exit_ingenic: + ingenic_close(ingenic); + +exit_usb: + usbdev_close(hndl); + + return ret; +} diff --git a/jzboot/src/shell.c b/jzboot/src/shell.c new file mode 100644 index 0000000..37434b6 --- /dev/null +++ b/jzboot/src/shell.c @@ -0,0 +1,514 @@ +/* + * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. + * Copyright (C) 2010 Sergey Gridassov , + * Peter Zotov + * + * 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 +#ifdef HAVE_LIBREADLINE +#include +#include +#endif +#include +#include +#include +#include + +#include "shell_internal.h" +#include "debug.h" +#include "ingenic.h" + +static void shell_update_cmdset(uint32_t cmdset, void *arg); +static void shell_progress(int action, int value, int max, void *arg); + +static const ingenic_callbacks_t shell_callbacks = { + shell_update_cmdset, + shell_progress +}; + +static const struct { + int set; + const char *name; + const shell_command_t *commands; +} cmdsets[] = { + { CMDSET_SPL, "SPL", spl_cmdset }, + { CMDSET_USBBOOT, "USBBoot", usbboot_cmdset }, + { 0, NULL, NULL } +}; + +shell_context_t *shell_init(void *ingenic) { +#ifdef HAVE_LIBREADLINE + rl_initialize(); +#endif + + debug(LEVEL_DEBUG, "Initializing shell\n"); + + shell_context_t *ctx = malloc(sizeof(shell_context_t)); + memset(ctx, 0, sizeof(shell_context_t)); + ctx->device = ingenic; + + ingenic_set_callbacks(ingenic, &shell_callbacks, ctx); + + shell_update_cmdset(ingenic_cmdset(ingenic), ctx); + + return ctx; +} + +int shell_enumerate_commands(shell_context_t *ctx, int (*callback)(shell_context_t *ctx, const shell_command_t *cmd, void *arg), void *arg) { + for(int i = 0; builtin_cmdset[i].cmd != NULL; i++) { + int ret = callback(ctx, builtin_cmdset + i, arg); + + if(ret != 0) + return ret; + } + + if(ctx->set_cmds) + for(int i = 0; ctx->set_cmds[i].cmd != NULL; i++) { + int ret = callback(ctx, ctx->set_cmds + i, arg); + + if(ret != 0) + return ret; + } + + return 0; +} + +static int shell_run_function(shell_context_t *ctx, const shell_command_t *cmd, void *arg) { + shell_run_data_t *data = arg; + + if(strcmp(cmd->cmd, data->argv[0]) == 0) { + int invalid = 0; + + if(cmd->args == NULL && data->argc != 1) + invalid = 1; + else if(cmd->args) { + char *dup = strdup(cmd->args), *save = dup, *ptrptr = NULL; + + int pos = 1; + int max_tokens = 1; + + for(char *token = strtok_r(dup, " ", &ptrptr); token; token = strtok_r(NULL, " ", &ptrptr)) { + if(strcmp(token, "...") == 0) { + max_tokens = -1; + + break; + } + + max_tokens++; + + if(data->argc - 1 < pos) { + if(*token == '[') { + break; + } else if(*token == '<') { + invalid = 1; + + break; + } + } + + pos++; + } + + if(max_tokens != -1 && data->argc > max_tokens) + invalid = 1; + + + free(save); + } + + if(invalid) { + if(cmd->args) + fprintf(stderr, "Usage: %s %s\n", cmd->cmd, cmd->args); + else + fprintf(stderr, "Usage: %s\n", cmd->cmd); + + errno = EINVAL; + + return -1; + + } else { + int ret = cmd->handler(ctx, data->argc, data->argv); + + if(ret == 0) + return 1; + else + return ret; + } + } else + return 0; +} + +int shell_run(shell_context_t *ctx, int argc, char *argv[]) { + shell_run_data_t data = { argc, argv }; + + int ret = shell_enumerate_commands(ctx, shell_run_function, &data); + + if(ret == 0) { + debug(LEVEL_ERROR, "Bad command '%s'\n", argv[0]); + + errno = EINVAL; + return -1; + + } else if(ret == 1) { + return 0; + } else + return ret; +} + +int shell_execute(shell_context_t *ctx, const char *cmd) { + yyscan_t scanner; + if(yylex_init_extra(ctx, &scanner) == -1) + return -1; + + ctx->line = strdup(cmd); + char *ptr = ctx->line; + + int token; + int state = STATE_WANTSTR; + int argc = 0; + char **argv = NULL; + int fret = 0; + + do { + int noway = 0; + + token = yylex(scanner); + + if((token == TOK_SEPARATOR || token == TOK_COMMENT || token == 0)) { + if(argc > 0) { + int ret = shell_run(ctx, argc, argv); + + for(int i = 0; i < argc; i++) { + free(argv[i]); + } + + free(argv); + + argv = NULL; + argc = 0; + + if(ret == -1) { + fret = -1; + + break; + } + } + + state = STATE_WANTSTR; + } else { + switch(state) { + case STATE_WANTSTR: + if(token == TOK_SPACE) { + state = STATE_WANTSTR; + } else if(token == TOK_STRING) { + int oargc = argc++; + + argv = realloc(argv, sizeof(char *) * argc); + + argv[oargc] = ctx->strval; + + state = STATE_WANTSPACE; + } else { + noway = 1; + } + + break; + + case STATE_WANTSPACE: + if(token == TOK_STRING) { + free(ctx->strval); + + noway = 1; + } else if(token == TOK_SPACE) { + state = STATE_WANTSTR; + } else + noway = 1; + } + + if(noway) { + debug(LEVEL_ERROR, "No way from state %d by token %d\n", state, token); + + for(int i = 0; i < argc; i++) + free(argv[i]); + + free(argv); + + fret = -1; + + break; + } + } + + } while(token && token != TOK_COMMENT); + + free(ptr); + + yylex_destroy(scanner); + + return fret; +} + +int shell_pull(shell_context_t *ctx, char *buf, int maxlen) { + size_t len = strlen(ctx->line); + + if(len < maxlen) + maxlen = len; + + memcpy(buf, ctx->line, maxlen); + + ctx->line += maxlen; + + return maxlen; +} + +void shell_fini(shell_context_t *ctx) { + free(ctx); +} + +int shell_source(shell_context_t *ctx, const char *filename) { + ctx->shell_exit = 0; + + FILE *file = fopen(filename, "r"); + + if(file == NULL) { + return -1; + } + + char *line; + + while((line = fgets(ctx->linebuf, sizeof(ctx->linebuf), file)) && !ctx->shell_exit) { + if(shell_execute(ctx, line) == -1) { + fclose(file); + + return -1; + } + } + + fclose(file); + + return 0; +} + +#ifdef HAVE_LIBREADLINE +static shell_context_t *completion_context; +static char **completion_matches; +static int completion_matches_count = 0; + +static int shell_completion_filler(shell_context_t *ctx, const shell_command_t *cmd, void *arg) { + const char *part = arg; + + size_t len = strlen(part), cmdlen = strlen(cmd->cmd); + + if(cmdlen >= len && memcmp(part, cmd->cmd, len) == 0) { + int idx = completion_matches_count++; + + completion_matches = realloc(completion_matches, sizeof(char **) * completion_matches_count); + completion_matches[idx] = strdup(cmd->cmd); + } + + return 0; +} + +static char *shell_completion(const char *partial, int state) { + static int completion_pass = 0, completion_matches_offset = 0; + + if(state == 0) { + if(completion_matches) { + for(int i = 0; i < completion_matches_count; i++) + if(completion_matches[i]) + free(completion_matches[i]); + + free(completion_matches); + + completion_matches = NULL; + completion_matches_count = 0; + } + + completion_pass = 0; + + char *tmp = rl_line_buffer; + + while(isspace(*tmp)) tmp++; + + int not_first = 0; + + for(; *tmp; tmp++) { + for(const char *sep = rl_basic_word_break_characters; *sep; sep++) { + if(*tmp == *sep) { + not_first = 1; + + break; + } + } + + if(not_first) + break; + } + + if(not_first) { + completion_pass = 1; + + return rl_filename_completion_function(partial, state); + } else { + shell_enumerate_commands(completion_context, shell_completion_filler, (void *) partial); + + completion_matches_offset = 0; + } + } + + if(completion_pass) { + return rl_filename_completion_function(partial, state); + + } else if(completion_matches_offset == completion_matches_count) { + return NULL; + } else { + char *val = completion_matches[completion_matches_offset]; + + completion_matches[completion_matches_offset++] = NULL; + + return val; + } +} +#endif + +void shell_interactive(shell_context_t *ctx) { + ctx->shell_exit = 0; + +#ifndef WITH_READLINE + char *line; + + while(!ctx->shell_exit) { + fputs("jzboot> ", stdout); + fflush(stdout); + + line = fgets(ctx->linebuf, sizeof(ctx->linebuf), stdin); + + if(line == NULL) + break; + + shell_execute(ctx, line); + } +#else + rl_completion_entry_function = shell_completion; + completion_context = ctx; + + rl_set_signals(); + + rl_filename_quote_characters = "\" "; + while(!ctx->shell_exit) { + char *line = readline("jzboot> "); + + if(line == NULL) { + break; + } + + add_history(line); + + shell_execute(ctx, line); + + free(line); + } + + rl_clear_signals(); +#endif +} + +static void shell_update_cmdset(uint32_t cmdset, void *arg) { + shell_context_t *ctx = arg; + + ctx->set_cmds = NULL; + + for(int i = 0; cmdsets[i].name != NULL; i++) { + if(cmdsets[i].set == cmdset) { + printf("Shell: using command set '%s', run 'help' for command list. CPU: %04X\n", cmdsets[i].name, ingenic_type(ctx->device)); + + ctx->set_cmds = cmdsets[i].commands; + + return; + } + } + + debug(LEVEL_ERROR, "Shell: unknown cmdset %u\n", cmdset); +} + +void *shell_device(shell_context_t *ctx) { + return ctx->device; +} + +void shell_exit(shell_context_t *ctx, int val) { + ctx->shell_exit = val; +} + +static void shell_progress(int action, int value, int max, void *arg) { + shell_context_t *ctx = arg; + + if(isatty(STDOUT_FILENO)) { + struct winsize size; + + int progress, percent; + + if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &size) == -1) + return; + + int bar_size = size.ws_col - 6; + + switch(action) { + case PROGRESS_INIT: + ctx->prev_progress = -1; + + + case PROGRESS_FINI: + putchar('\r'); + + for(int i = 0; i < size.ws_col; i++) + putchar(' '); + + putchar('\r'); + + fflush(stdout); + + break; + + case PROGRESS_UPDATE: + progress = value * bar_size / max; + percent = value * 100 / max; + + if(progress != ctx->prev_progress) { + fputs("\r|", stdout); + + for(int i = 0; i < progress; i++) { + putchar('='); + } + + for(int i = progress; i < bar_size; i++) + putchar(' '); + + printf("|%3d%%", percent); + + fflush(stdout); + + ctx->prev_progress = progress; + + } + + + break; + + } + } +} + diff --git a/jzboot/src/shell_builtins.c b/jzboot/src/shell_builtins.c new file mode 100644 index 0000000..e85fb40 --- /dev/null +++ b/jzboot/src/shell_builtins.c @@ -0,0 +1,171 @@ +/* + * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. + * Copyright (C) 2010 Sergey Gridassov , + * Peter Zotov + * + * 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 "shell.h" +#include "app_config.h" +#include "ingenic.h" + +static int builtin_help(shell_context_t *ctx, int argc, char *argv[]); +static int builtin_exit(shell_context_t *ctx, int argc, char *argv[]); +static int builtin_source(shell_context_t *ctx, int argc, char *argv[]); +static int builtin_echo(shell_context_t *ctx, int argc, char *argv[]); +static int builtin_sleep(shell_context_t *ctx, int argc, char *argv[]); +static int builtin_redetect(shell_context_t *ctx, int argc, char *argv[]); +static int builtin_rebuildcfg(shell_context_t *ctx, int argc, char *argv[]); +static int builtin_set(shell_context_t *ctx, int argc, char *argv[]); +static int builtin_safe(shell_context_t *ctx, int argc, char *argv[]); + +const shell_command_t builtin_cmdset[] = { + { "help", "Display this message", builtin_help, NULL }, + { "exit", "Batch: stop current script, interactive: end session", builtin_exit, NULL }, + { "source", "Run specified script", builtin_source, "" }, + { "echo", "Output specified string", builtin_echo, " ..." }, + { "sleep", "Sleep a specified amount of time", builtin_sleep, "" }, + { "set", "Print or set configuraton variables", builtin_set, "[VARIABLE] [VALUE]" }, + { "safe", "Run command ignoring errors", builtin_safe, " [ARG] ..." }, + + { "redetect", "Redetect CPU", builtin_redetect, NULL }, + { "rebuildcfg", "Rebuild firmware configuration data", builtin_rebuildcfg, NULL }, + + { NULL, NULL, NULL } +}; + +static int help_maxwidth_function(shell_context_t *ctx, const shell_command_t *cmd, void *arg) { + int len = strlen(cmd->cmd), *maxlen = arg; + + if(cmd->args) + len += strlen(cmd->args) + 1; + + if(len > *maxlen) + *maxlen = len; + + return 0; +} + +static int help_print_function(shell_context_t *ctx, const shell_command_t *cmd, void *arg) { + int len = strlen(cmd->cmd), *maxlen = arg; + + fputs(cmd->cmd, stdout); + + if(cmd->args) { + len += strlen(cmd->args) + 1; + + putchar(' '); + fputs(cmd->args, stdout); + } + + for(int i = 0; i < *maxlen - len; i++) + putchar(' '); + + puts(cmd->description); + + return 0; +} + +static int builtin_help(shell_context_t *ctx, int argc, char *argv[]) { + int maxwidth = 0; + + shell_enumerate_commands(ctx, help_maxwidth_function, &maxwidth); + + maxwidth += 2; + + return shell_enumerate_commands(ctx, help_print_function, &maxwidth); +} + +static int builtin_exit(shell_context_t *ctx, int argc, char *argv[]) { + shell_exit(ctx, 1); + + return 0; +} + +static int builtin_source(shell_context_t *ctx, int argc, char *argv[]) { + int ret = shell_source(ctx, argv[1]); + + if(ret == -1) { + fprintf(stderr, "Error while sourcing file %s: %s\n", argv[1], strerror(errno)); + } + + shell_exit(ctx, 0); + + return ret; +} + +static int builtin_echo(shell_context_t *ctx, int argc, char *argv[]) { + for(int i = 1; i < argc; i++) { + fputs(argv[i], stdout); + + putchar((i < argc - 1) ? ' ' : '\n'); + } + + return 0; +} + +static int builtin_sleep(shell_context_t *ctx, int argc, char *argv[]) { + uint32_t ms = atoi(argv[1]); + + usleep(ms * 1000); + + return 0; +} + +static int builtin_redetect(shell_context_t *ctx, int argc, char *argv[]) { + if(ingenic_redetect(shell_device(ctx)) == -1) { + perror("ingenic_redetect"); + + return -1; + } else + return 0; +} + + +static int builtin_set(shell_context_t *ctx, int argc, char *argv[]) { + if(argc == 1) { + if(cfg_environ) { + for(int i = 0; cfg_environ[i] != NULL; i++) + printf("%s\n", cfg_environ[i]); + } + + } else if(argc == 2) { + cfg_unsetenv(argv[1]); + + } else if(argc == 3) { + cfg_setenv(argv[1], argv[2]); + } + + return 0; +} + + +static int builtin_rebuildcfg(shell_context_t *ctx, int argc, char *argv[]) { + return ingenic_rebuild(shell_device(ctx)); +} + +static int builtin_safe(shell_context_t *ctx, int argc, char *argv[]) { + if(shell_run(ctx, argc - 1, argv + 1) == -1) + perror("shell_run"); + + return 0; +} + diff --git a/jzboot/src/shell_lex.c b/jzboot/src/shell_lex.c new file mode 100644 index 0000000..c32427d --- /dev/null +++ b/jzboot/src/shell_lex.c @@ -0,0 +1,1965 @@ +#line 2 "shell_lex.c" + +#line 4 "shell_lex.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart(yyin ,yyscanner ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void yyrestart (FILE *input_file ,yyscan_t yyscanner ); +void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); +void yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +void yypop_buffer_state (yyscan_t yyscanner ); + +static void yyensure_buffer_stack (yyscan_t yyscanner ); +static void yy_load_buffer_state (yyscan_t yyscanner ); +static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); + +#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner) + +YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); + +void *yyalloc (yy_size_t ,yyscan_t yyscanner ); +void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); +void yyfree (void * ,yyscan_t yyscanner ); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +#define yywrap(n) 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); +static int yy_get_next_buffer (yyscan_t yyscanner ); +static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 10 +#define YY_END_OF_BUFFER 11 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[19] = + { 0, + 0, 0, 0, 0, 11, 5, 3, 1, 4, 2, + 6, 9, 8, 5, 3, 6, 7, 0 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, + 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 3, 4, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[7] = + { 0, + 1, 2, 3, 4, 4, 5 + } ; + +static yyconst flex_int16_t yy_base[24] = + { 0, + 0, 0, 4, 8, 12, 0, 0, 29, 29, 29, + 0, 29, 0, 0, 0, 0, 29, 29, 14, 19, + 7, 24, 5 + } ; + +static yyconst flex_int16_t yy_def[24] = + { 0, + 18, 1, 19, 19, 18, 20, 21, 18, 18, 18, + 22, 18, 23, 20, 21, 22, 18, 0, 18, 18, + 18, 18, 18 + } ; + +static yyconst flex_int16_t yy_nxt[36] = + { 0, + 6, 7, 8, 9, 10, 6, 12, 17, 15, 13, + 12, 18, 18, 13, 11, 11, 11, 11, 11, 14, + 18, 18, 18, 14, 16, 16, 18, 16, 5, 18, + 18, 18, 18, 18, 18 + } ; + +static yyconst flex_int16_t yy_chk[36] = + { 0, + 1, 1, 1, 1, 1, 1, 3, 23, 21, 3, + 4, 5, 0, 4, 19, 19, 19, 19, 19, 20, + 0, 0, 0, 20, 22, 22, 0, 22, 18, 18, + 18, 18, 18, 18, 18 + } ; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "shell_lex.l" +/* + * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. + * Copyright (C) 2010 Sergey Gridassov + * + * 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 . + */ +#line 20 "shell_lex.l" +#include "shell_internal.h" +#include +#include + +static char *str_append(char *str, const char *src) { + if(str) { + size_t newlen = strlen(str) + strlen(src) + 1; + + char *newstr = malloc(newlen); + + strcpy(newstr, str); + strcat(newstr, src); + + free(str); + + return newstr; + } else + return strdup(src); +} +#define YY_NO_INPUT 1 + +#line 489 "shell_lex.c" + +#define INITIAL 0 +#define STR 1 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + }; /* end struct yyguts_t */ + +static int yy_init_globals (yyscan_t yyscanner ); + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy (yyscan_t yyscanner ); + +int yyget_debug (yyscan_t yyscanner ); + +void yyset_debug (int debug_flag ,yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner ); + +void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); + +FILE *yyget_in (yyscan_t yyscanner ); + +void yyset_in (FILE * in_str ,yyscan_t yyscanner ); + +FILE *yyget_out (yyscan_t yyscanner ); + +void yyset_out (FILE * out_str ,yyscan_t yyscanner ); + +int yyget_leng (yyscan_t yyscanner ); + +char *yyget_text (yyscan_t yyscanner ); + +int yyget_lineno (yyscan_t yyscanner ); + +void yyset_lineno (int line_number ,yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap (yyscan_t yyscanner ); +#else +extern int yywrap (yyscan_t yyscanner ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (yyscan_t yyscanner ); +#else +static int input (yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + size_t n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (yyscan_t yyscanner); + +#define YY_DECL int yylex (yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + +#line 43 "shell_lex.l" + +#line 716 "shell_lex.c" + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + yy_load_buffer_state(yyscanner ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 19 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_current_state != 18 ); + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 44 "shell_lex.l" +{ yyextra->strval = NULL; BEGIN(STR); } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 45 "shell_lex.l" +return TOK_SEPARATOR; + YY_BREAK +case 3: +/* rule 3 can match eol */ +YY_RULE_SETUP +#line 46 "shell_lex.l" +return TOK_SPACE; + YY_BREAK +case 4: +YY_RULE_SETUP +#line 47 "shell_lex.l" +return TOK_COMMENT; + YY_BREAK +case 5: +YY_RULE_SETUP +#line 48 "shell_lex.l" +{ yyextra->strval = strdup(yytext); return TOK_STRING; } + YY_BREAK +case 6: +/* rule 6 can match eol */ +YY_RULE_SETUP +#line 49 "shell_lex.l" +yyextra->strval = str_append(yyextra->strval, yytext); + YY_BREAK +case 7: +YY_RULE_SETUP +#line 50 "shell_lex.l" +yyextra->strval = str_append(yyextra->strval, "\""); + YY_BREAK +case 8: +YY_RULE_SETUP +#line 51 "shell_lex.l" +yyextra->strval = str_append(yyextra->strval, "\\"); + YY_BREAK +case 9: +YY_RULE_SETUP +#line 52 "shell_lex.l" +{ BEGIN(INITIAL); return TOK_STRING; } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 53 "shell_lex.l" +ECHO; + YY_BREAK +#line 847 "shell_lex.c" +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(STR): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( yywrap(yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = yyg->yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, (size_t) num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart(yyin ,yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 19 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + register int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + register char *yy_cp = yyg->yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 19 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 18); + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yyg->yy_c_buf_p - yyg->yytext_ptr; + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart(yyin ,yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap(yyscanner ) ) + return EOF; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); + yy_load_buffer_state(yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state(yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void yy_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ,yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer(b,file ,yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * @param yyscanner The scanner object. + */ + void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree((void *) b->yy_ch_buf ,yyscanner ); + + yyfree((void *) b ,yyscanner ); +} + +#ifndef __cplusplus +extern int isatty (int ); +#endif /* __cplusplus */ + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_flush_buffer(b ,yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state(yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(yyscanner); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void yypop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (yyscan_t yyscanner) +{ + int num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer(b ,yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner) +{ + + return yy_scan_bytes(yystr,strlen(yystr) ,yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) yyalloc(n ,yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer(buf,n ,yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int yyget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int yyget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int yyget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *yyget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param line_number + * @param yyscanner The scanner object. + */ +void yyset_lineno (int line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "yyset_lineno called with no buffer" , yyscanner); + + yylineno = line_number; +} + +/** Set the current column. + * @param line_number + * @param yyscanner The scanner object. + */ +void yyset_column (int column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "yyset_column called with no buffer" , yyscanner); + + yycolumn = column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * @param yyscanner The scanner object. + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = in_str ; +} + +void yyset_out (FILE * out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = out_str ; +} + +int yyget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void yyset_debug (int bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +/* User-visible API */ + +/* yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ + +int yylex_init(yyscan_t* ptr_yy_globals) + +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* yylex_init_extra has the same functionality as yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to yyalloc in + * the yyextra field. + */ + +int yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) + +{ + struct yyguts_t dummy_yyguts; + + yyset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + yyset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = 0; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = (char *) 0; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + yyfree(yyg->yy_buffer_stack ,yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + yyfree(yyg->yy_start_stack ,yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size , yyscan_t yyscanner) +{ + return (void *) malloc( size ); +} + +void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void yyfree (void * ptr , yyscan_t yyscanner) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 53 "shell_lex.l" diff --git a/jzboot/src/shell_lex.l b/jzboot/src/shell_lex.l new file mode 100644 index 0000000..65f8987 --- /dev/null +++ b/jzboot/src/shell_lex.l @@ -0,0 +1,52 @@ +/* + * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. + * Copyright (C) 2010 Sergey Gridassov + * + * 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 "shell_internal.h" +#include +#include + +static char *str_append(char *str, const char *src) { + if(str) { + size_t newlen = strlen(str) + strlen(src) + 1; + + char *newstr = malloc(newlen); + + strcpy(newstr, str); + strcat(newstr, src); + + free(str); + + return newstr; + } else + return strdup(src); +} +%} +%option noyywrap nounput noinput batch reentrant + +%x STR +%% +["] { yyextra->strval = NULL; BEGIN(STR); } +; return TOK_SEPARATOR; +[[:space:]]+ return TOK_SPACE; +[#] return TOK_COMMENT; +[^[:space:];"#]+ { yyextra->strval = strdup(yytext); return TOK_STRING; } +[^\\"]+ yyextra->strval = str_append(yyextra->strval, yytext); +\\["] yyextra->strval = str_append(yyextra->strval, "\""); +\\ yyextra->strval = str_append(yyextra->strval, "\\"); +["] { BEGIN(INITIAL); return TOK_STRING; } diff --git a/jzboot/src/spl_cmdset.c b/jzboot/src/spl_cmdset.c new file mode 100644 index 0000000..76a3c77 --- /dev/null +++ b/jzboot/src/spl_cmdset.c @@ -0,0 +1,128 @@ +/* + * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. + * Copyright (C) 2010 Sergey Gridassov , + * Peter Zotov + * + * 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 "shell.h" +#include "app_config.h" +#include "ingenic.h" + +static int spl_memtest(shell_context_t *ctx, int argc, char *argv[]); +static int spl_gpio(shell_context_t *ctx, int argc, char *argv[]); +static int spl_boot(shell_context_t *ctx, int argc, char *argv[]); + +const shell_command_t spl_cmdset[] = { + { "memtest", "SDRAM test", spl_memtest, "[BASE] " }, + { "gpio", "Set GPIO #PIN to STATE 0 or 1", spl_gpio, " " }, + { "boot", "Load stage2 USB bootloader", spl_boot, NULL }, + { NULL, NULL, NULL, NULL } +}; + +static int spl_stage1_op(shell_context_t *ctx, uint32_t op, uint32_t pin, uint32_t base, uint32_t size) { + if(cfg_getenv("STAGE1_FILE") == NULL) { + printf("Variable STAGE1_FILE is not set\n"); + + return -1; + } + + int ret = ingenic_stage1_debugop(shell_device(ctx), cfg_getenv("STAGE1_FILE"), op, pin, base, size); + + if(ret == -1) + perror("ingenic_stage1_debugop"); + + return ret; +} + +static int spl_memtest(shell_context_t *ctx, int argc, char *argv[]) { + uint32_t start, size; + + if(argc == 3) { + start = strtoul(argv[1], NULL, 0); + size = strtoul(argv[2], NULL, 0); + } else { + start = SDRAM_BASE; + size = ingenic_sdram_size(shell_device(ctx)); + } + + if(cfg_getenv("STAGE1_FILE") == NULL) { + printf("Variable STAGE1_FILE is not set\n"); + + return -1; + } + + uint32_t fail; + + int ret = ingenic_memtest(shell_device(ctx), cfg_getenv("STAGE1_FILE"), start, size, &fail); + + if(ret == -1) { + if(errno == EFAULT) { + printf("Memory test failed at address 0x%08X\n", fail); + } else { + perror("ingenic_memtest"); + } + + } else { + printf("Memory test passed\n"); + } + + return ret; +} + +static int spl_gpio(shell_context_t *ctx, int argc, char *argv[]) { + if(strcmp(argv[2], "0") && strcmp(argv[2], "1")) { + printf("Usage: %s \n", argv[0]); + printf(" STATE := 0 | 1\n"); + + return -1; + } + + return spl_stage1_op(ctx, !strcmp(argv[2], "1") ? STAGE1_DEBUG_GPIO_SET : STAGE1_DEBUG_GPIO_CLEAR, atoi(argv[1]), 0, 0); +} + +static int spl_boot(shell_context_t *ctx, int argc, char *argv[]) { + int ret = spl_stage1_op(ctx, STAGE1_DEBUG_BOOT, 0, 0, 0); + + if(ret == -1) + return -1; + + if(cfg_getenv("STAGE2_FILE") == NULL) { + printf("Variable STAGE2_FILE is not set\n"); + + return -1; + } + + ret = ingenic_loadstage(shell_device(ctx), INGENIC_STAGE2, cfg_getenv("STAGE2_FILE")); + + if(ret == -1) { + perror("ingenic_loadstage"); + + return -1; + } + + ret = ingenic_configure_stage2(shell_device(ctx)); + + if(ret == -1) + perror("ingenic_configure_stage2"); + + return ret; +} + diff --git a/jzboot/src/usbboot_cmdset.c b/jzboot/src/usbboot_cmdset.c new file mode 100644 index 0000000..6d9ec2c --- /dev/null +++ b/jzboot/src/usbboot_cmdset.c @@ -0,0 +1,162 @@ +/* + * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. + * Copyright (C) 2010 Peter Zotov + * + * 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 "shell.h" +#include "app_config.h" +#include "ingenic.h" +#include "elfldr.h" + +static int usbboot_boot(shell_context_t *ctx, int argc, char *argv[]); +static int usbboot_load(shell_context_t *ctx, int argc, char *argv[]); +static int usbboot_go(shell_context_t *ctx, int argc, char *argv[]); +static int usbboot_load_kernel(shell_context_t *ctx, int argc, char *argv[]); +static int usbboot_nquery(shell_context_t *ctx, int argc, char *argv[]); +static int usbboot_ndump(shell_context_t *ctx, int argc, char *argv[]); +static int usbboot_nerase(shell_context_t *ctx, int argc, char *argv[]); +static int usbboot_nprogram(shell_context_t *ctx, int argc, char *argv[]); +static int usbboot_nload(shell_context_t *ctx, int argc, char *argv[]); + +const shell_command_t usbboot_cmdset[] = { + + { "boot", "Reconfigure stage2", usbboot_boot, NULL }, + { "load", "Load file to SDRAM", usbboot_load, " " }, + { "go", "Jump to
", usbboot_go, "
" }, + { "load_kernel", "Load ELF kernel and initrd to memory", usbboot_load_kernel, " [INITRAMFS]" }, + + { "nquery", "Query NAND information", usbboot_nquery, "" }, + { "ndump", "Dump NAND to file", usbboot_ndump, " " }, + { "ndump_oob", "Dump NAND with OOB to file", usbboot_ndump, " " }, + { "nerase", "Erase NAND blocks", usbboot_nerase, " " }, + { "nprogram", "Program NAND from file", usbboot_nprogram, " " }, + { "nprogram_oob", "Program NAND with OOB from file", usbboot_nprogram, " " }, + { "nload", "Load NAND data to SDRAM", usbboot_nload, " " }, + + { NULL, NULL, NULL, NULL } +}; + +static int usbboot_boot(shell_context_t *ctx, int argc, char *argv[]) { + int ret = ingenic_configure_stage2(shell_device(ctx)); + + if(ret == -1) + perror("ingenic_configure_stage2"); + + return ret; +} + +static int usbboot_load(shell_context_t *ctx, int argc, char *argv[]) { + int ret = ingenic_load_sdram_file(shell_device(ctx), strtoul(argv[2], NULL, 0), argv[1]); + + if(ret == -1) + perror("ingenic_load_sdram_file"); + + return ret; +} + +static int usbboot_go(shell_context_t *ctx, int argc, char *argv[]) { + int ret = ingenic_go(shell_device(ctx), strtoul(argv[1], NULL, 0)); + + if(ret == -1) + perror("ingenic_go"); + + return ret; +} + +static int usbboot_nquery(shell_context_t *ctx, int argc, char *argv[]) { + nand_info_t info; + + int ret = ingenic_query_nand(shell_device(ctx), atoi(argv[1]), &info); + + if(ret == -1) { + perror("ingenic_query_nand"); + + return -1; + } + + printf( + "VID: %02hhX\n" + "PID: %02hhX\n" + "Chip: %02hhX\n" + "Page: %02hhX\n" + "Plane: %02hhX\n", + info.vid, info.pid, info.chip, info.page, info.plane); + + + return 0; +} + +static int usbboot_ndump(shell_context_t *ctx, int argc, char *argv[]) { + int type = strcmp(argv[0], "ndump_oob") ? NO_OOB : OOB_ECC; + + if(cfg_getenv("NAND_RAW")) + type |= NAND_RAW; + + int ret = ingenic_dump_nand(shell_device(ctx), atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), type, argv[4]); + + if(ret == -1) + perror("ingenic_dump_nand"); + + return ret; +} + +static int usbboot_nerase(shell_context_t *ctx, int argc, char *argv[]) { + int ret = ingenic_erase_nand(shell_device(ctx), atoi(argv[1]), atoi(argv[2]), atoi(argv[3])); + + if(ret == -1) + perror("ingenic_erase_nand"); + + return ret; + +} + +static int usbboot_nprogram(shell_context_t *ctx, int argc, char *argv[]) { + int type = strcmp(argv[0], "nprogram_oob") ? NO_OOB : OOB_ECC; + + if(strcmp(argv[0], "nprogram_oob") == 0) { + if(cfg_getenv("NAND_RAW")) + type = OOB_ECC; + else + type = OOB_NO_ECC; + } else + type = NO_OOB; + + int ret = ingenic_program_nand(shell_device(ctx), atoi(argv[1]), atoi(argv[2]), type, argv[3]); + + if(ret == -1) + perror("ingenic_program_nand"); + + return ret; +} + +static int usbboot_nload(shell_context_t *ctx, int argc, char *argv[]) { + int ret = ingenic_load_nand(shell_device(ctx), atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), strtoul(argv[4], NULL, 0)); + + if(ret == -1) + perror("ingenic_load_nand"); + + return ret; +} + +static int usbboot_load_kernel(shell_context_t *ctx, int argc, char *argv[]) { + return load_elf(shell_device(ctx), argv[1], argv[2], + argc == 4 ? argv[3] : NULL); +} + diff --git a/jzboot/src/usbdev.c b/jzboot/src/usbdev.c new file mode 100644 index 0000000..d202e5c --- /dev/null +++ b/jzboot/src/usbdev.c @@ -0,0 +1,239 @@ +/* + * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. + * Copyright (C) 2010 Sergey Gridassov , + * Peter Zotov + * + * 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 "usbdev.h" +#include "debug.h" +#include "devmgr.h" + +#define CONTROL_TIMEOUT 5000 + +static libusb_context *ctx = NULL; + +static int translate_libusb(int code); + +int usbdev_enumerate() { + libusb_device **list; + ssize_t devices_count = libusb_get_device_list(ctx, &list); + + if(devices_count < 0) + return translate_libusb(devices_count); + + for(int i = 0; i < devices_count; i++) { + struct libusb_device_descriptor descr; + + int ret = libusb_get_device_descriptor(list[i], &descr); + + if(ret != LIBUSB_SUCCESS) { + libusb_free_device_list(list, 1); + + return translate_libusb(ret); + } + + if(is_ingenic(descr.idVendor, descr.idProduct)) { + add_device(descr.idVendor, descr.idProduct, libusb_ref_device(list[i])); + } + } + + libusb_free_device_list(list, 1); + + return 0; +} + +int usbdev_init() { + if(translate_libusb(libusb_init(&ctx)) == -1) + return -1; + + libusb_set_debug(ctx, get_debug_level()); + + return 0; +} + +void usbdev_fini() { + libusb_exit(ctx); + ctx = NULL; +} + +void *usbdev_open(void *dev) { + libusb_device_handle *hndl; + + if(translate_libusb(libusb_open(dev, &hndl)) == -1) + return NULL; + + int ret = libusb_kernel_driver_active(hndl, INTERFACE_BOOT); + + if(ret < 0) { + libusb_close(hndl); + + translate_libusb(ret); + + return NULL; + + } else if(ret == 1) { + debug(LEVEL_INFO, "Deactivating kernel driver\n"); + + if(translate_libusb(libusb_detach_kernel_driver(hndl, INTERFACE_BOOT)) == -1) { + libusb_close(hndl); + + return NULL; + } + } + + if(translate_libusb(libusb_claim_interface(hndl, INTERFACE_BOOT)) == -1) { + libusb_close(hndl); + + return NULL; + } + + debug(LEVEL_DEBUG, "Device open\n"); + + return hndl; +} + +void usbdev_close(void *_hndl) { + libusb_device_handle *hndl = _hndl; + + libusb_release_interface(hndl, INTERFACE_BOOT); + + libusb_close(hndl); + + debug(LEVEL_DEBUG, "Device closed\n"); +} + +int usbdev_vendor(void *_hndl, int direction, uint8_t req, uint16_t value, uint16_t index, void *data, uint16_t size) { + libusb_device_handle *hndl = _hndl; + + uint8_t type = LIBUSB_REQUEST_TYPE_VENDOR; + + if(direction == USBDEV_FROMDEV) + type |= LIBUSB_ENDPOINT_IN; + + debug(LEVEL_DEBUG, "Control: type %02hhX, request %hhu, value %hu, index %hu, data %p, size %hu\n", type, req, value, index, data, size); + + int ret = libusb_control_transfer(hndl, type, req, value, index, data, size, CONTROL_TIMEOUT); + + if(ret >= 0) + return ret; + else + return translate_libusb(ret); +} + +int usbdev_sendbulk(void *hndl, void *data, int size) { + int trans; + + debug(LEVEL_DEBUG, "Bulk: writing data %p, size %d\n", data, size); + + if(translate_libusb(libusb_bulk_transfer(hndl, ENDPOINT_OUT, data, size, &trans, CONTROL_TIMEOUT)) == -1) { + return -1; + } + + if(trans != size) { + debug(LEVEL_WARNING, "Bulk data truncated: requested %d, sent %d\n", size, trans); + + errno = EIO; + + return -1; + } + + return 0; +} + +int usbdev_recvbulk(void *hndl, void *data, int size) { + int trans; + + debug(LEVEL_DEBUG, "Bulk: reading data %p, size %d\n", data, size); + + int ret = translate_libusb(libusb_bulk_transfer(hndl, ENDPOINT_IN, data, size, &trans, CONTROL_TIMEOUT)); + + return ret == -1 ? -1 : trans; +} + +static int translate_libusb(int code) { + switch(code) { + case LIBUSB_SUCCESS: + return 0; + + case LIBUSB_ERROR_IO: + errno = EIO; + + break; + + case LIBUSB_ERROR_INVALID_PARAM: + errno = EINVAL; + + break; + + case LIBUSB_ERROR_ACCESS: + errno = EACCES; + + break; + + case LIBUSB_ERROR_NO_DEVICE: + case LIBUSB_ERROR_NOT_FOUND: + errno = ENOENT; + + break; + + case LIBUSB_ERROR_BUSY: + errno = EBUSY; + + break; + + case LIBUSB_ERROR_TIMEOUT: + errno = ETIMEDOUT; + + break; + + case LIBUSB_ERROR_OVERFLOW: + errno = EOVERFLOW; + + break; + + case LIBUSB_ERROR_PIPE: + errno = EPIPE; + + break; + + case LIBUSB_ERROR_INTERRUPTED: + errno = EINTR; + + break; + + case LIBUSB_ERROR_NO_MEM: + errno = ENOMEM; + + break; + + case LIBUSB_ERROR_NOT_SUPPORTED: + errno = ENOTSUP; + + break; + + + case LIBUSB_ERROR_OTHER: + default: + errno = EFAULT; + } + + debug(LEVEL_DEBUG, "Translated libusb return %d to %d\n", code, errno); + + return -1; +}