From 301f0c660521885ad885bed404c9d2ad2023e977 Mon Sep 17 00:00:00 2001 From: Sergey Gridassov Date: Sat, 4 Dec 2010 04:14:23 +0300 Subject: [PATCH 01/50] Initial commit. --- .gitignore | 3 + COPYING | 4 + COPYING.GPL3 | 674 +++++++++++++++++++ Makefile | 31 + config.c | 110 ++++ config.h | 28 + debug.c | 47 ++ debug.h | 33 + devmgr.c | 77 +++ devmgr.h | 34 + fw.bin | Bin 0 -> 7612 bytes ingenic.c | 286 ++++++++ ingenic.h | 70 ++ initial.cfg | 40 ++ main.c | 187 ++++++ shell.c | 379 +++++++++++ shell.h | 49 ++ shell_lex.c | 1793 ++++++++++++++++++++++++++++++++++++++++++++++++++ shell_lex.l | 54 ++ spl_cmdset.c | 39 ++ usbdev.c | 216 ++++++ usbdev.h | 36 + 22 files changed, 4190 insertions(+) create mode 100644 .gitignore create mode 100644 COPYING create mode 100644 COPYING.GPL3 create mode 100644 Makefile create mode 100644 config.c create mode 100644 config.h create mode 100644 debug.c create mode 100644 debug.h create mode 100644 devmgr.c create mode 100644 devmgr.h create mode 100755 fw.bin create mode 100644 ingenic.c create mode 100644 ingenic.h create mode 100644 initial.cfg create mode 100644 main.c create mode 100644 shell.c create mode 100644 shell.h create mode 100644 shell_lex.c create mode 100644 shell_lex.l create mode 100644 spl_cmdset.c create mode 100644 usbdev.c create mode 100644 usbdev.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7735af4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +jzboot +*.o +*.d diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..b438b7f --- /dev/null +++ b/COPYING @@ -0,0 +1,4 @@ +fw.bin is (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/COPYING.GPL3 b/COPYING.GPL3 new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/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/Makefile b/Makefile new file mode 100644 index 0000000..b664f86 --- /dev/null +++ b/Makefile @@ -0,0 +1,31 @@ +READLINE ?= 0 + + +ifneq (${READLINE},0) + LIBS += -lreadline + CPPFLAGS += -DWITH_READLINE +endif + +CC = gcc +TARGET = jzboot +SOURCES = debug.c devmgr.c ingenic.c main.c shell_lex.c usbdev.c shell.c config.c spl_cmdset.c +CFLAGS = --std=gnu99 -Wall -Werror -O2 $(shell pkg-config libusb-1.0 --cflags) +LIBS += $(shell pkg-config libusb-1.0 --libs) + +OBJECTS = ${SOURCES:.c=.o} + +all: ${TARGET} + +${TARGET}: ${OBJECTS} + ${CC} ${LDFLAGS} -o $@ $^ ${LIBS} + +clean: + rm -f ${TARGET} ${OBJECTS} ${SOURCES:.c=.d} + +%.o: %.c + ${CC} ${CPPFLAGS} ${CFLAGS} -o $@ -MD -c $< + +%.c: %.l + flex -o $@ $< + +-include ${SOURCES:.c=.d} diff --git a/config.c b/config.c new file mode 100644 index 0000000..cc94566 --- /dev/null +++ b/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 "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/config.h b/config.h new file mode 100644 index 0000000..dd4307b --- /dev/null +++ b/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/debug.c b/debug.c new file mode 100644 index 0000000..8506073 --- /dev/null +++ b/debug.c @@ -0,0 +1,47 @@ +/* + * 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); +} diff --git a/debug.h b/debug.h new file mode 100644 index 0000000..3998e84 --- /dev/null +++ b/debug.h @@ -0,0 +1,33 @@ +/* + * 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 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/devmgr.c b/devmgr.c new file mode 100644 index 0000000..6e83ac4 --- /dev/null +++ b/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/devmgr.h b/devmgr.h new file mode 100644 index 0000000..49a92c4 --- /dev/null +++ b/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/fw.bin b/fw.bin new file mode 100755 index 0000000000000000000000000000000000000000..cfdcd02202c7e4c12f285c272fdafc0f8906515c GIT binary patch literal 7612 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 + * + * 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 "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) + +typedef struct { + void *usb; + uint32_t type; + + const ingenic_callbacks_t *callbacks; + void *callbacks_data; + + firmware_config_t cfg; +} 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 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"); + } +} + +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) { + if(errno == EFAULT) { + debug(LEVEL_DEBUG, "Stage detected\n"); + } else + return 0; + } + + magic[8] = 0; + + for(int i = 0; magic_list[i].magic != NULL; i++) + if(strcmp(magic_list[i].magic, magic) == 0) { + debug(LEVEL_DEBUG, "Magic: '%s', type: %08X\n", magic, magic_list[i].id); + + 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) && handle->callbacks && handle->callbacks->cmdset_change) + handle->callbacks->cmdset_change(handle->callbacks_data); + + 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); +} + +#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; }; handle->cfg.var = v; } + +int ingenic_rebuild(void *hndl) { + HANDLE; + + handle->cfg.cpu_id = 0x4750; //CPUID(handle->type); + + CFGOPT("EXTCLK", ext_clk, v <= 27 && v >= 12); + CFGOPT("CPUSPEED", cpu_speed, (v % 12) == 0); + handle->cfg.cpu_speed /= handle->cfg.ext_clk; + CFGOPT("PHMDIV", phm_div, v <= 32 && v >= 2); + CFGOPT("USEUART", use_uart, 1); + CFGOPT("BAUDRATE", baudrate, 1); + + CFGOPT("SDRAM_BUSWIDTH", bus_width, (v == 16) || (v == 32)); + handle->cfg.bus_width = handle->cfg.bus_width == 16 ? 1 : 0; + CFGOPT("SDRAM_BANKS", bank_num, (v >= 4) && ((v % 4) == 0)); + handle->cfg.bank_num /= 4; + CFGOPT("SDRAM_ROWADDR", row_addr, 1); + CFGOPT("SDRAM_COLADDR", col_addr, 1); + CFGOPT("SDRAM_ISMOBILE", is_mobile, v == 0 || v == 1); + CFGOPT("SDRAM_ISBUSSHARE", is_busshare, v == 0 || v == 1); + CFGOPT("DEBUGOPS", debug_ops, 1); + CFGOPT("PINNUM", pin_num, 1); + CFGOPT("START", start, 1); + CFGOPT("SIZE", size, 1); + + + + debug(LEVEL_DEBUG, "Firmware configuration dump:\n"); + + hexdump(&handle->cfg, sizeof(firmware_config_t)); + + return 0; +} + +static int ingenic_address(void *usb, uint32_t base) { + debug(LEVEL_DEBUG, "Ingenic: address 0x%08X\n", base); + + return usbdev_vendor(usb, USBDEV_TODEV, VR_SET_DATA_ADDRESS, (base >> 16), base & 0xFFFF, 0, 0); +} + +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; + + 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); + fread(data, size, 1, fd); + + fclose(fd); + + memcpy(data + 8, &handle->cfg, sizeof(firmware_config_t)); + + debug(LEVEL_DEBUG, "Ingenic: loading stage%d to 0x%08X, %d bytes\n", id, base, size); + + if(ingenic_address(handle->usb, base) == -1) { + free(data); + + return -1; + } + + hexdump(data, size); + + int ret = usbdev_sendbulk(handle->usb, data, size); + + free(data); + + if(ret == -1) + return -1; + + debug(LEVEL_DEBUG, "Ingenic: stage written\n"); + + debug(LEVEL_DEBUG, "Starting stage!\n"); + + ret = usbdev_vendor(handle->usb, USBDEV_TODEV, cmd, (base >> 16), base & 0xFFFF, 0, 0); + + if(ret == -1) + return -1; + + return ingenic_redetect(hndl); +} diff --git a/ingenic.h b/ingenic.h new file mode 100644 index 0000000..32f2ea4 --- /dev/null +++ b/ingenic.h @@ -0,0 +1,70 @@ +/* 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 + +typedef struct { + void (*cmdset_change)(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); + +int ingenic_rebuild(void *hndl); +int ingenic_loadstage(void *hndl, int id, const char *filename); + +#define CMDSET_SPL 1 +#define CMDSET_USBBOOT 2 + +#define INGENIC_STAGE1 1 +#define INGENIC_STAGE2 2 + +#define STAGE1_BASE 0x2000 +#define SDRAM_BASE 0x80000000 + +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; + + /* debug args */ + uint8_t debug_ops; + uint8_t pin_num; + uint32_t start; + uint32_t size; +} __attribute__((packed)) firmware_config_t; + +#endif diff --git a/initial.cfg b/initial.cfg new file mode 100644 index 0000000..19aef7d --- /dev/null +++ b/initial.cfg @@ -0,0 +1,40 @@ +# Configuration variables: +# STAGE1_FILE + +set STAGE1_FILE fw.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 8 # Specify the ECC offset inside the oob data (0-[oobsize-1]) +set NAND_BADBLACKPOS 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 + +# DEBUG +set DEBUGOPS 0 +set PINNUM 0 +set START 0 +set SIZE 0 + + +rebuildcfg diff --git a/main.c b/main.c new file mode 100644 index 0000000..916abeb --- /dev/null +++ b/main.c @@ -0,0 +1,187 @@ +/* + * 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" + +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\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:")) != -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; + + 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; + } + + if(shell_init(ingenic) == -1) { + perror("shell_init"); + + ret = 1; + + goto exit_ingenic; + } + + if(config) + if(shell_source(config) == -1) { + perror("shell_source"); + } + + if(cmd != NULL) { + if(shell_execute(cmd) == -1) { + perror("shell_execute"); + + ret = 1; + } + + } else if(script != NULL) { + if(shell_source(script) == -1) { + perror("shell_source"); + + ret = 1; + } + } else + shell_interactive(); + + shell_fini(); + +exit_ingenic: + ingenic_close(ingenic); + +exit_usb: + usbdev_close(hndl); + + return ret; +} diff --git a/shell.c b/shell.c new file mode 100644 index 0000000..66dc964 --- /dev/null +++ b/shell.c @@ -0,0 +1,379 @@ +/* + * 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 +#ifdef WITH_READLINE +#include +#include +#endif +#include +#include + +#include "shell.h" +#include "debug.h" +#include "ingenic.h" +#include "config.h" + +static void *device = NULL; +static char linebuf[512]; +char *strval = NULL, *line = NULL; + +int yylex(); +void yyrestart(FILE *new_file); + +static int builtin_help(int argc, char *argv[]); +static int builtin_exit(int argc, char *argv[]); +static int builtin_source(int argc, char *argv[]); +static int builtin_echo(int argc, char *argv[]); +static int builtin_redetect(int argc, char *argv[]); +static int builtin_rebuildcfg(int argc, char *argv[]); +static int builtin_set(int argc, char *argv[]); + +static const shell_command_t commands[] = { + { "help", "- Display this message", builtin_help }, + { "exit", "- Batch: stop current script, interactive: end session", builtin_exit }, + { "source", " - run specified script", builtin_source }, + { "echo", " - output specified string", builtin_echo }, + { "set", "[VARIABLE] [VALUE] - print or set configuraton variables", builtin_set }, + + { "redetect", " - Redetect CPU", builtin_redetect }, + { "rebuildcfg", " - Rebuild firmware configuration data", builtin_rebuildcfg }, + + { NULL, NULL, NULL } +}; + +static void shell_update_cmdset(void *arg); + +static const ingenic_callbacks_t shell_callbacks = { + shell_update_cmdset, +}; + +static const shell_command_t *set_cmds = NULL; +static int shell_exit = 0; + +int shell_init(void *ingenic) { +#ifdef WITH_READLINE + rl_initialize(); +#endif + + debug(LEVEL_DEBUG, "Initializing shell\n"); + + device = ingenic; + + ingenic_set_callbacks(ingenic, &shell_callbacks, NULL); + + shell_update_cmdset(NULL); + + return 0; +} + +#define STATE_WANTSTR 0 +#define STATE_WANTSPACE 1 + +int shell_run(int argc, char *argv[]) { + for(int i = 0; commands[i].cmd != NULL; i++) + if(strcmp(commands[i].cmd, argv[0]) == 0) + return commands[i].handler(argc, argv); + + if(set_cmds) { + for(int i = 0; set_cmds[i].cmd != NULL; i++) + if(strcmp(set_cmds[i].cmd, argv[0]) == 0) + return set_cmds[i].handler(argc, argv); + } + + debug(LEVEL_ERROR, "Bad command '%s'\n", argv[0]); + + errno = EINVAL; + return -1; +} + +int shell_execute(const char *cmd) { + line = strdup(cmd); + char *ptr = line; + + int token; + int state = STATE_WANTSTR; + int argc = 0; + char **argv = NULL; + + yyrestart(NULL); + + do { + int noway = 0; + + token = yylex(); + + if((token == TOK_SEPARATOR || token == TOK_COMMENT || token == 0)) { + if(argc > 0) { + int ret = shell_run(argc, argv); + + for(int i = 0; i < argc; i++) { + free(argv[i]); + } + + free(argv); + + argv = NULL; + argc = 0; + + if(ret == -1) { + free(ptr); + + return -1; + } + } + + 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] = strval; + + state = STATE_WANTSPACE; + } else { + noway = 1; + } + + break; + + case STATE_WANTSPACE: + if(token == TOK_STRING) { + free(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); + free(ptr); + + return -1; + } + } + + } while(token && token != TOK_COMMENT); + + free(ptr); + + return 0; +} + +int shell_pull(char *buf, int maxlen) { + size_t len = strlen(line); + + if(len < maxlen) + maxlen = len; + + memcpy(buf, line, maxlen); + + line += maxlen; + + return maxlen; +} + +void shell_fini() { + device = NULL; +} + +int shell_source(const char *filename) { + shell_exit = 0; + + FILE *file = fopen(filename, "r"); + + if(file == NULL) { + return -1; + } + + char *line; + + while((line = fgets(linebuf, sizeof(linebuf), file)) && !shell_exit) { + if(shell_execute(line) == -1) { + fclose(file); + + return -1; + } + } + + fclose(file); + + return 0; +} + +void shell_interactive() { + shell_exit = 0; + +#ifndef WITH_READLINE + char *line; + + while(1) { + fputs("jzboot> ", stdout); + fflush(stdout); + + line = fgets(linebuf, sizeof(linebuf), stdin); + + if(line == NULL) + break; + + shell_execute(line); + } +#else + + rl_set_signals(); + + while(!shell_exit) { + char *line = readline("jzboot> "); + + if(line == NULL) { + printf("line null, EOP\n"); + break; + } + + add_history(line); + + shell_execute(line); + + free(line); + } + + rl_clear_signals(); +#endif +} + +static int builtin_help(int argc, char *argv[]) { + for(int i = 0; commands[i].cmd != NULL; i++) { + printf("%s %s\n", commands[i].cmd, commands[i].description); + } + + if(set_cmds) { + for(int i = 0; set_cmds[i].cmd != NULL; i++) + printf("%s %s\n", set_cmds[i].cmd, set_cmds[i].description); + } + + return 0; +} + +static int builtin_exit(int argc, char *argv[]) { + shell_exit = 1; + + return 0; +} + +static int builtin_source(int argc, char *argv[]) { + if(argc < 2) { + printf("Usage: %s \n", argv[0]); + + return -1; + } + + int ret = shell_source(argv[1]); + + shell_exit = 0; + + return ret; +} + +static int builtin_echo(int argc, char *argv[]) { + if(argc < 2) { + printf("Usage: %s \n", argv[0]); + + return -1; + } + + puts(argv[1]); + + return 0; +} + +static int builtin_redetect(int argc, char *argv[]) { + if(ingenic_redetect(device) == -1) { + perror("ingenic_redetect"); + + return -1; + } else + return 0; +} + + +static int builtin_set(int argc, char *argv[]) { + if(argc == 1 && 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(int argc, char *argv[]) { + return ingenic_rebuild(device); +} + +static const struct { + int set; + const char *name; + const shell_command_t *commands; +} cmdsets[] = { + { CMDSET_SPL, "SPL", spl_cmdset }, + { 0, NULL, NULL } +}; + +static void shell_update_cmdset(void *arg) { + set_cmds = NULL; + + int set = ingenic_cmdset(device); + + for(int i = 0; cmdsets[i].name != NULL; i++) { + if(cmdsets[i].set == set) { + printf("Shell: using command set '%s', run 'help' for command list. CPU: %04X\n", cmdsets[i].name, ingenic_type(device)); + + set_cmds = cmdsets[i].commands; + + return; + } + } + + debug(LEVEL_ERROR, "Shell: unknown cmdset %d\n", set); +} + +void *shell_device() { + return device; +} diff --git a/shell.h b/shell.h new file mode 100644 index 0000000..6a7b429 --- /dev/null +++ b/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__ + +typedef struct { + const char *cmd; + const char *description; + int (*handler)(int argc, char *argv[]); +} shell_command_t; + +int shell_init(void *ingenic); +void shell_fini(); + +void shell_interactive(); +int shell_source(const char *filename); +int shell_execute(const char *input); + +void *shell_device(); + +// lexer interface +extern char *strval; + +#define TOK_SEPARATOR 1 +#define TOK_STRING 2 +#define TOK_SPACE 3 +#define TOK_COMMENT 4 + +int shell_pull(char *buf, int maxlen); + +extern const shell_command_t spl_cmdset[]; + +#endif diff --git a/shell_lex.c b/shell_lex.c new file mode 100644 index 0000000..eea7de3 --- /dev/null +++ b/shell_lex.c @@ -0,0 +1,1793 @@ +#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) + +/* 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 (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 (((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 ) + +#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 + +extern int yyleng; + +extern FILE *yyin, *yyout; + +#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 = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (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, (yytext_ptr) ) + +#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 */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ + +/* 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 ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(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 (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart (FILE *input_file ); +void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); +void yy_delete_buffer (YY_BUFFER_STATE b ); +void yy_flush_buffer (YY_BUFFER_STATE b ); +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); +void yypop_buffer_state (void ); + +static void yyensure_buffer_stack (void ); +static void yy_load_buffer_state (void ); +static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); + +#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); +YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ); + +void *yyalloc (yy_size_t ); +void *yyrealloc (void *,yy_size_t ); +void yyfree (void * ); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + 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; + +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; + +typedef int yy_state_type; + +extern int yylineno; + +int yylineno = 1; + +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state (void ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); +static int yy_get_next_buffer (void ); +static void yy_fatal_error (yyconst char msg[] ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (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 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +extern int yy_flex_debug; +int yy_flex_debug = 0; + +/* 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 +char *yytext; +#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.h" +#include +#include + +#define YY_INPUT(buf, result, max_size) result = shell_pull(buf, max_size); + +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 512 "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 + +static int yy_init_globals (void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy (void ); + +int yyget_debug (void ); + +void yyset_debug (int debug_flag ); + +YY_EXTRA_TYPE yyget_extra (void ); + +void yyset_extra (YY_EXTRA_TYPE user_defined ); + +FILE *yyget_in (void ); + +void yyset_in (FILE * in_str ); + +FILE *yyget_out (void ); + +void yyset_out (FILE * out_str ); + +int yyget_leng (void ); + +char *yyget_text (void ); + +int yyget_lineno (void ); + +void yyset_lineno (int line_number ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap (void ); +#else +extern int yywrap (void ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (void ); +#else +static int input (void ); +#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 ) +#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 (void); + +#define YY_DECL int yylex (void) +#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; + +#line 45 "shell_lex.l" + +#line 700 "shell_lex.c" + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); + } + + yy_load_buffer_state( ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of yytext. */ + *yy_cp = (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 = (yy_start); +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (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 = (yy_last_accepting_cpos); + yy_current_state = (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 = (yy_hold_char); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 46 "shell_lex.l" +{ strval = NULL; BEGIN(STR); } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 47 "shell_lex.l" +return TOK_SEPARATOR; + YY_BREAK +case 3: +/* rule 3 can match eol */ +YY_RULE_SETUP +#line 48 "shell_lex.l" +return TOK_SPACE; + YY_BREAK +case 4: +YY_RULE_SETUP +#line 49 "shell_lex.l" +return TOK_COMMENT; + YY_BREAK +case 5: +YY_RULE_SETUP +#line 50 "shell_lex.l" +{ strval = strdup(yytext); return TOK_STRING; } + YY_BREAK +case 6: +/* rule 6 can match eol */ +YY_RULE_SETUP +#line 51 "shell_lex.l" +strval = str_append(strval, yytext); + YY_BREAK +case 7: +YY_RULE_SETUP +#line 52 "shell_lex.l" +strval = str_append(strval, "\""); + YY_BREAK +case 8: +YY_RULE_SETUP +#line 53 "shell_lex.l" +strval = str_append(strval, "\\"); + YY_BREAK +case 9: +YY_RULE_SETUP +#line 54 "shell_lex.l" +{ BEGIN(INITIAL); return TOK_STRING; } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 55 "shell_lex.l" +ECHO; + YY_BREAK +#line 831 "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 - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (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. + */ + (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 ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* 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 ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( yywrap( ) ) + { + /* 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. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (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 (void) +{ + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = (yytext_ptr); + register int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(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 ( (yy_c_buf_p) - (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) ((yy_c_buf_p) - (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 = (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) ((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 ); + } + 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" ); + + (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]), + (yy_n_chars), (size_t) num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart(yyin ); + } + + 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) ((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 = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (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 (void) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = (yy_start); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (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] ) + { + (yy_last_accepting_state) = yy_current_state; + (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 ) +{ + register int yy_is_jam; + register char *yy_cp = (yy_c_buf_p); + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (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 (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(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 ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + int offset = (yy_c_buf_p) - (yytext_ptr); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + 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 ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( ) ) + return EOF; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve yytext */ + (yy_hold_char) = *++(yy_c_buf_p); + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); + } + + yy_init_buffer(YY_CURRENT_BUFFER,input_file ); + yy_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( ); + + /* 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. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void yy_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(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. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); + 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 ); + 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 ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * + */ + void yy_delete_buffer (YY_BUFFER_STATE b ) +{ + + 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 ); + + yyfree((void *) b ); +} + +#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 ) + +{ + int oerrno = errno; + + yy_flush_buffer(b ); + + 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. + * + */ + void yy_flush_buffer (YY_BUFFER_STATE b ) +{ + 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( ); +} + +/** 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. + * + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void yypop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( ); + (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 (void) +{ + int num_to_alloc; + + if (!(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; + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (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 + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) +{ + 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 ) ); + 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 ); + + 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 + * + * @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 ) +{ + + return yy_scan_bytes(yystr,strlen(yystr) ); +} + +/** 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. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len ) +{ + 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 ); + 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 ); + 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 ) +{ + (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] = (yy_hold_char); \ + (yy_c_buf_p) = yytext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int yyget_lineno (void) +{ + + return yylineno; +} + +/** Get the input stream. + * + */ +FILE *yyget_in (void) +{ + return yyin; +} + +/** Get the output stream. + * + */ +FILE *yyget_out (void) +{ + return yyout; +} + +/** Get the length of the current token. + * + */ +int yyget_leng (void) +{ + return yyleng; +} + +/** Get the current token. + * + */ + +char *yyget_text (void) +{ + return yytext; +} + +/** Set the current line number. + * @param line_number + * + */ +void yyset_lineno (int line_number ) +{ + + yylineno = line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * in_str ) +{ + yyin = in_str ; +} + +void yyset_out (FILE * out_str ) +{ + yyout = out_str ; +} + +int yyget_debug (void) +{ + return yy_flex_debug; +} + +void yyset_debug (int bdebug ) +{ + yy_flex_debug = bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + (yy_buffer_stack) = 0; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = (char *) 0; + (yy_init) = 0; + (yy_start) = 0; + +/* 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 (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(); + } + + /* Destroy the stack itself. */ + yyfree((yy_buffer_stack) ); + (yy_buffer_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( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ + 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 ) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size ) +{ + return (void *) malloc( size ); +} + +void *yyrealloc (void * ptr, yy_size_t size ) +{ + /* 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 ) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 55 "shell_lex.l" diff --git a/shell_lex.l b/shell_lex.l new file mode 100644 index 0000000..240b1ef --- /dev/null +++ b/shell_lex.l @@ -0,0 +1,54 @@ +/* + * 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.h" +#include +#include + +#define YY_INPUT(buf, result, max_size) result = shell_pull(buf, max_size); + +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 + +%x STR +%% +["] { strval = NULL; BEGIN(STR); } +; return TOK_SEPARATOR; +[[:space:]]+ return TOK_SPACE; +[#] return TOK_COMMENT; +[^[:space:];"#]+ { strval = strdup(yytext); return TOK_STRING; } +[^\\"]+ strval = str_append(strval, yytext); +\\["] strval = str_append(strval, "\""); +\\ strval = str_append(strval, "\\"); +["] { BEGIN(INITIAL); return TOK_STRING; } diff --git a/spl_cmdset.c b/spl_cmdset.c new file mode 100644 index 0000000..c26d3f3 --- /dev/null +++ b/spl_cmdset.c @@ -0,0 +1,39 @@ +/* + * 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 "shell.h" +#include "config.h" +#include "ingenic.h" + +static int spl_memtest(int argc, char *argv[]); + +const shell_command_t spl_cmdset[] = { + { "memtest", "[BASE ] - SDRAM test", spl_memtest }, + { NULL, NULL, NULL } +}; + +static int spl_memtest(int argc, char *argv[]) { + if(argc != 1 && argc != 3) { + printf("Usage: %s [BASE ]\n", argv[0]); + } + + return ingenic_loadstage(shell_device(), INGENIC_STAGE1, cfg_getenv("STAGE1_FILE")); +} diff --git a/usbdev.c b/usbdev.c new file mode 100644 index 0000000..d8b10a5 --- /dev/null +++ b/usbdev.c @@ -0,0 +1,216 @@ +/* + * 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 "usbdev.h" +#include "debug.h" +#include "devmgr.h" + +#define CONTROL_TIMEOUT 1000 + +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); + + return translate_libusb(libusb_bulk_transfer(hndl, ENDPOINT_OUT, data, size, &trans, CONTROL_TIMEOUT)); +} + +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; +} diff --git a/usbdev.h b/usbdev.h new file mode 100644 index 0000000..772308e --- /dev/null +++ b/usbdev.h @@ -0,0 +1,36 @@ +/* + * 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 __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); + +#endif From 3851d0db665be36484a975ff6cbd1fec49f6c041 Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Sat, 4 Dec 2010 04:15:25 +0300 Subject: [PATCH 02/50] Show an error if a file cannot be sourced. --- shell.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/shell.c b/shell.c index 66dc964..c05e7a4 100644 --- a/shell.c +++ b/shell.c @@ -1,6 +1,7 @@ /* * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. - * Copyright (C) 2010 Sergey Gridassov + * 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 @@ -299,6 +300,10 @@ static int builtin_source(int argc, char *argv[]) { int ret = shell_source(argv[1]); + if(ret == -1) { + printf("Error while sourcing file %s\n", argv[1]); + } + shell_exit = 0; return ret; From db010b1855fb6fce3e5f60ef14d98f89a85bd208 Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Sat, 4 Dec 2010 04:36:25 +0300 Subject: [PATCH 03/50] Add support for booting of stage2. --- ingenic.c | 24 ++++++++++++++++++++++-- ingenic.h | 1 + initial.cfg | 3 ++- spl_cmdset.c | 26 ++++++++++++++++++++++++-- 4 files changed, 49 insertions(+), 5 deletions(-) diff --git a/ingenic.c b/ingenic.c index 63e4a08..61cc020 100644 --- a/ingenic.c +++ b/ingenic.c @@ -1,6 +1,7 @@ /* * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. - * Copyright (C) 2010 Sergey Gridassov + * 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 @@ -36,6 +37,7 @@ typedef struct { void *usb; uint32_t type; + uint32_t total_sdram_size; const ingenic_callbacks_t *callbacks; void *callbacks_data; @@ -200,7 +202,10 @@ int ingenic_rebuild(void *hndl) { CFGOPT("START", start, 1); CFGOPT("SIZE", size, 1); - + 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); debug(LEVEL_DEBUG, "Firmware configuration dump:\n"); @@ -234,6 +239,12 @@ int ingenic_loadstage(void *hndl, int id, const char *file) { break; + case INGENIC_STAGE2: + base = SDRAM_BASE + handle->total_sdram_size - STAGE2_CODESIZE; + cmd = VR_PROGRAM_START2; + + break; + default: errno = EINVAL; @@ -275,6 +286,15 @@ int ingenic_loadstage(void *hndl, int id, const char *file) { debug(LEVEL_DEBUG, "Ingenic: stage written\n"); + if(id == INGENIC_STAGE2) { + debug(LEVEL_DEBUG, "Ingenic: flushing cache\n"); + + ret = usbdev_vendor(handle->usb, USBDEV_TODEV, VR_FLUSH_CACHES, 0, 0, 0, 0); + + if(ret == -1) + return -1; + } + debug(LEVEL_DEBUG, "Starting stage!\n"); ret = usbdev_vendor(handle->usb, USBDEV_TODEV, cmd, (base >> 16), base & 0xFFFF, 0, 0); diff --git a/ingenic.h b/ingenic.h index 32f2ea4..f9a280e 100644 --- a/ingenic.h +++ b/ingenic.h @@ -39,6 +39,7 @@ int ingenic_loadstage(void *hndl, int id, const char *filename); #define INGENIC_STAGE2 2 #define STAGE1_BASE 0x2000 +#define STAGE2_CODESIZE 0x400000 #define SDRAM_BASE 0x80000000 typedef struct { diff --git a/initial.cfg b/initial.cfg index 19aef7d..6a15eac 100644 --- a/initial.cfg +++ b/initial.cfg @@ -1,7 +1,8 @@ # Configuration variables: -# STAGE1_FILE +# STAGE1_FILE, STAGE2_FILE set STAGE1_FILE fw.bin +set STAGE2_FILE usb_boot.bin set EXTCLK 12 # Define the external crystal in MHz set CPUSPEED 252 # Define the PLL output frequency diff --git a/spl_cmdset.c b/spl_cmdset.c index c26d3f3..813e9d6 100644 --- a/spl_cmdset.c +++ b/spl_cmdset.c @@ -1,6 +1,7 @@ /* * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. - * Copyright (C) 2010 Sergey Gridassov + * 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 @@ -24,16 +25,37 @@ #include "ingenic.h" static int spl_memtest(int argc, char *argv[]); +static int spl_boot(int argc, char *argv[]); const shell_command_t spl_cmdset[] = { { "memtest", "[BASE ] - SDRAM test", spl_memtest }, + { "boot", " - Load stage2 USB bootloader", spl_boot }, { NULL, NULL, NULL } }; +static int spl_load_stage1() { + return ingenic_loadstage(shell_device(), INGENIC_STAGE1, cfg_getenv("STAGE1_FILE")); +} + static int spl_memtest(int argc, char *argv[]) { if(argc != 1 && argc != 3) { printf("Usage: %s [BASE ]\n", argv[0]); } - return ingenic_loadstage(shell_device(), INGENIC_STAGE1, cfg_getenv("STAGE1_FILE")); + return spl_load_stage1(); // TODO +} + +static int spl_boot(int argc, char *argv[]) { + if(argc != 1) { + printf("Usage: %s\n", argv[0]); + } + + int ret; + + ret = spl_load_stage1(); + + if(ret == -1) + return -1; + + return ingenic_loadstage(shell_device(), INGENIC_STAGE2, cfg_getenv("STAGE2_FILE")); } From 5cc2d7446f00021255d7c94322ae20100ac84a78 Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Sat, 4 Dec 2010 04:38:59 +0300 Subject: [PATCH 04/50] Make exit command work without readline. --- shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell.c b/shell.c index c05e7a4..9bd85ee 100644 --- a/shell.c +++ b/shell.c @@ -238,7 +238,7 @@ void shell_interactive() { #ifndef WITH_READLINE char *line; - while(1) { + while(!shell_exit) { fputs("jzboot> ", stdout); fflush(stdout); From 5639e64034b7abc2aae1f028fb27b82ab5646a59 Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Sat, 4 Dec 2010 04:46:29 +0300 Subject: [PATCH 05/50] Improve error condition handling. --- ingenic.c | 5 ++++- shell.c | 20 ++++++++++++++++++-- spl_cmdset.c | 12 ++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/ingenic.c b/ingenic.c index 61cc020..5ed4921 100644 --- a/ingenic.c +++ b/ingenic.c @@ -253,8 +253,11 @@ int ingenic_loadstage(void *hndl, int id, const char *file) { FILE *fd = fopen(file, "rb"); - if(fd == NULL) + if(fd == NULL) { + debug(LEVEL_ERROR, "Ingenic: cannot load file `%s'\n", file); + return -1; + } fseek(fd, 0, SEEK_END); int size = ftell(fd); diff --git a/shell.c b/shell.c index 9bd85ee..b387a9e 100644 --- a/shell.c +++ b/shell.c @@ -292,7 +292,7 @@ static int builtin_exit(int argc, char *argv[]) { } static int builtin_source(int argc, char *argv[]) { - if(argc < 2) { + if(argc != 2) { printf("Usage: %s \n", argv[0]); return -1; @@ -322,6 +322,12 @@ static int builtin_echo(int argc, char *argv[]) { } static int builtin_redetect(int argc, char *argv[]) { + if(argc != 1) { + printf("Usage: %s\n", argv[0]); + + return -1; + } + if(ingenic_redetect(device) == -1) { perror("ingenic_redetect"); @@ -339,9 +345,13 @@ static int builtin_set(int argc, char *argv[]) { } else if(argc == 2) { cfg_unsetenv(argv[1]); - } else if(argc >= 3) { + } else if(argc == 3) { cfg_setenv(argv[1], argv[2]); + } else { + printf("Usage: %s [VARIABLE] [VALUE]\n", argv[0]); + + return -1; } return 0; @@ -349,6 +359,12 @@ static int builtin_set(int argc, char *argv[]) { static int builtin_rebuildcfg(int argc, char *argv[]) { + if(argc != 1) { + printf("Usage: %s\n", argv[0]); + + return -1; + } + return ingenic_rebuild(device); } diff --git a/spl_cmdset.c b/spl_cmdset.c index 813e9d6..8b9fe53 100644 --- a/spl_cmdset.c +++ b/spl_cmdset.c @@ -34,6 +34,12 @@ const shell_command_t spl_cmdset[] = { }; static int spl_load_stage1() { + if(cfg_getenv("STAGE1_FILE") == NULL) { + printf("Variable STAGE1_FILE is not set\n"); + + return -1; + } + return ingenic_loadstage(shell_device(), INGENIC_STAGE1, cfg_getenv("STAGE1_FILE")); } @@ -57,5 +63,11 @@ static int spl_boot(int argc, char *argv[]) { if(ret == -1) return -1; + if(cfg_getenv("STAGE2_FILE") == NULL) { + printf("Variable STAGE2_FILE is not set\n"); + + return -1; + } + return ingenic_loadstage(shell_device(), INGENIC_STAGE2, cfg_getenv("STAGE2_FILE")); } From 1b01185cbb03dd918f10eab6dfaa06220c65925f Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Sat, 4 Dec 2010 04:51:45 +0300 Subject: [PATCH 06/50] Add USB bootloader stage2 firmware. --- COPYING | 2 +- usb_boot.bin | Bin 0 -> 32276 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 usb_boot.bin diff --git a/COPYING b/COPYING index b438b7f..78d994c 100644 --- a/COPYING +++ b/COPYING @@ -1,4 +1,4 @@ -fw.bin is (c) Ingenic Semiconductor Co., Ltd. +fw.bin, usb_boot.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/usb_boot.bin b/usb_boot.bin new file mode 100644 index 0000000000000000000000000000000000000000..56eabed9ff4da73db8204e5671d3d452b642c53d GIT binary patch literal 32276 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 Date: Sat, 4 Dec 2010 05:07:30 +0300 Subject: [PATCH 07/50] Add sleep command to shell. --- shell.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/shell.c b/shell.c index b387a9e..bbe24e6 100644 --- a/shell.c +++ b/shell.c @@ -24,6 +24,7 @@ #include #endif #include +#include #include #include "shell.h" @@ -42,6 +43,7 @@ static int builtin_help(int argc, char *argv[]); static int builtin_exit(int argc, char *argv[]); static int builtin_source(int argc, char *argv[]); static int builtin_echo(int argc, char *argv[]); +static int builtin_sleep(int argc, char *argv[]); static int builtin_redetect(int argc, char *argv[]); static int builtin_rebuildcfg(int argc, char *argv[]); static int builtin_set(int argc, char *argv[]); @@ -51,6 +53,7 @@ static const shell_command_t commands[] = { { "exit", "- Batch: stop current script, interactive: end session", builtin_exit }, { "source", " - run specified script", builtin_source }, { "echo", " - output specified string", builtin_echo }, + { "sleep", " - sleep a specified amount of time", builtin_sleep }, { "set", "[VARIABLE] [VALUE] - print or set configuraton variables", builtin_set }, { "redetect", " - Redetect CPU", builtin_redetect }, @@ -321,6 +324,20 @@ static int builtin_echo(int argc, char *argv[]) { return 0; } +static int builtin_sleep(int argc, char *argv[]) { + if(argc != 2) { + printf("Usage: %s \n", argv[0]); + + return -1; + } + + uint32_t ms = atoi(argv[1]); + + usleep(ms * 1000); + + return 0; +} + static int builtin_redetect(int argc, char *argv[]) { if(argc != 1) { printf("Usage: %s\n", argv[0]); From 4f6670e5af2e3eea457d48d8e4888b712fdcf5ad Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Sat, 4 Dec 2010 05:17:56 +0300 Subject: [PATCH 08/50] Fix echo shell command to print all arguments. --- shell.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/shell.c b/shell.c index bbe24e6..524de3a 100644 --- a/shell.c +++ b/shell.c @@ -319,7 +319,16 @@ static int builtin_echo(int argc, char *argv[]) { return -1; } - puts(argv[1]); + for(int i = 1; i < argc; i++) { + printf("%s", argv[i]); + + if(i < argc - 1) { + printf(" "); + + } else { + printf("\n"); + } + } return 0; } From 5d8f35d88e448840bb431ab98ddd73223b6cf04c Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Sat, 4 Dec 2010 06:43:15 +0300 Subject: [PATCH 09/50] Add USBBoot cmdset skeleton. --- Makefile | 2 +- shell.c | 3 ++- shell.h | 1 + usbboot_cmdset.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 usbboot_cmdset.c diff --git a/Makefile b/Makefile index b664f86..87f5e00 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ endif CC = gcc TARGET = jzboot -SOURCES = debug.c devmgr.c ingenic.c main.c shell_lex.c usbdev.c shell.c config.c spl_cmdset.c +SOURCES = debug.c devmgr.c ingenic.c main.c shell_lex.c usbdev.c shell.c config.c spl_cmdset.c usbboot_cmdset.c CFLAGS = --std=gnu99 -Wall -Werror -O2 $(shell pkg-config libusb-1.0 --cflags) LIBS += $(shell pkg-config libusb-1.0 --libs) diff --git a/shell.c b/shell.c index 524de3a..d86e1c1 100644 --- a/shell.c +++ b/shell.c @@ -399,7 +399,8 @@ static const struct { const char *name; const shell_command_t *commands; } cmdsets[] = { - { CMDSET_SPL, "SPL", spl_cmdset }, + { CMDSET_SPL, "SPL", spl_cmdset }, + { CMDSET_USBBOOT, "USBBoot", usbboot_cmdset }, { 0, NULL, NULL } }; diff --git a/shell.h b/shell.h index 6a7b429..0f11518 100644 --- a/shell.h +++ b/shell.h @@ -45,5 +45,6 @@ extern char *strval; int shell_pull(char *buf, int maxlen); extern const shell_command_t spl_cmdset[]; +extern const shell_command_t usbboot_cmdset[]; #endif diff --git a/usbboot_cmdset.c b/usbboot_cmdset.c new file mode 100644 index 0000000..221c73c --- /dev/null +++ b/usbboot_cmdset.c @@ -0,0 +1,28 @@ +/* + * 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 "shell.h" +#include "config.h" +#include "ingenic.h" + +const shell_command_t usbboot_cmdset[] = { + { NULL, NULL, NULL } +}; From 8c36acee575ceaf4d395d76c23e93f312d2e5275 Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Sat, 4 Dec 2010 07:01:21 +0300 Subject: [PATCH 10/50] Implement GPIO changing with SPL commands. --- ingenic.h | 4 ++++ spl_cmdset.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/ingenic.h b/ingenic.h index f9a280e..0432301 100644 --- a/ingenic.h +++ b/ingenic.h @@ -38,6 +38,10 @@ int ingenic_loadstage(void *hndl, int id, const char *filename); #define INGENIC_STAGE1 1 #define INGENIC_STAGE2 2 +#define SPL_DEBUG_MEMTEST "1" +#define SPL_DEBUG_GPIO_SET "2" +#define SPL_DEBUG_GPIO_CLEAR "3" + #define STAGE1_BASE 0x2000 #define STAGE2_CODESIZE 0x400000 #define SDRAM_BASE 0x80000000 diff --git a/spl_cmdset.c b/spl_cmdset.c index 8b9fe53..0d37a2b 100644 --- a/spl_cmdset.c +++ b/spl_cmdset.c @@ -19,16 +19,19 @@ #include #include +#include #include "shell.h" #include "config.h" #include "ingenic.h" static int spl_memtest(int argc, char *argv[]); +static int spl_gpio(int argc, char *argv[]); static int spl_boot(int argc, char *argv[]); const shell_command_t spl_cmdset[] = { { "memtest", "[BASE ] - SDRAM test", spl_memtest }, + { "gpio", " - Set GPIO #PIN to STATE 0 or 1", spl_gpio }, { "boot", " - Load stage2 USB bootloader", spl_boot }, { NULL, NULL, NULL } }; @@ -51,6 +54,40 @@ static int spl_memtest(int argc, char *argv[]) { return spl_load_stage1(); // TODO } +static int spl_gpio(int argc, char *argv[]) { + if(argc != 3 || (strcmp(argv[2], "0") && strcmp(argv[2], "1"))) { + printf("Usage: %s \n", argv[0]); + printf(" STATE := 0 | 1\n"); + + return -1; + } + + char *old_debugops = strdup(cfg_getenv("DEBUGOPS")), + *old_pinnum = strdup(cfg_getenv("PINNUM")); + + cfg_setenv("DEBUGOPS", (!strcmp(argv[2], "1")) ? + SPL_DEBUG_GPIO_SET : SPL_DEBUG_GPIO_CLEAR); + cfg_setenv("PINNUM", argv[1]); + + int ret = 0; + + ret = shell_execute("rebuildcfg"); + + if(ret == -1) + goto finally; + + ret = spl_load_stage1(); + +finally: + cfg_setenv("DEBUGOPS", old_debugops); + cfg_setenv("PINNUM", old_pinnum); + + free(old_debugops); + free(old_pinnum); + + return ret; +} + static int spl_boot(int argc, char *argv[]) { if(argc != 1) { printf("Usage: %s\n", argv[0]); From ba795ac17d369b9a4d82a81deb7639a416f80777 Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Sat, 4 Dec 2010 07:23:33 +0300 Subject: [PATCH 11/50] Add the code needed to launch memtest. --- ingenic.c | 4 ++++ spl_cmdset.c | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/ingenic.c b/ingenic.c index 5ed4921..7c1da6d 100644 --- a/ingenic.c +++ b/ingenic.c @@ -207,6 +207,10 @@ int ingenic_rebuild(void *hndl) { * (handle->cfg.bank_num + 1) * 2 * (2 - handle->cfg.bus_width); + char tmp[20]; + snprintf(tmp, 20, "%d", handle->total_sdram_size); + cfg_setenv("SDRAM_SIZE", tmp); + debug(LEVEL_DEBUG, "Firmware configuration dump:\n"); hexdump(&handle->cfg, sizeof(firmware_config_t)); diff --git a/spl_cmdset.c b/spl_cmdset.c index 0d37a2b..dbf83ba 100644 --- a/spl_cmdset.c +++ b/spl_cmdset.c @@ -49,9 +49,47 @@ static int spl_load_stage1() { static int spl_memtest(int argc, char *argv[]) { if(argc != 1 && argc != 3) { printf("Usage: %s [BASE ]\n", argv[0]); + + return -1; } - return spl_load_stage1(); // TODO + char *old_debugops = strdup(cfg_getenv("DEBUGOPS")), + *old_start = strdup(cfg_getenv("PINNUM")), + *old_size = strdup(cfg_getenv("SIZE")); + + cfg_setenv("DEBUGOPS", SPL_DEBUG_MEMTEST); + + if(argc == 3) { + cfg_setenv("START", argv[1]); + cfg_setenv("SIZE", argv[2]); + + } else { + char tmp[20]; + snprintf(tmp, 20, "%d", SDRAM_BASE); + + cfg_setenv("START", tmp); + cfg_setenv("SIZE", cfg_getenv("SDRAM_SIZE")); + } + + int ret = 0; + + ret = shell_execute("rebuildcfg"); + + if(ret == -1) + goto finally; + + ret = spl_load_stage1(); + +finally: + cfg_setenv("DEBUGOPS", old_debugops); + cfg_setenv("START", old_start); + cfg_setenv("SIZE", old_size); + + free(old_debugops); + free(old_start); + free(old_size); + + return ret; } static int spl_gpio(int argc, char *argv[]) { From 0f35fd7a47583f9435e62a19acb797719d09ca65 Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Sat, 4 Dec 2010 07:25:17 +0300 Subject: [PATCH 12/50] Add bulk receive code to USB abstraction. --- usbdev.c | 11 ++++++++++- usbdev.h | 4 +++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/usbdev.c b/usbdev.c index d8b10a5..ebda583 100644 --- a/usbdev.c +++ b/usbdev.c @@ -1,6 +1,7 @@ /* * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. - * Copyright (C) 2010 Sergey Gridassov + * 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 @@ -143,6 +144,14 @@ int usbdev_sendbulk(void *hndl, void *data, int size) { return translate_libusb(libusb_bulk_transfer(hndl, ENDPOINT_OUT, data, size, &trans, CONTROL_TIMEOUT)); } +int usbdev_recvbulk(void *hndl, void *data, int size) { + int trans; + + debug(LEVEL_DEBUG, "Bulk: reading data %p, size %d\n", data, size); + + return translate_libusb(libusb_bulk_transfer(hndl, ENDPOINT_IN, data, size, &trans, CONTROL_TIMEOUT)); +} + static int translate_libusb(int code) { switch(code) { case LIBUSB_SUCCESS: diff --git a/usbdev.h b/usbdev.h index 772308e..6bc24d1 100644 --- a/usbdev.h +++ b/usbdev.h @@ -1,6 +1,7 @@ /* * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. - * Copyright (C) 2010 Sergey Gridassov + * 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 @@ -32,5 +33,6 @@ 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 From 0bf753e06a747ad1f8274e0de32384b34da20382 Mon Sep 17 00:00:00 2001 From: Sergey Gridassov Date: Sat, 4 Dec 2010 10:45:49 +0300 Subject: [PATCH 13/50] Code cleanup --- ingenic.c | 32 +++++++++++++++++++++++--------- ingenic.h | 22 ++++++++++++++-------- initial.cfg | 7 ------- shell.c | 11 +++-------- spl_cmdset.c | 48 +++++++++++++++++------------------------------- 5 files changed, 57 insertions(+), 63 deletions(-) diff --git a/ingenic.c b/ingenic.c index 5ed4921..2b96e75 100644 --- a/ingenic.c +++ b/ingenic.c @@ -180,7 +180,7 @@ void ingenic_close(void *hndl) { int ingenic_rebuild(void *hndl) { HANDLE; - handle->cfg.cpu_id = 0x4750; //CPUID(handle->type); + handle->cfg.cpu_id = CPUID(handle->type); CFGOPT("EXTCLK", ext_clk, v <= 27 && v >= 12); CFGOPT("CPUSPEED", cpu_speed, (v % 12) == 0); @@ -197,10 +197,8 @@ int ingenic_rebuild(void *hndl) { CFGOPT("SDRAM_COLADDR", col_addr, 1); CFGOPT("SDRAM_ISMOBILE", is_mobile, v == 0 || v == 1); CFGOPT("SDRAM_ISBUSSHARE", is_busshare, v == 0 || v == 1); - CFGOPT("DEBUGOPS", debug_ops, 1); - CFGOPT("PINNUM", pin_num, 1); - CFGOPT("START", start, 1); - CFGOPT("SIZE", size, 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 @@ -220,6 +218,24 @@ static int ingenic_address(void *usb, uint32_t base) { return usbdev_vendor(usb, USBDEV_TODEV, VR_SET_DATA_ADDRESS, (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; + + debug(LEVEL_DEBUG, "Debug configuration dump:\n"); + hexdump(&handle->cfg, sizeof(firmware_config_t)); + + 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; @@ -253,11 +269,8 @@ int ingenic_loadstage(void *hndl, int id, const char *file) { FILE *fd = fopen(file, "rb"); - if(fd == NULL) { - debug(LEVEL_ERROR, "Ingenic: cannot load file `%s'\n", file); - + if(fd == NULL) return -1; - } fseek(fd, 0, SEEK_END); int size = ftell(fd); @@ -307,3 +320,4 @@ int ingenic_loadstage(void *hndl, int id, const char *file) { return ingenic_redetect(hndl); } + diff --git a/ingenic.h b/ingenic.h index 0432301..44e12ff 100644 --- a/ingenic.h +++ b/ingenic.h @@ -31,6 +31,7 @@ int ingenic_type(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); #define CMDSET_SPL 1 #define CMDSET_USBBOOT 2 @@ -38,14 +39,23 @@ int ingenic_loadstage(void *hndl, int id, const char *filename); #define INGENIC_STAGE1 1 #define INGENIC_STAGE2 2 -#define SPL_DEBUG_MEMTEST "1" -#define SPL_DEBUG_GPIO_SET "2" -#define SPL_DEBUG_GPIO_CLEAR "3" +#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 +typedef struct { + /* debug args */ + uint8_t debug_ops; + uint8_t pin_num; + uint32_t start; + uint32_t size; +} ingenic_stage1_debug_t; + typedef struct { /* CPU ID */ uint32_t cpu_id; @@ -65,11 +75,7 @@ typedef struct { uint8_t is_mobile; uint8_t is_busshare; - /* debug args */ - uint8_t debug_ops; - uint8_t pin_num; - uint32_t start; - uint32_t size; + ingenic_stage1_debug_t debug; } __attribute__((packed)) firmware_config_t; #endif diff --git a/initial.cfg b/initial.cfg index 6a15eac..15c1c53 100644 --- a/initial.cfg +++ b/initial.cfg @@ -31,11 +31,4 @@ 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 -# DEBUG -set DEBUGOPS 0 -set PINNUM 0 -set START 0 -set SIZE 0 - - rebuildcfg diff --git a/shell.c b/shell.c index 524de3a..05c9101 100644 --- a/shell.c +++ b/shell.c @@ -304,7 +304,7 @@ static int builtin_source(int argc, char *argv[]) { int ret = shell_source(argv[1]); if(ret == -1) { - printf("Error while sourcing file %s\n", argv[1]); + fprintf(stderr, "Error while sourcing file %s: %s\n", argv[1], strerror(errno)); } shell_exit = 0; @@ -320,14 +320,9 @@ static int builtin_echo(int argc, char *argv[]) { } for(int i = 1; i < argc; i++) { - printf("%s", argv[i]); + fputs(argv[i], stdout); - if(i < argc - 1) { - printf(" "); - - } else { - printf("\n"); - } + putchar((i < argc - 1) ? ' ' : '\n'); } return 0; diff --git a/spl_cmdset.c b/spl_cmdset.c index 0d37a2b..56ed4da 100644 --- a/spl_cmdset.c +++ b/spl_cmdset.c @@ -36,14 +36,19 @@ const shell_command_t spl_cmdset[] = { { NULL, NULL, NULL } }; -static int spl_load_stage1() { +static int spl_stage1_op(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; } - return ingenic_loadstage(shell_device(), INGENIC_STAGE1, cfg_getenv("STAGE1_FILE")); + int ret = ingenic_stage1_debugop(shell_device(), cfg_getenv("STAGE1_FILE"), op, pin, base, size); + + if(ret == -1) + perror("ingenic_stage1_debugop"); + + return ret; } static int spl_memtest(int argc, char *argv[]) { @@ -51,7 +56,7 @@ static int spl_memtest(int argc, char *argv[]) { printf("Usage: %s [BASE ]\n", argv[0]); } - return spl_load_stage1(); // TODO + return spl_stage1_op(STAGE1_DEBUG_BOOT, 0, 0, 0); // TODO } static int spl_gpio(int argc, char *argv[]) { @@ -62,30 +67,7 @@ static int spl_gpio(int argc, char *argv[]) { return -1; } - char *old_debugops = strdup(cfg_getenv("DEBUGOPS")), - *old_pinnum = strdup(cfg_getenv("PINNUM")); - - cfg_setenv("DEBUGOPS", (!strcmp(argv[2], "1")) ? - SPL_DEBUG_GPIO_SET : SPL_DEBUG_GPIO_CLEAR); - cfg_setenv("PINNUM", argv[1]); - - int ret = 0; - - ret = shell_execute("rebuildcfg"); - - if(ret == -1) - goto finally; - - ret = spl_load_stage1(); - -finally: - cfg_setenv("DEBUGOPS", old_debugops); - cfg_setenv("PINNUM", old_pinnum); - - free(old_debugops); - free(old_pinnum); - - return ret; + return spl_stage1_op(!strcmp(argv[2], "1") ? STAGE1_DEBUG_GPIO_SET : STAGE1_DEBUG_GPIO_CLEAR, atoi(argv[1]), 0, 0); } static int spl_boot(int argc, char *argv[]) { @@ -93,9 +75,7 @@ static int spl_boot(int argc, char *argv[]) { printf("Usage: %s\n", argv[0]); } - int ret; - - ret = spl_load_stage1(); + int ret = spl_stage1_op(STAGE1_DEBUG_BOOT, 0, 0, 0); if(ret == -1) return -1; @@ -106,5 +86,11 @@ static int spl_boot(int argc, char *argv[]) { return -1; } - return ingenic_loadstage(shell_device(), INGENIC_STAGE2, cfg_getenv("STAGE2_FILE")); + ret = ingenic_loadstage(shell_device(), INGENIC_STAGE2, cfg_getenv("STAGE2_FILE")); + + if(ret == -1) + perror("ingenic_loadstage"); + + return ret; } + From cc2de4cf2672e81cc18e79c46b82d9850637181b Mon Sep 17 00:00:00 2001 From: Sergey Gridassov Date: Sat, 4 Dec 2010 10:56:51 +0300 Subject: [PATCH 14/50] Implemented ingenic_sdram_size --- fw.bin | Bin ingenic.c | 12 +++++++----- ingenic.h | 1 + 3 files changed, 8 insertions(+), 5 deletions(-) mode change 100755 => 100644 fw.bin diff --git a/fw.bin b/fw.bin old mode 100755 new mode 100644 diff --git a/ingenic.c b/ingenic.c index 2b96e75..8c6db8d 100644 --- a/ingenic.c +++ b/ingenic.c @@ -97,12 +97,8 @@ static void hexdump(const void *data, size_t size) { 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) { - if(errno == EFAULT) { - debug(LEVEL_DEBUG, "Stage detected\n"); - } else + if(usbdev_vendor(usb_hndl, USBDEV_FROMDEV, VR_GET_CPU_INFO, 0, 0, magic, 8) == -1) return 0; - } magic[8] = 0; @@ -212,6 +208,12 @@ int ingenic_rebuild(void *hndl) { return 0; } +uint32_t ingenic_sdram_size(void *hndl) { + HANDLE; + + return handle->total_sdram_size; +} + static int ingenic_address(void *usb, uint32_t base) { debug(LEVEL_DEBUG, "Ingenic: address 0x%08X\n", base); diff --git a/ingenic.h b/ingenic.h index 44e12ff..0588501 100644 --- a/ingenic.h +++ b/ingenic.h @@ -28,6 +28,7 @@ void ingenic_set_callbacks(void *hndl, const ingenic_callbacks_t *callbacks, voi 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); From 4a19dabdd4b7d8c44f9436051326ccaa60f91e52 Mon Sep 17 00:00:00 2001 From: Sergey Gridassov Date: Sat, 4 Dec 2010 12:35:49 +0300 Subject: [PATCH 15/50] Implemented nand configuration; increased command timeout; implemented stage2 configuration; implemented safe builtin; added boot.cfg --- boot.cfg | 5 +++++ ingenic.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ ingenic.h | 25 +++++++++++++++++++++- initial.cfg | 2 +- main.c | 5 +++++ shell.c | 15 +++++++++++++ spl_cmdset.c | 10 ++++++++- usbboot_cmdset.c | 14 ++++++++++++ usbdev.c | 2 +- 9 files changed, 129 insertions(+), 4 deletions(-) create mode 100644 boot.cfg diff --git a/boot.cfg b/boot.cfg new file mode 100644 index 0000000..8b1e865 --- /dev/null +++ b/boot.cfg @@ -0,0 +1,5 @@ +source initial.cfg + +safe memtest +boot + diff --git a/ingenic.c b/ingenic.c index 670a397..394a20d 100644 --- a/ingenic.c +++ b/ingenic.c @@ -43,6 +43,7 @@ typedef struct { void *callbacks_data; firmware_config_t cfg; + nand_config_t nand; } ingenic_handle_t; static const struct { @@ -173,6 +174,8 @@ void ingenic_close(void *hndl) { #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; }; handle->cfg.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; }; handle->nand.nand_##var = v; } + int ingenic_rebuild(void *hndl) { HANDLE; @@ -205,6 +208,27 @@ int ingenic_rebuild(void *hndl) { hexdump(&handle->cfg, sizeof(firmware_config_t)); + handle->nand.cpuid = CPUID(handle->type); + + NOPT("BUSWIDTH", bw, 1); + NOPT("ROWCYCLES", rc, 1); + NOPT("PAGESIZE", ps, 1); + NOPT("PAGEPERBLOCK", ppb, 1); + NOPT("FORCEERASE", force_erase, 1); +// FIXME: pn is not set by xburst-tools usbboot. Is this intended? + NOPT("OOBSIZE", os, 1); + NOPT("ECCPOS", eccpos, 1); + NOPT("BADBLOCKPOS", bbpos, 1); + NOPT("BADBLOCKPAGE", bbpage, 1); + NOPT("PLANENUM", plane, 1); + NOPT("BCHBIT", bchbit, 1); + NOPT("WPPIN", wppin, 1); + NOPT("BLOCKPERCHIP", bpc, 1); + + debug(LEVEL_DEBUG, "NAND configuration dump:\n"); + + hexdump(&handle->nand, sizeof(nand_config_t)); + return 0; } @@ -348,3 +372,34 @@ int ingenic_memtest(void *hndl, const char *filename, uint32_t base, uint32_t si 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; + + debug(LEVEL_DEBUG, "Stage2 configured\n"); + + return 0; +} + diff --git a/ingenic.h b/ingenic.h index aa3ea82..32c166c 100644 --- a/ingenic.h +++ b/ingenic.h @@ -35,6 +35,8 @@ 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); + #define CMDSET_SPL 1 #define CMDSET_USBBOOT 2 @@ -50,13 +52,15 @@ int ingenic_memtest(void *hndl, const char *filename, uint32_t base, uint32_t si #define STAGE2_CODESIZE 0x400000 #define SDRAM_BASE 0x80000000 +#define DS_flash_info 0 +#define DS_hand 1 typedef struct { /* debug args */ uint8_t debug_ops; uint8_t pin_num; uint32_t start; uint32_t size; -} ingenic_stage1_debug_t; +} __attribute__((packed)) ingenic_stage1_debug_t; typedef struct { /* CPU ID */ @@ -80,4 +84,23 @@ typedef struct { 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; + #endif diff --git a/initial.cfg b/initial.cfg index 15c1c53..924d485 100644 --- a/initial.cfg +++ b/initial.cfg @@ -24,7 +24,7 @@ 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 8 # Specify the ECC offset inside the oob data (0-[oobsize-1]) -set NAND_BADBLACKPOS 0 # Specify the badblock flag offset inside the oob (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) diff --git a/main.c b/main.c index 916abeb..663ab08 100644 --- a/main.c +++ b/main.c @@ -157,6 +157,10 @@ int main(int argc, char *argv[]) { if(config) if(shell_source(config) == -1) { perror("shell_source"); + + ret = 1; + + goto exit_shell; } if(cmd != NULL) { @@ -175,6 +179,7 @@ int main(int argc, char *argv[]) { } else shell_interactive(); +exit_shell: shell_fini(); exit_ingenic: diff --git a/shell.c b/shell.c index 80fe6ec..913e6e3 100644 --- a/shell.c +++ b/shell.c @@ -47,6 +47,7 @@ static int builtin_sleep(int argc, char *argv[]); static int builtin_redetect(int argc, char *argv[]); static int builtin_rebuildcfg(int argc, char *argv[]); static int builtin_set(int argc, char *argv[]); +static int builtin_safe(int argc, char *argv[]); static const shell_command_t commands[] = { { "help", "- Display this message", builtin_help }, @@ -55,6 +56,7 @@ static const shell_command_t commands[] = { { "echo", " - output specified string", builtin_echo }, { "sleep", " - sleep a specified amount of time", builtin_sleep }, { "set", "[VARIABLE] [VALUE] - print or set configuraton variables", builtin_set }, + { "safe", " [ARG]... - run command ignoring errors", builtin_safe }, { "redetect", " - Redetect CPU", builtin_redetect }, { "rebuildcfg", " - Rebuild firmware configuration data", builtin_rebuildcfg }, @@ -389,6 +391,19 @@ static int builtin_rebuildcfg(int argc, char *argv[]) { return ingenic_rebuild(device); } +static int builtin_safe(int argc, char *argv[]) { + if(argc < 2) { + printf("Usage: %s [ARG]...\n", argv[0]); + + return -1; + } + + if(shell_run(argc - 1, argv + 1) == -1) + perror("shell_run"); + + return 0; +} + static const struct { int set; const char *name; diff --git a/spl_cmdset.c b/spl_cmdset.c index 5782f64..86503e5 100644 --- a/spl_cmdset.c +++ b/spl_cmdset.c @@ -122,9 +122,17 @@ static int spl_boot(int argc, char *argv[]) { ret = ingenic_loadstage(shell_device(), INGENIC_STAGE2, cfg_getenv("STAGE2_FILE")); - if(ret == -1) + if(ret == -1) { perror("ingenic_loadstage"); + return -1; + } + + ret = ingenic_configure_stage2(shell_device()); + + if(ret == -1) + perror("ingenic_configure_stage2"); + return ret; } diff --git a/usbboot_cmdset.c b/usbboot_cmdset.c index 221c73c..298a86f 100644 --- a/usbboot_cmdset.c +++ b/usbboot_cmdset.c @@ -23,6 +23,20 @@ #include "config.h" #include "ingenic.h" +static int usbboot_boot(int argc, char *argv[]); + const shell_command_t usbboot_cmdset[] = { + { "boot", "- Reconfigure stage2", usbboot_boot }, + { NULL, NULL, NULL } }; + +static int usbboot_boot(int argc, char *argv[]) { + int ret = ingenic_configure_stage2(shell_device()); + + if(ret == -1) + perror("ingenic_configure_stage2"); + + return ret; +} + diff --git a/usbdev.c b/usbdev.c index ab2b95f..e2731c0 100644 --- a/usbdev.c +++ b/usbdev.c @@ -24,7 +24,7 @@ #include "debug.h" #include "devmgr.h" -#define CONTROL_TIMEOUT 1000 +#define CONTROL_TIMEOUT 5000 static libusb_context *ctx = NULL; From 86ba12af1279d805af2215886be71cd49dadb21e Mon Sep 17 00:00:00 2001 From: Sergey Gridassov Date: Sat, 4 Dec 2010 13:17:33 +0300 Subject: [PATCH 16/50] USB abstraction: implemented sent length checking Ingenic: implemented SDRAM load and go USBBoot cmdset: implemented 'load' and 'go' --- ingenic.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++-- ingenic.h | 6 ++++ usbboot_cmdset.c | 35 ++++++++++++++++++++++ usbdev.c | 14 ++++++++- 4 files changed, 127 insertions(+), 4 deletions(-) diff --git a/ingenic.c b/ingenic.c index 394a20d..8e6c371 100644 --- a/ingenic.c +++ b/ingenic.c @@ -238,8 +238,8 @@ uint32_t ingenic_sdram_size(void *hndl) { return handle->total_sdram_size; } -static int ingenic_address(void *usb, uint32_t base) { - return usbdev_vendor(usb, USBDEV_TODEV, VR_SET_DATA_ADDRESS, (base >> 16), base & 0xFFFF, 0, 0); +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) { @@ -307,7 +307,7 @@ int ingenic_loadstage(void *hndl, int id, const char *file) { memcpy(data + 8, &handle->cfg, sizeof(firmware_config_t)); - if(ingenic_address(handle->usb, base) == -1) { + if(ingenic_wordop(handle->usb, VR_SET_DATA_ADDRESS, base) == -1) { free(data); return -1; @@ -403,3 +403,73 @@ int ingenic_configure_stage2(void *hndl) { return 0; } +int ingenic_load_sdram(void *hndl, void *data, uint32_t base, uint32_t size) { + HANDLE; + + while(size) { + int block = size > 65535 ? 65535 : size; + + debug(LEVEL_DEBUG, "Loading SDRAM from %p to 0x%08X, size %u\n", data, base, block); + + 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_sendbulk(handle->usb, data, 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]; + + if(usbdev_recvbulk(handle->usb, result, sizeof(result)) == -1) + return -1; + + data += 65535; + base += 65535; + if(size <= 65535) + break; + + size -= 65535; + } + 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); + fread(data, size, 1, fd); + + fclose(fd); + + int ret = ingenic_load_sdram(handle, data, base, size); + + free(data); + + return ret; +} + +int ingenic_go(void *hndl, uint32_t address) { + HANDLE; + + return ingenic_wordop(handle->usb, VR_PROGRAM_START2, address); +} + diff --git a/ingenic.h b/ingenic.h index 32c166c..ec546ba 100644 --- a/ingenic.h +++ b/ingenic.h @@ -36,6 +36,9 @@ int ingenic_stage1_debugop(void *device, const char *filename, uint32_t op, uint 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); #define CMDSET_SPL 1 #define CMDSET_USBBOOT 2 @@ -54,6 +57,9 @@ int ingenic_configure_stage2(void *hndl); #define DS_flash_info 0 #define DS_hand 1 + +#define SDRAM_LOAD 0 + typedef struct { /* debug args */ uint8_t debug_ops; diff --git a/usbboot_cmdset.c b/usbboot_cmdset.c index 298a86f..2bbd29d 100644 --- a/usbboot_cmdset.c +++ b/usbboot_cmdset.c @@ -18,15 +18,20 @@ #include #include +#include #include "shell.h" #include "config.h" #include "ingenic.h" static int usbboot_boot(int argc, char *argv[]); +static int usbboot_load(int argc, char *argv[]); +static int usbboot_go(int argc, char *argv[]); const shell_command_t usbboot_cmdset[] = { { "boot", "- Reconfigure stage2", usbboot_boot }, + { "load", " - Load file to SDRAM", usbboot_load }, + { "go", "
- Jump to
", usbboot_go }, { NULL, NULL, NULL } }; @@ -40,3 +45,33 @@ static int usbboot_boot(int argc, char *argv[]) { return ret; } +static int usbboot_load(int argc, char *argv[]) { + if(argc != 3) { + printf("Usage: %s \n", argv[0]); + + return -1; + } + + int ret = ingenic_load_sdram_file(shell_device(), strtoul(argv[2], NULL, 0), argv[1]); + + if(ret == -1) + perror("ingenic_load_sdram_file"); + + return ret; +} + +static int usbboot_go(int argc, char *argv[]) { + if(argc != 2) { + printf("Usage: %s
\n", argv[0]); + + return -1; + } + + int ret = ingenic_go(shell_device(), strtoul(argv[1], NULL, 0)); + + if(ret == -1) + perror("ingenic_go"); + + return ret; +} + diff --git a/usbdev.c b/usbdev.c index e2731c0..d202e5c 100644 --- a/usbdev.c +++ b/usbdev.c @@ -141,7 +141,19 @@ int usbdev_sendbulk(void *hndl, void *data, int size) { debug(LEVEL_DEBUG, "Bulk: writing data %p, size %d\n", data, size); - return translate_libusb(libusb_bulk_transfer(hndl, ENDPOINT_OUT, data, size, &trans, CONTROL_TIMEOUT)); + 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) { From 8488331cdf265937fc24409c5ef0b25682daa1dc Mon Sep 17 00:00:00 2001 From: Sergey Gridassov Date: Sat, 4 Dec 2010 14:03:43 +0300 Subject: [PATCH 17/50] Implemented ingenic_query_nand --- ingenic.c | 32 +++++++++++++++++++++++ ingenic.h | 66 +++++++++++++++++++++++++++++++----------------- usbboot_cmdset.c | 33 ++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 23 deletions(-) diff --git a/ingenic.c b/ingenic.c index 8e6c371..68946b3 100644 --- a/ingenic.c +++ b/ingenic.c @@ -473,3 +473,35 @@ int ingenic_go(void *hndl, uint32_t 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; +} + + diff --git a/ingenic.h b/ingenic.h index ec546ba..c7563eb 100644 --- a/ingenic.h +++ b/ingenic.h @@ -17,29 +17,6 @@ #define VR_CONFIGRATION 0x09 #define VR_GET_NUM 0x0a -typedef struct { - void (*cmdset_change)(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); - #define CMDSET_SPL 1 #define CMDSET_USBBOOT 2 @@ -60,6 +37,16 @@ int ingenic_go(void *hndl, uint32_t address); #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 + typedef struct { /* debug args */ uint8_t debug_ops; @@ -109,4 +96,37 @@ typedef struct { 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)(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); + #endif diff --git a/usbboot_cmdset.c b/usbboot_cmdset.c index 2bbd29d..75dbd7a 100644 --- a/usbboot_cmdset.c +++ b/usbboot_cmdset.c @@ -27,12 +27,16 @@ static int usbboot_boot(int argc, char *argv[]); static int usbboot_load(int argc, char *argv[]); static int usbboot_go(int argc, char *argv[]); +static int usbboot_nquery(int argc, char *argv[]); const shell_command_t usbboot_cmdset[] = { + { "boot", "- Reconfigure stage2", usbboot_boot }, { "load", " - Load file to SDRAM", usbboot_load }, { "go", "
- Jump to
", usbboot_go }, + { "nquery", " - Query NAND information", usbboot_nquery }, + { NULL, NULL, NULL } }; @@ -75,3 +79,32 @@ static int usbboot_go(int argc, char *argv[]) { return ret; } +static int usbboot_nquery(int argc, char *argv[]) { + if(argc != 2) { + printf("Usage: %s \n", argv[0]); + + return -1; + } + + nand_info_t info; + + int ret = ingenic_query_nand(shell_device(), 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; +} + From 9f966656d4bfcabe1c1cf08da057dfdb24eeb920 Mon Sep 17 00:00:00 2001 From: Sergey Gridassov Date: Sat, 4 Dec 2010 16:16:57 +0300 Subject: [PATCH 18/50] Implemented NAND dumping --- dump.scr | 23 ++++++++++++++++ ingenic.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ ingenic.h | 7 +++++ usbboot_cmdset.c | 25 +++++++++++++++++- 4 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 dump.scr diff --git a/dump.scr b/dump.scr new file mode 100644 index 0000000..2e30689 --- /dev/null +++ b/dump.scr @@ -0,0 +1,23 @@ +echo "Dumping script" +nquery 0 + +set NAND_ECCPOS 3 +rebuildcfg +boot + +echo "Configured for bootloader IO!" + +ndump 0 0 64 "dump/nand.bin" + +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/ingenic.c b/ingenic.c index 68946b3..b3ac770 100644 --- a/ingenic.c +++ b/ingenic.c @@ -504,4 +504,73 @@ int ingenic_query_nand(void *hndl, int cs, nand_info_t *info) { return 0; } +int ingenic_dump_nand(void *hndl, int cs, int start, int pages, 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; + + debug(LEVEL_DEBUG, "Ingenic: NAND dump: page size: %d bytes, pages in chunk: %d\n", page_size, chunk_pages); + + FILE *dest = fopen(filename, "wb"); + + if(dest == NULL) + return -1; + + void *iobuf = malloc(chunk_pages * page_size); + + int ret = 0; + + while(pages > 0) { + int chunk = pages < chunk_pages ? pages : chunk_pages; + int bytes = chunk * page_size; + + debug(LEVEL_DEBUG, "Ingenic: dumping NAND %d to file %s from page %d, size: %d bytes (%d pages)\n", cs, filename, start, bytes, chunk); + + 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_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; + + return -1; + } + + uint32_t result[4]; + + ret = usbdev_recvbulk(handle->usb, result, sizeof(result)); + + if(ret == -1) + return -1; + + fwrite(iobuf, bytes, 1, dest); + + + start += chunk; + pages -= chunk; + } + + free(iobuf); + fclose(dest); + + return ret; +} \ No newline at end of file diff --git a/ingenic.h b/ingenic.h index c7563eb..ae10ea8 100644 --- a/ingenic.h +++ b/ingenic.h @@ -32,6 +32,8 @@ #define STAGE2_CODESIZE 0x400000 #define SDRAM_BASE 0x80000000 +#define STAGE2_IOBUF (2048 * 128) + #define DS_flash_info 0 #define DS_hand 1 @@ -47,6 +49,10 @@ #define NAND_PROGRAM 7 #define NAND_READ_TO_RAM 8 +#define OOB_ECC 0 +#define OOB_NO_ECC 1 +#define NO_OOB 2 + typedef struct { /* debug args */ uint8_t debug_ops; @@ -128,5 +134,6 @@ 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); #endif diff --git a/usbboot_cmdset.c b/usbboot_cmdset.c index 75dbd7a..0827a6a 100644 --- a/usbboot_cmdset.c +++ b/usbboot_cmdset.c @@ -28,6 +28,7 @@ static int usbboot_boot(int argc, char *argv[]); static int usbboot_load(int argc, char *argv[]); static int usbboot_go(int argc, char *argv[]); static int usbboot_nquery(int argc, char *argv[]); +static int usbboot_ndump(int argc, char *argv[]); const shell_command_t usbboot_cmdset[] = { @@ -36,7 +37,9 @@ const shell_command_t usbboot_cmdset[] = { { "go", "
- Jump to
", usbboot_go }, { "nquery", " - Query NAND information", usbboot_nquery }, - + { "ndump", " - Dump NAND to file", usbboot_ndump }, + { "ndump_oob", " - Dump NAND with OOB to file", usbboot_ndump }, + { NULL, NULL, NULL } }; @@ -108,3 +111,23 @@ static int usbboot_nquery(int argc, char *argv[]) { return 0; } +static int usbboot_ndump(int argc, char *argv[]) { + if(argc != 5) { + printf("Usage: %s \n", argv[0]); + + return -1; + } + + int type = strcmp(argv[0], "ndump_oob") ? NO_OOB : OOB_ECC; + + int ret = ingenic_dump_nand(shell_device(), atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), type, argv[4]); + + if(ret == -1) { + perror("ingenic_dump_nand"); + + return -1; + } + + return 0; +} + From a821e6cf485b50a1d1d179f25b249de2b2ff46c3 Mon Sep 17 00:00:00 2001 From: Sergey Gridassov Date: Sat, 4 Dec 2010 16:56:31 +0300 Subject: [PATCH 19/50] Implemented ECC bypass in nread; implemented nerase --- dump.scr | 2 ++ ingenic.c | 70 +++++++++++++++++++++++++++-------------------- ingenic.h | 2 ++ usb_boot.bin | Bin 32276 -> 31796 bytes usbboot_cmdset.c | 24 ++++++++++++++-- 5 files changed, 66 insertions(+), 32 deletions(-) diff --git a/dump.scr b/dump.scr index 2e30689..64b5f6b 100644 --- a/dump.scr +++ b/dump.scr @@ -1,6 +1,7 @@ echo "Dumping script" nquery 0 +set NAND_IGNORE_ECC 1 set NAND_ECCPOS 3 rebuildcfg boot @@ -9,6 +10,7 @@ echo "Configured for bootloader IO!" ndump 0 0 64 "dump/nand.bin" +set NAND_IGNORE_ECC set NAND_ECCPOS 8 rebuildcfg boot diff --git a/ingenic.c b/ingenic.c index b3ac770..268410b 100644 --- a/ingenic.c +++ b/ingenic.c @@ -104,11 +104,8 @@ static uint32_t ingenic_probe(void *usb_hndl) { magic[8] = 0; for(int i = 0; magic_list[i].magic != NULL; i++) - if(strcmp(magic_list[i].magic, magic) == 0) { - debug(LEVEL_DEBUG, "Magic: '%s', type: %08X\n", magic, magic_list[i].id); - + if(strcmp(magic_list[i].magic, magic) == 0) return magic_list[i].id; - } debug(LEVEL_ERROR, "Unknown CPU: '%s'\n", magic); errno = EINVAL; @@ -204,10 +201,6 @@ int ingenic_rebuild(void *hndl) { * (handle->cfg.bank_num + 1) * 2 * (2 - handle->cfg.bus_width); - debug(LEVEL_DEBUG, "Firmware configuration dump:\n"); - - hexdump(&handle->cfg, sizeof(firmware_config_t)); - handle->nand.cpuid = CPUID(handle->type); NOPT("BUSWIDTH", bw, 1); @@ -225,10 +218,6 @@ int ingenic_rebuild(void *hndl) { NOPT("WPPIN", wppin, 1); NOPT("BLOCKPERCHIP", bpc, 1); - debug(LEVEL_DEBUG, "NAND configuration dump:\n"); - - hexdump(&handle->nand, sizeof(nand_config_t)); - return 0; } @@ -250,9 +239,6 @@ int ingenic_stage1_debugop(void *hndl, const char *filename, uint32_t op, uint32 handle->cfg.debug.start = base; handle->cfg.debug.size = size; - debug(LEVEL_DEBUG, "Debug configuration dump:\n"); - hexdump(&handle->cfg, sizeof(firmware_config_t)); - int ret = ingenic_loadstage(handle, INGENIC_STAGE1, filename); memset(&handle->cfg.debug, 0, sizeof(ingenic_stage1_debug_t)); @@ -398,8 +384,6 @@ int ingenic_configure_stage2(void *hndl) { if(ret == -1) return -1; - debug(LEVEL_DEBUG, "Stage2 configured\n"); - return 0; } @@ -409,8 +393,6 @@ int ingenic_load_sdram(void *hndl, void *data, uint32_t base, uint32_t size) { while(size) { int block = size > 65535 ? 65535 : size; - debug(LEVEL_DEBUG, "Loading SDRAM from %p to 0x%08X, size %u\n", data, base, block); - if(ingenic_wordop(handle->usb, VR_SET_DATA_ADDRESS, base) == -1) return -1; @@ -510,8 +492,6 @@ int ingenic_dump_nand(void *hndl, int cs, int start, int pages, int type, const int page_size = (handle->nand.nand_ps + (type == NO_OOB ? 0 : handle->nand.nand_os)); int chunk_pages = STAGE2_IOBUF / page_size; - debug(LEVEL_DEBUG, "Ingenic: NAND dump: page size: %d bytes, pages in chunk: %d\n", page_size, chunk_pages); - FILE *dest = fopen(filename, "wb"); if(dest == NULL) @@ -520,13 +500,13 @@ int ingenic_dump_nand(void *hndl, int cs, int start, int pages, int type, const void *iobuf = malloc(chunk_pages * page_size); int ret = 0; + int ignore_ecc = type & IGNORE_ECC; + type &= ~IGNORE_ECC; while(pages > 0) { int chunk = pages < chunk_pages ? pages : chunk_pages; int bytes = chunk * page_size; - - debug(LEVEL_DEBUG, "Ingenic: dumping NAND %d to file %s from page %d, size: %d bytes (%d pages)\n", cs, filename, start, bytes, chunk); - + ret = ingenic_wordop(handle->usb, VR_SET_DATA_ADDRESS, start); if(ret == -1) @@ -549,21 +529,29 @@ int ingenic_dump_nand(void *hndl, int cs, int start, int pages, int type, const if(ret != bytes) { debug(LEVEL_ERROR, "Ingenic: NAND dump truncated: expected %d bytes, received %d\n", bytes, ret); - + errno = EIO; - return -1; + break; } - uint32_t result[4]; + uint16_t result[4]; + ret = usbdev_recvbulk(handle->usb, result, sizeof(result)); if(ret == -1) return -1; + if(result[3] != 0 && !ignore_ecc) { + 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; @@ -573,4 +561,28 @@ int ingenic_dump_nand(void *hndl, int cs, int start, int pages, int type, const fclose(dest); return ret; -} \ No newline at end of file +} + +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; +} diff --git a/ingenic.h b/ingenic.h index ae10ea8..bec6432 100644 --- a/ingenic.h +++ b/ingenic.h @@ -52,6 +52,7 @@ #define OOB_ECC 0 #define OOB_NO_ECC 1 #define NO_OOB 2 +#define IGNORE_ECC (1 << 7) typedef struct { /* debug args */ @@ -135,5 +136,6 @@ 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_erase_nand(void *hndl, int cs, int start, int blocks); #endif diff --git a/usb_boot.bin b/usb_boot.bin index 56eabed9ff4da73db8204e5671d3d452b642c53d..b5d0ba4e3e3fa93ccae4fc584fb3b32224bdfed9 100644 GIT binary patch literal 31796 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

@4CBw<-LSEseJhz z%U1*11?9IdS^258wM&4?h3{6@FG;Mu^Um6fzFWEEo~ho|uUxXKehM5^`P!vGWmUse z?bzSN%GWNv+i!Luo{cN-T()w_?P!X3iVA*-wGOo3y#8V^S#{F8Rf)B1OHdQ~LAj3| z-{^m}8#lJcJ{p64f@M{|KcareVMVgIUcnU~@Vqy1xr3OAdp&OySIu+yvKy{3Ts|mu zThhFFb2 zv;iEdS0qUJ|8TaRx@wy&Rozi>9G0PR+_0@m#tS~fwbNoI&6=H~|$%*kT`_Hy^b{*1l9 z`N3AJzOK${-Lz@rCTn9$%cGddNj41T^y2pQ`Yj5BvX4$tcH0zXADN;oHbvQorzpF1 zin3b@${yZ0j+Qux(3awg;3~&OS~mS}&)b6Q5U!u&!XHBPnsDvGbsAUc&nL>mj2XAz zUiYC@35#FH$K{~dSEa5 zUz|4+>n+oQSjlj5dKk|h1~IMZb1+MhX+;KaWiTozjn8R{FH<8lbbFV#5|KFXu0R%z zqX5T$M^P->aap+7hces+b)e4KRIc&wK1e+M$Ne)UGVcnYyQstK|M|bjL*kbHfw-e4 z?l*|L=6Z1(amD6{>)b4EHx6&Swo2R;s8cy#+&0`BV7Rlm8t^-bKSXoBLfjJmE*JMr zl%G%GH=K^qdb9`p^Pdzqf%l{D6Za6lqC4zG+_zDuyIS0e8REWvow(1S&p7IwT#FL3w{NBG1Z9gsUTL{_{AKotR vIh5lgD6WJ0C3ISFKN3S9xMTCjJr@zT=@HNe&lR}Jah(E=YtZNE2gLoqO;^PA literal 32276 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 - 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 }, { NULL, NULL, NULL } }; @@ -120,14 +123,29 @@ static int usbboot_ndump(int argc, char *argv[]) { int type = strcmp(argv[0], "ndump_oob") ? NO_OOB : OOB_ECC; + if(cfg_getenv("NAND_IGNORE_ECC")) + type |= IGNORE_ECC; + int ret = ingenic_dump_nand(shell_device(), atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), type, argv[4]); - if(ret == -1) { + if(ret == -1) perror("ingenic_dump_nand"); + + return ret; +} + +static int usbboot_nerase(int argc, char *argv[]) { + if(argc != 4) { + printf("Usage: %s \n", argv[0]); return -1; } - return 0; + int ret = ingenic_erase_nand(shell_device(), atoi(argv[1]), atoi(argv[2]), atoi(argv[3])); + + if(ret == -1) + perror("ingenic_erase_nand"); + + return ret; + } - From 8dbb1401fd548749469c94811d216a7d9fa32019 Mon Sep 17 00:00:00 2001 From: Sergey Gridassov Date: Sat, 4 Dec 2010 18:30:11 +0300 Subject: [PATCH 20/50] Implemented nprogram (USE WITH CARE!) --- dump.scr | 8 +++-- ingenic.c | 87 +++++++++++++++++++++++++++++++++++++++++++++--- ingenic.h | 3 +- usbboot_cmdset.c | 32 ++++++++++++++++-- 4 files changed, 119 insertions(+), 11 deletions(-) diff --git a/dump.scr b/dump.scr index 64b5f6b..93d19ac 100644 --- a/dump.scr +++ b/dump.scr @@ -1,16 +1,18 @@ echo "Dumping script" nquery 0 -set NAND_IGNORE_ECC 1 +#set NAND_RAW 1 set NAND_ECCPOS 3 rebuildcfg boot echo "Configured for bootloader IO!" -ndump 0 0 64 "dump/nand.bin" +ndump_oob 0 0 128 "dump/nand.bin" -set NAND_IGNORE_ECC +exit + +set NAND_RAW set NAND_ECCPOS 8 rebuildcfg boot diff --git a/ingenic.c b/ingenic.c index 268410b..f84db2b 100644 --- a/ingenic.c +++ b/ingenic.c @@ -488,7 +488,10 @@ 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) { 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; @@ -500,8 +503,6 @@ int ingenic_dump_nand(void *hndl, int cs, int start, int pages, int type, const void *iobuf = malloc(chunk_pages * page_size); int ret = 0; - int ignore_ecc = type & IGNORE_ECC; - type &= ~IGNORE_ECC; while(pages > 0) { int chunk = pages < chunk_pages ? pages : chunk_pages; @@ -517,7 +518,7 @@ int ingenic_dump_nand(void *hndl, int cs, int start, int pages, int type, const if(ret == -1) break; - ret = ingenic_nandop(handle->usb, cs, NAND_READ, type); + ret = ingenic_nandop(handle->usb, cs, raw ? NAND_READ_RAW : NAND_READ, type); if(ret == -1) break; @@ -543,7 +544,7 @@ int ingenic_dump_nand(void *hndl, int cs, int start, int pages, int type, const if(ret == -1) return -1; - if(result[3] != 0 && !ignore_ecc) { + if(result[3] != 0 && !raw) { debug(LEVEL_ERROR, "Ingenic: ECC failure while reading NAND. See UART output for details\n"); errno = EIO; @@ -586,3 +587,79 @@ int ingenic_erase_nand(void *hndl, int cs, int start, int blocks) { 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 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); + + while(pages > 0) { + int chunk = pages < chunk_pages ? pages : chunk_pages; + int bytes = chunk * page_size; + + debug(LEVEL_DEBUG, "Writing %d pages from %d\n", chunk, start); + + ret = fread(iobuf, 1, bytes, in); + + 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; + } + + free(iobuf); + fclose(in); + + return ret; +} diff --git a/ingenic.h b/ingenic.h index bec6432..dd2cbcb 100644 --- a/ingenic.h +++ b/ingenic.h @@ -52,7 +52,7 @@ #define OOB_ECC 0 #define OOB_NO_ECC 1 #define NO_OOB 2 -#define IGNORE_ECC (1 << 7) +#define NAND_RAW (1 << 7) typedef struct { /* debug args */ @@ -136,6 +136,7 @@ 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); #endif diff --git a/usbboot_cmdset.c b/usbboot_cmdset.c index 9ad88f1..fa4c6a8 100644 --- a/usbboot_cmdset.c +++ b/usbboot_cmdset.c @@ -31,6 +31,7 @@ static int usbboot_go(int argc, char *argv[]); static int usbboot_nquery(int argc, char *argv[]); static int usbboot_ndump(int argc, char *argv[]); static int usbboot_nerase(int argc, char *argv[]); +static int usbboot_nprogram(int argc, char *argv[]); const shell_command_t usbboot_cmdset[] = { @@ -42,6 +43,8 @@ const shell_command_t usbboot_cmdset[] = { { "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 }, { NULL, NULL, NULL } }; @@ -123,8 +126,8 @@ static int usbboot_ndump(int argc, char *argv[]) { int type = strcmp(argv[0], "ndump_oob") ? NO_OOB : OOB_ECC; - if(cfg_getenv("NAND_IGNORE_ECC")) - type |= IGNORE_ECC; + if(cfg_getenv("NAND_RAW")) + type |= NAND_RAW; int ret = ingenic_dump_nand(shell_device(), atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), type, argv[4]); @@ -149,3 +152,28 @@ static int usbboot_nerase(int argc, char *argv[]) { return ret; } + +static int usbboot_nprogram(int argc, char *argv[]) { + if(argc != 4) { + printf("Usage: %s \n", argv[0]); + + return -1; + } + + 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(), atoi(argv[1]), atoi(argv[2]), type, argv[3]); + + if(ret == -1) + perror("ingenic_program_nand"); + + return ret; +} From f3d7b160a7bece11a918c7b080c132f47f120551 Mon Sep 17 00:00:00 2001 From: Sergey Gridassov Date: Sat, 4 Dec 2010 21:14:46 +0300 Subject: [PATCH 21/50] Implemented nload --- boot.cfg | 1 - ingenic.c | 51 ++++++++++++++++++++++++++++++++++++------------ ingenic.h | 1 + usbboot_cmdset.c | 17 ++++++++++++++++ 4 files changed, 56 insertions(+), 14 deletions(-) diff --git a/boot.cfg b/boot.cfg index 8b1e865..7696940 100644 --- a/boot.cfg +++ b/boot.cfg @@ -1,5 +1,4 @@ source initial.cfg -safe memtest boot diff --git a/ingenic.c b/ingenic.c index f84db2b..30164c5 100644 --- a/ingenic.c +++ b/ingenic.c @@ -391,8 +391,13 @@ int ingenic_load_sdram(void *hndl, void *data, uint32_t base, uint32_t size) { HANDLE; while(size) { - int block = size > 65535 ? 65535 : size; + int block = size > STAGE2_IOBUF ? STAGE2_IOBUF : size; + printf("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; @@ -400,25 +405,20 @@ int ingenic_load_sdram(void *hndl, void *data, uint32_t base, uint32_t size) { return -1; - if(usbdev_sendbulk(handle->usb, data, 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]; - if(usbdev_recvbulk(handle->usb, result, sizeof(result)) == -1) + int ret = usbdev_recvbulk(handle->usb, result, sizeof(result)); + if(ret == -1) return -1; + + hexdump(result, ret); - data += 65535; - base += 65535; - if(size <= 65535) - break; - - size -= 65535; + data += block; + base += block; + size -= block; } debug(LEVEL_DEBUG, "Load done\n"); @@ -452,6 +452,8 @@ int ingenic_load_sdram_file(void *hndl, uint32_t base, const char *file) { 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); } @@ -663,3 +665,26 @@ int ingenic_program_nand(void *hndl, int cs, int start, int type, const char *fi 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/ingenic.h b/ingenic.h index dd2cbcb..5e6b25c 100644 --- a/ingenic.h +++ b/ingenic.h @@ -138,5 +138,6 @@ 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/usbboot_cmdset.c b/usbboot_cmdset.c index fa4c6a8..e177246 100644 --- a/usbboot_cmdset.c +++ b/usbboot_cmdset.c @@ -32,6 +32,7 @@ static int usbboot_nquery(int argc, char *argv[]); static int usbboot_ndump(int argc, char *argv[]); static int usbboot_nerase(int argc, char *argv[]); static int usbboot_nprogram(int argc, char *argv[]); +static int usbboot_nload(int argc, char *argv[]); const shell_command_t usbboot_cmdset[] = { @@ -45,6 +46,7 @@ const shell_command_t usbboot_cmdset[] = { { "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 } }; @@ -177,3 +179,18 @@ static int usbboot_nprogram(int argc, char *argv[]) { return ret; } + +static int usbboot_nload(int argc, char *argv[]) { + if(argc != 5) { + printf("Usage: %s \n", argv[0]); + + return -1; + } + + int ret = ingenic_load_nand(shell_device(), atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), strtoul(argv[4], NULL, 0)); + + if(ret == -1) + perror("ingenic_load_nand"); + + return ret; +} From a80ec957c69fc132a1aa95d56154283b171fa34a Mon Sep 17 00:00:00 2001 From: Sergey Gridassov Date: Fri, 10 Dec 2010 12:43:54 +0300 Subject: [PATCH 22/50] Made shell reentrant --- Makefile | 2 +- main.c | 14 +- shell.c | 343 ++++++------------- shell.h | 34 +- shell_builtins.c | 181 ++++++++++ shell_internal.h | 62 ++++ shell_lex.c | 876 ++++++++++++++++++++++++++++------------------- shell_lex.l | 16 +- spl_cmdset.c | 28 +- usbboot_cmdset.c | 48 +-- 10 files changed, 949 insertions(+), 655 deletions(-) create mode 100644 shell_builtins.c create mode 100644 shell_internal.h diff --git a/Makefile b/Makefile index 87f5e00..c43c028 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ endif CC = gcc TARGET = jzboot -SOURCES = debug.c devmgr.c ingenic.c main.c shell_lex.c usbdev.c shell.c config.c spl_cmdset.c usbboot_cmdset.c +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 CFLAGS = --std=gnu99 -Wall -Werror -O2 $(shell pkg-config libusb-1.0 --cflags) LIBS += $(shell pkg-config libusb-1.0 --libs) diff --git a/main.c b/main.c index 663ab08..e94aa93 100644 --- a/main.c +++ b/main.c @@ -146,7 +146,9 @@ int main(int argc, char *argv[]) { goto exit_usb; } - if(shell_init(ingenic) == -1) { + shell_context_t *shell = shell_init(ingenic); + + if(shell == NULL) { perror("shell_init"); ret = 1; @@ -155,7 +157,7 @@ int main(int argc, char *argv[]) { } if(config) - if(shell_source(config) == -1) { + if(shell_source(shell, config) == -1) { perror("shell_source"); ret = 1; @@ -164,23 +166,23 @@ int main(int argc, char *argv[]) { } if(cmd != NULL) { - if(shell_execute(cmd) == -1) { + if(shell_execute(shell, cmd) == -1) { perror("shell_execute"); ret = 1; } } else if(script != NULL) { - if(shell_source(script) == -1) { + if(shell_source(shell, script) == -1) { perror("shell_source"); ret = 1; } } else - shell_interactive(); + shell_interactive(shell); exit_shell: - shell_fini(); + shell_fini(shell); exit_ingenic: ingenic_close(ingenic); diff --git a/shell.c b/shell.c index 913e6e3..32e1d64 100644 --- a/shell.c +++ b/shell.c @@ -27,42 +27,9 @@ #include #include -#include "shell.h" +#include "shell_internal.h" #include "debug.h" #include "ingenic.h" -#include "config.h" - -static void *device = NULL; -static char linebuf[512]; -char *strval = NULL, *line = NULL; - -int yylex(); -void yyrestart(FILE *new_file); - -static int builtin_help(int argc, char *argv[]); -static int builtin_exit(int argc, char *argv[]); -static int builtin_source(int argc, char *argv[]); -static int builtin_echo(int argc, char *argv[]); -static int builtin_sleep(int argc, char *argv[]); -static int builtin_redetect(int argc, char *argv[]); -static int builtin_rebuildcfg(int argc, char *argv[]); -static int builtin_set(int argc, char *argv[]); -static int builtin_safe(int argc, char *argv[]); - -static const shell_command_t commands[] = { - { "help", "- Display this message", builtin_help }, - { "exit", "- Batch: stop current script, interactive: end session", builtin_exit }, - { "source", " - run specified script", builtin_source }, - { "echo", " - output specified string", builtin_echo }, - { "sleep", " - sleep a specified amount of time", builtin_sleep }, - { "set", "[VARIABLE] [VALUE] - print or set configuraton variables", builtin_set }, - { "safe", " [ARG]... - run command ignoring errors", builtin_safe }, - - { "redetect", " - Redetect CPU", builtin_redetect }, - { "rebuildcfg", " - Rebuild firmware configuration data", builtin_rebuildcfg }, - - { NULL, NULL, NULL } -}; static void shell_update_cmdset(void *arg); @@ -70,64 +37,106 @@ static const ingenic_callbacks_t shell_callbacks = { shell_update_cmdset, }; -static const shell_command_t *set_cmds = NULL; -static int shell_exit = 0; +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 } +}; -int shell_init(void *ingenic) { +shell_context_t *shell_init(void *ingenic) { #ifdef WITH_READLINE rl_initialize(); #endif debug(LEVEL_DEBUG, "Initializing shell\n"); - device = ingenic; + 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, NULL); + ingenic_set_callbacks(ingenic, &shell_callbacks, ctx); - shell_update_cmdset(NULL); + shell_update_cmdset(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; } -#define STATE_WANTSTR 0 -#define STATE_WANTSPACE 1 +static int shell_run_function(shell_context_t *ctx, const shell_command_t *cmd, void *arg) { + shell_run_data_t *data = arg; -int shell_run(int argc, char *argv[]) { - for(int i = 0; commands[i].cmd != NULL; i++) - if(strcmp(commands[i].cmd, argv[0]) == 0) - return commands[i].handler(argc, argv); + if(strcmp(cmd->cmd, data->argv[0]) == 0) { + int ret = cmd->handler(ctx, data->argc, data->argv); - if(set_cmds) { - for(int i = 0; set_cmds[i].cmd != NULL; i++) - if(strcmp(set_cmds[i].cmd, argv[0]) == 0) - return set_cmds[i].handler(argc, argv); - } - - debug(LEVEL_ERROR, "Bad command '%s'\n", argv[0]); - - errno = EINVAL; - return -1; + if(ret == 0) + return 1; + else + return ret; + } else + return 0; } -int shell_execute(const char *cmd) { - line = strdup(cmd); - char *ptr = line; +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; - - yyrestart(NULL); + int fret = -1; do { int noway = 0; - token = yylex(); + token = yylex(&scanner); if((token == TOK_SEPARATOR || token == TOK_COMMENT || token == 0)) { if(argc > 0) { - int ret = shell_run(argc, argv); + int ret = shell_run(ctx, argc, argv); for(int i = 0; i < argc; i++) { free(argv[i]); @@ -139,9 +148,9 @@ int shell_execute(const char *cmd) { argc = 0; if(ret == -1) { - free(ptr); + fret = -1; - return -1; + break; } } @@ -156,7 +165,7 @@ int shell_execute(const char *cmd) { argv = realloc(argv, sizeof(char *) * argc); - argv[oargc] = strval; + argv[oargc] = ctx->strval; state = STATE_WANTSPACE; } else { @@ -167,7 +176,7 @@ int shell_execute(const char *cmd) { case STATE_WANTSPACE: if(token == TOK_STRING) { - free(strval); + free(ctx->strval); noway = 1; } else if(token == TOK_SPACE) { @@ -183,9 +192,10 @@ int shell_execute(const char *cmd) { free(argv[i]); free(argv); - free(ptr); - return -1; + fret = -1; + + break; } } @@ -193,28 +203,30 @@ int shell_execute(const char *cmd) { free(ptr); - return 0; + yylex_destroy(&scanner); + + return fret; } -int shell_pull(char *buf, int maxlen) { - size_t len = strlen(line); +int shell_pull(shell_context_t *ctx, char *buf, int maxlen) { + size_t len = strlen(ctx->line); if(len < maxlen) maxlen = len; - memcpy(buf, line, maxlen); + memcpy(buf, ctx->line, maxlen); - line += maxlen; + ctx->line += maxlen; return maxlen; } -void shell_fini() { - device = NULL; +void shell_fini(shell_context_t *ctx) { + free(ctx); } -int shell_source(const char *filename) { - shell_exit = 0; +int shell_source(shell_context_t *ctx, const char *filename) { + ctx->shell_exit = 0; FILE *file = fopen(filename, "r"); @@ -224,8 +236,8 @@ int shell_source(const char *filename) { char *line; - while((line = fgets(linebuf, sizeof(linebuf), file)) && !shell_exit) { - if(shell_execute(line) == -1) { + while((line = fgets(ctx->linebuf, sizeof(ctx->linebuf), file)) && !ctx->shell_exit) { + if(shell_execute(ctx, line) == -1) { fclose(file); return -1; @@ -237,38 +249,37 @@ int shell_source(const char *filename) { return 0; } -void shell_interactive() { - shell_exit = 0; +void shell_interactive(shell_context_t *ctx) { + ctx->shell_exit = 0; #ifndef WITH_READLINE char *line; - while(!shell_exit) { + while(!ctx->shell_exit) { fputs("jzboot> ", stdout); fflush(stdout); - line = fgets(linebuf, sizeof(linebuf), stdin); + line = fgets(ctx->linebuf, sizeof(ctx->linebuf), stdin); if(line == NULL) break; - shell_execute(line); + shell_execute(ctx, line); } #else rl_set_signals(); - while(!shell_exit) { + while(!ctx->shell_exit) { char *line = readline("jzboot> "); if(line == NULL) { - printf("line null, EOP\n"); break; } add_history(line); - shell_execute(line); + shell_execute(ctx, line); free(line); } @@ -277,153 +288,18 @@ void shell_interactive() { #endif } -static int builtin_help(int argc, char *argv[]) { - for(int i = 0; commands[i].cmd != NULL; i++) { - printf("%s %s\n", commands[i].cmd, commands[i].description); - } - - if(set_cmds) { - for(int i = 0; set_cmds[i].cmd != NULL; i++) - printf("%s %s\n", set_cmds[i].cmd, set_cmds[i].description); - } - - return 0; -} - -static int builtin_exit(int argc, char *argv[]) { - shell_exit = 1; - - return 0; -} - -static int builtin_source(int argc, char *argv[]) { - if(argc != 2) { - printf("Usage: %s \n", argv[0]); - - return -1; - } - - int ret = shell_source(argv[1]); - - if(ret == -1) { - fprintf(stderr, "Error while sourcing file %s: %s\n", argv[1], strerror(errno)); - } - - shell_exit = 0; - - return ret; -} - -static int builtin_echo(int argc, char *argv[]) { - if(argc < 2) { - printf("Usage: %s \n", argv[0]); - - return -1; - } - - for(int i = 1; i < argc; i++) { - fputs(argv[i], stdout); - - putchar((i < argc - 1) ? ' ' : '\n'); - } - - return 0; -} - -static int builtin_sleep(int argc, char *argv[]) { - if(argc != 2) { - printf("Usage: %s \n", argv[0]); - - return -1; - } - - uint32_t ms = atoi(argv[1]); - - usleep(ms * 1000); - - return 0; -} - -static int builtin_redetect(int argc, char *argv[]) { - if(argc != 1) { - printf("Usage: %s\n", argv[0]); - - return -1; - } - - if(ingenic_redetect(device) == -1) { - perror("ingenic_redetect"); - - return -1; - } else - return 0; -} - - -static int builtin_set(int argc, char *argv[]) { - if(argc == 1 && 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]); - - } else { - printf("Usage: %s [VARIABLE] [VALUE]\n", argv[0]); - - return -1; - } - - return 0; -} - - -static int builtin_rebuildcfg(int argc, char *argv[]) { - if(argc != 1) { - printf("Usage: %s\n", argv[0]); - - return -1; - } - - return ingenic_rebuild(device); -} - -static int builtin_safe(int argc, char *argv[]) { - if(argc < 2) { - printf("Usage: %s [ARG]...\n", argv[0]); - - return -1; - } - - if(shell_run(argc - 1, argv + 1) == -1) - perror("shell_run"); - - return 0; -} - -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 } -}; - static void shell_update_cmdset(void *arg) { - set_cmds = NULL; + shell_context_t *ctx = arg; - int set = ingenic_cmdset(device); + ctx->set_cmds = NULL; + + int set = ingenic_cmdset(ctx->device); for(int i = 0; cmdsets[i].name != NULL; i++) { if(cmdsets[i].set == set) { - printf("Shell: using command set '%s', run 'help' for command list. CPU: %04X\n", cmdsets[i].name, ingenic_type(device)); + printf("Shell: using command set '%s', run 'help' for command list. CPU: %04X\n", cmdsets[i].name, ingenic_type(ctx->device)); - set_cmds = cmdsets[i].commands; + ctx->set_cmds = cmdsets[i].commands; return; } @@ -432,6 +308,11 @@ static void shell_update_cmdset(void *arg) { debug(LEVEL_ERROR, "Shell: unknown cmdset %d\n", set); } -void *shell_device() { - return device; +void *shell_device(shell_context_t *ctx) { + return ctx->device; } + +void shell_exit(shell_context_t *ctx, int val) { + ctx->shell_exit = val; +} + diff --git a/shell.h b/shell.h index 0f11518..8a77369 100644 --- a/shell.h +++ b/shell.h @@ -19,32 +19,30 @@ #ifndef __SHELL__H__ #define __SHELL__H__ -typedef struct { +#ifndef SHELL_INTERNALS +typedef void shell_context_t; +#endif + +typedef struct shell_command { const char *cmd; const char *description; - int (*handler)(int argc, char *argv[]); + int (*handler)(shell_context_t *ctx, int argc, char *argv[]); } shell_command_t; -int shell_init(void *ingenic); -void shell_fini(); +shell_context_t *shell_init(void *ingenic); +void shell_fini(shell_context_t *context); -void shell_interactive(); -int shell_source(const char *filename); -int shell_execute(const char *input); +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_device(); - -// lexer interface -extern char *strval; - -#define TOK_SEPARATOR 1 -#define TOK_STRING 2 -#define TOK_SPACE 3 -#define TOK_COMMENT 4 - -int shell_pull(char *buf, int maxlen); +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/shell_builtins.c b/shell_builtins.c new file mode 100644 index 0000000..675da32 --- /dev/null +++ b/shell_builtins.c @@ -0,0 +1,181 @@ +/* + * 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 "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 }, + { "exit", "- Batch: stop current script, interactive: end session", builtin_exit }, + { "source", " - run specified script", builtin_source }, + { "echo", " - output specified string", builtin_echo }, + { "sleep", " - sleep a specified amount of time", builtin_sleep }, + { "set", "[VARIABLE] [VALUE] - print or set configuraton variables", builtin_set }, + { "safe", " [ARG]... - run command ignoring errors", builtin_safe }, + + { "redetect", " - Redetect CPU", builtin_redetect }, + { "rebuildcfg", " - Rebuild firmware configuration data", builtin_rebuildcfg }, + + { NULL, NULL, NULL } +}; + +static int builtin_help(shell_context_t *ctx, int argc, char *argv[]) { +/* for(int i = 0; commands[i].cmd != NULL; i++) { + printf("%s %s\n", commands[i].cmd, commands[i].description); + } + + if(set_cmds) { + for(int i = 0; set_cmds[i].cmd != NULL; i++) + printf("%s %s\n", set_cmds[i].cmd, set_cmds[i].description); + }*/ + + return 0; +} + +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[]) { + if(argc != 2) { + printf("Usage: %s \n", argv[0]); + + return -1; + } + + 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[]) { + if(argc < 2) { + printf("Usage: %s \n", argv[0]); + + return -1; + } + + 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[]) { + if(argc != 2) { + printf("Usage: %s \n", argv[0]); + + return -1; + } + + uint32_t ms = atoi(argv[1]); + + usleep(ms * 1000); + + return 0; +} + +static int builtin_redetect(shell_context_t *ctx, int argc, char *argv[]) { + if(argc != 1) { + printf("Usage: %s\n", argv[0]); + + return -1; + } + + 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 && 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]); + + } else { + printf("Usage: %s [VARIABLE] [VALUE]\n", argv[0]); + + return -1; + } + + return 0; +} + + +static int builtin_rebuildcfg(shell_context_t *ctx, int argc, char *argv[]) { + if(argc != 1) { + printf("Usage: %s\n", argv[0]); + + return -1; + } + + return ingenic_rebuild(shell_device(ctx)); +} + +static int builtin_safe(shell_context_t *ctx, int argc, char *argv[]) { + if(argc < 2) { + printf("Usage: %s [ARG]...\n", argv[0]); + + return -1; + } + + if(shell_run(ctx, argc - 1, argv + 1) == -1) + perror("shell_run"); + + return 0; +} + diff --git a/shell_internal.h b/shell_internal.h new file mode 100644 index 0000000..e416c20 --- /dev/null +++ b/shell_internal.h @@ -0,0 +1,62 @@ +/* + * 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; +} 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/shell_lex.c b/shell_lex.c index eea7de3..c32427d 100644 --- a/shell_lex.c +++ b/shell_lex.c @@ -119,24 +119,41 @@ typedef unsigned int flex_uint32_t; */ #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 (yy_start) = 1 + 2 * +#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 (((yy_start) - 1) / 2) +#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 ) +#define YY_NEW_FILE yyrestart(yyin ,yyscanner ) #define YY_END_OF_BUFFER_CHAR 0 @@ -162,10 +179,6 @@ typedef unsigned int flex_uint32_t; typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif -extern int yyleng; - -extern FILE *yyin, *yyout; - #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 @@ -179,14 +192,14 @@ extern FILE *yyin, *yyout; /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ - *yy_cp = (yy_hold_char); \ + *yy_cp = yyg->yy_hold_char; \ YY_RESTORE_YY_MORE_OFFSET \ - (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + 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, (yytext_ptr) ) +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T @@ -258,71 +271,51 @@ struct yy_buffer_state }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ -/* Stack of input buffers. */ -static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ -static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ -static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ - /* 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 ( (yy_buffer_stack) \ - ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ +#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 (yy_buffer_stack)[(yy_buffer_stack_top)] +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] -/* yy_hold_char holds the character lost when yytext is formed. */ -static char yy_hold_char; -static int yy_n_chars; /* number of characters read into yy_ch_buf */ -int yyleng; +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 ); -/* Points to current character in buffer. */ -static char *yy_c_buf_p = (char *) 0; -static int yy_init = 0; /* whether we need to initialize */ -static int yy_start = 0; /* start state number */ +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 ); -/* Flag which is used to allow yywrap()'s to do buffer switches - * instead of setting up a fresh yyin. A bit of a hack ... - */ -static int yy_did_buffer_switch_on_eof; +#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner) -void yyrestart (FILE *input_file ); -void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); -YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); -void yy_delete_buffer (YY_BUFFER_STATE b ); -void yy_flush_buffer (YY_BUFFER_STATE b ); -void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); -void yypop_buffer_state (void ); +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 ); -static void yyensure_buffer_stack (void ); -static void yy_load_buffer_state (void ); -static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); - -#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) - -YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); -YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); -YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ); - -void *yyalloc (yy_size_t ); -void *yyrealloc (void *,yy_size_t ); -void yyfree (void * ); +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 (); \ + yyensure_buffer_stack (yyscanner); \ YY_CURRENT_BUFFER_LVALUE = \ - yy_create_buffer(yyin,YY_BUF_SIZE ); \ + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } @@ -330,9 +323,9 @@ void yyfree (void * ); #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ - yyensure_buffer_stack (); \ + yyensure_buffer_stack (yyscanner); \ YY_CURRENT_BUFFER_LVALUE = \ - yy_create_buffer(yyin,YY_BUF_SIZE ); \ + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } @@ -344,31 +337,24 @@ void yyfree (void * ); typedef unsigned char YY_CHAR; -FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; - typedef int yy_state_type; -extern int yylineno; +#define yytext_ptr yytext_r -int yylineno = 1; - -extern char *yytext; -#define yytext_ptr yytext - -static yy_state_type yy_get_previous_state (void ); -static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); -static int yy_get_next_buffer (void ); -static void yy_fatal_error (yyconst char msg[] ); +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 \ - (yytext_ptr) = yy_bp; \ + yyg->yytext_ptr = yy_bp; \ yyleng = (size_t) (yy_cp - yy_bp); \ - (yy_hold_char) = *yy_cp; \ + yyg->yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ - (yy_c_buf_p) = yy_cp; + yyg->yy_c_buf_p = yy_cp; #define YY_NUM_RULES 10 #define YY_END_OF_BUFFER 11 @@ -452,12 +438,6 @@ static yyconst flex_int16_t yy_chk[36] = 18, 18, 18, 18, 18 } ; -static yy_state_type yy_last_accepting_state; -static char *yy_last_accepting_cpos; - -extern int yy_flex_debug; -int yy_flex_debug = 0; - /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ @@ -465,7 +445,6 @@ int yy_flex_debug = 0; #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET -char *yytext; #line 1 "shell_lex.l" /* * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. @@ -485,12 +464,10 @@ char *yytext; * along with this program. If not, see . */ #line 20 "shell_lex.l" -#include "shell.h" +#include "shell_internal.h" #include #include -#define YY_INPUT(buf, result, max_size) result = shell_pull(buf, max_size); - static char *str_append(char *str, const char *src) { if(str) { size_t newlen = strlen(str) + strlen(src) + 1; @@ -508,7 +485,7 @@ static char *str_append(char *str, const char *src) { } #define YY_NO_INPUT 1 -#line 512 "shell_lex.c" +#line 489 "shell_lex.c" #define INITIAL 0 #define STR 1 @@ -525,36 +502,74 @@ static char *str_append(char *str, const char *src) { #define YY_EXTRA_TYPE void * #endif -static int yy_init_globals (void ); +/* 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 (void ); +int yylex_destroy (yyscan_t yyscanner ); -int yyget_debug (void ); +int yyget_debug (yyscan_t yyscanner ); -void yyset_debug (int debug_flag ); +void yyset_debug (int debug_flag ,yyscan_t yyscanner ); -YY_EXTRA_TYPE yyget_extra (void ); +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner ); -void yyset_extra (YY_EXTRA_TYPE user_defined ); +void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); -FILE *yyget_in (void ); +FILE *yyget_in (yyscan_t yyscanner ); -void yyset_in (FILE * in_str ); +void yyset_in (FILE * in_str ,yyscan_t yyscanner ); -FILE *yyget_out (void ); +FILE *yyget_out (yyscan_t yyscanner ); -void yyset_out (FILE * out_str ); +void yyset_out (FILE * out_str ,yyscan_t yyscanner ); -int yyget_leng (void ); +int yyget_leng (yyscan_t yyscanner ); -char *yyget_text (void ); +char *yyget_text (yyscan_t yyscanner ); -int yyget_lineno (void ); +int yyget_lineno (yyscan_t yyscanner ); -void yyset_lineno (int line_number ); +void yyset_lineno (int line_number ,yyscan_t yyscanner ); /* Macros after this point can all be overridden by user definitions in * section 1. @@ -562,26 +577,26 @@ void yyset_lineno (int line_number ); #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus -extern "C" int yywrap (void ); +extern "C" int yywrap (yyscan_t yyscanner ); #else -extern int yywrap (void ); +extern int yywrap (yyscan_t yyscanner ); #endif #endif #ifndef yytext_ptr -static void yy_flex_strncpy (char *,yyconst char *,int ); +static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); #endif #ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * ); +static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus -static int yyinput (void ); +static int yyinput (yyscan_t yyscanner ); #else -static int input (void ); +static int input (yyscan_t yyscanner ); #endif #endif @@ -655,7 +670,7 @@ static int input (void ); /* Report a fatal error. */ #ifndef YY_FATAL_ERROR -#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) #endif /* end tables serialization structures and prototypes */ @@ -666,9 +681,9 @@ static int input (void ); #ifndef YY_DECL #define YY_DECL_IS_OURS 1 -extern int yylex (void); +extern int yylex (yyscan_t yyscanner); -#define YY_DECL int yylex (void) +#define YY_DECL int yylex (yyscan_t yyscanner) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng @@ -693,21 +708,22 @@ YY_DECL register yy_state_type yy_current_state; register char *yy_cp, *yy_bp; register int yy_act; - -#line 45 "shell_lex.l" + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; -#line 700 "shell_lex.c" +#line 43 "shell_lex.l" - if ( !(yy_init) ) +#line 716 "shell_lex.c" + + if ( !yyg->yy_init ) { - (yy_init) = 1; + yyg->yy_init = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif - if ( ! (yy_start) ) - (yy_start) = 1; /* first start state */ + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ if ( ! yyin ) yyin = stdin; @@ -716,35 +732,35 @@ YY_DECL yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { - yyensure_buffer_stack (); + yyensure_buffer_stack (yyscanner); YY_CURRENT_BUFFER_LVALUE = - yy_create_buffer(yyin,YY_BUF_SIZE ); + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); } - yy_load_buffer_state( ); + yy_load_buffer_state(yyscanner ); } while ( 1 ) /* loops until end-of-file is reached */ { - yy_cp = (yy_c_buf_p); + yy_cp = yyg->yy_c_buf_p; /* Support of yytext. */ - *yy_cp = (yy_hold_char); + *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 = (yy_start); + 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] ) { - (yy_last_accepting_state) = yy_current_state; - (yy_last_accepting_cpos) = yy_cp; + 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 ) { @@ -756,8 +772,8 @@ yy_match: ++yy_cp; } while ( yy_current_state != 18 ); - yy_cp = (yy_last_accepting_cpos); - yy_current_state = (yy_last_accepting_state); + 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]; @@ -770,64 +786,64 @@ do_action: /* This label is used only to access EOF actions. */ { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ - *yy_cp = (yy_hold_char); - yy_cp = (yy_last_accepting_cpos); - yy_current_state = (yy_last_accepting_state); + *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 46 "shell_lex.l" -{ strval = NULL; BEGIN(STR); } +#line 44 "shell_lex.l" +{ yyextra->strval = NULL; BEGIN(STR); } YY_BREAK case 2: YY_RULE_SETUP -#line 47 "shell_lex.l" +#line 45 "shell_lex.l" return TOK_SEPARATOR; YY_BREAK case 3: /* rule 3 can match eol */ YY_RULE_SETUP -#line 48 "shell_lex.l" +#line 46 "shell_lex.l" return TOK_SPACE; YY_BREAK case 4: YY_RULE_SETUP -#line 49 "shell_lex.l" +#line 47 "shell_lex.l" return TOK_COMMENT; YY_BREAK case 5: YY_RULE_SETUP -#line 50 "shell_lex.l" -{ strval = strdup(yytext); return TOK_STRING; } +#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 51 "shell_lex.l" -strval = str_append(strval, yytext); +#line 49 "shell_lex.l" +yyextra->strval = str_append(yyextra->strval, yytext); YY_BREAK case 7: YY_RULE_SETUP -#line 52 "shell_lex.l" -strval = str_append(strval, "\""); +#line 50 "shell_lex.l" +yyextra->strval = str_append(yyextra->strval, "\""); YY_BREAK case 8: YY_RULE_SETUP -#line 53 "shell_lex.l" -strval = str_append(strval, "\\"); +#line 51 "shell_lex.l" +yyextra->strval = str_append(yyextra->strval, "\\"); YY_BREAK case 9: YY_RULE_SETUP -#line 54 "shell_lex.l" +#line 52 "shell_lex.l" { BEGIN(INITIAL); return TOK_STRING; } YY_BREAK case 10: YY_RULE_SETUP -#line 55 "shell_lex.l" +#line 53 "shell_lex.l" ECHO; YY_BREAK -#line 831 "shell_lex.c" +#line 847 "shell_lex.c" case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(STR): yyterminate(); @@ -835,10 +851,10 @@ case YY_STATE_EOF(STR): case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ - int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ - *yy_cp = (yy_hold_char); + *yy_cp = yyg->yy_hold_char; YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) @@ -852,7 +868,7 @@ case YY_STATE_EOF(STR): * this is the first action (other than possibly a * back-up) that will match for the new input source. */ - (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + 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; } @@ -864,13 +880,13 @@ case YY_STATE_EOF(STR): * end-of-buffer state). Contrast this with the test * in input(). */ - if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + 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; - (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; - yy_current_state = yy_get_previous_state( ); + yy_current_state = yy_get_previous_state( yyscanner ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have @@ -881,33 +897,33 @@ case YY_STATE_EOF(STR): * will run more slowly). */ - yy_next_state = yy_try_NUL_trans( yy_current_state ); + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); - yy_bp = (yytext_ptr) + YY_MORE_ADJ; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ - yy_cp = ++(yy_c_buf_p); + yy_cp = ++yyg->yy_c_buf_p; yy_current_state = yy_next_state; goto yy_match; } else { - yy_cp = (yy_last_accepting_cpos); - yy_current_state = (yy_last_accepting_state); + 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( ) ) + else switch ( yy_get_next_buffer( yyscanner ) ) { case EOB_ACT_END_OF_FILE: { - (yy_did_buffer_switch_on_eof) = 0; + yyg->yy_did_buffer_switch_on_eof = 0; - if ( yywrap( ) ) + if ( yywrap(yyscanner ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up @@ -918,7 +934,7 @@ case YY_STATE_EOF(STR): * YY_NULL, it'll still work - another * YY_NULL will get returned. */ - (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; @@ -926,30 +942,30 @@ case YY_STATE_EOF(STR): else { - if ( ! (yy_did_buffer_switch_on_eof) ) + if ( ! yyg->yy_did_buffer_switch_on_eof ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: - (yy_c_buf_p) = - (yytext_ptr) + yy_amount_of_matched_text; + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; - yy_current_state = yy_get_previous_state( ); + yy_current_state = yy_get_previous_state( yyscanner ); - yy_cp = (yy_c_buf_p); - yy_bp = (yytext_ptr) + YY_MORE_ADJ; + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: - (yy_c_buf_p) = - &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; - yy_current_state = yy_get_previous_state( ); + yy_current_state = yy_get_previous_state( yyscanner ); - yy_cp = (yy_c_buf_p); - yy_bp = (yytext_ptr) + YY_MORE_ADJ; + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; goto yy_find_action; } break; @@ -969,20 +985,21 @@ case YY_STATE_EOF(STR): * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ -static int yy_get_next_buffer (void) +static int yy_get_next_buffer (yyscan_t yyscanner) { - register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; - register char *source = (yytext_ptr); + 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 ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + 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 ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + 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. @@ -1002,7 +1019,7 @@ static int yy_get_next_buffer (void) /* Try to read more data. */ /* First move last chars to start of buffer. */ - number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); @@ -1011,7 +1028,7 @@ static int yy_get_next_buffer (void) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; else { @@ -1025,7 +1042,7 @@ static int yy_get_next_buffer (void) YY_BUFFER_STATE b = YY_CURRENT_BUFFER; int yy_c_buf_p_offset = - (int) ((yy_c_buf_p) - b->yy_ch_buf); + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { @@ -1038,7 +1055,7 @@ static int yy_get_next_buffer (void) b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ - yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); + yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner ); } else /* Can't grow it, we don't own it. */ @@ -1048,7 +1065,7 @@ static int yy_get_next_buffer (void) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); - (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + 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; @@ -1060,17 +1077,17 @@ static int yy_get_next_buffer (void) /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), - (yy_n_chars), (size_t) num_to_read ); + yyg->yy_n_chars, (size_t) num_to_read ); - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } - if ( (yy_n_chars) == 0 ) + if ( yyg->yy_n_chars == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; - yyrestart(yyin ); + yyrestart(yyin ,yyscanner); } else @@ -1084,39 +1101,40 @@ static int yy_get_next_buffer (void) else ret_val = EOB_ACT_CONTINUE_SCAN; - if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + 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 = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); + 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()" ); } - (yy_n_chars) += number_to_move; - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + 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; - (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + 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 (void) + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) { register yy_state_type yy_current_state; register char *yy_cp; - - yy_current_state = (yy_start); + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + 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] ) { - (yy_last_accepting_state) = yy_current_state; - (yy_last_accepting_cpos) = yy_cp; + 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 ) { @@ -1135,16 +1153,17 @@ static int yy_get_next_buffer (void) * synopsis * next_state = yy_try_NUL_trans( current_state ); */ - static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) { register int yy_is_jam; - register char *yy_cp = (yy_c_buf_p); + 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] ) { - (yy_last_accepting_state) = yy_current_state; - (yy_last_accepting_cpos) = yy_cp; + 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 ) { @@ -1160,32 +1179,33 @@ static int yy_get_next_buffer (void) #ifndef YY_NO_INPUT #ifdef __cplusplus - static int yyinput (void) + static int yyinput (yyscan_t yyscanner) #else - static int input (void) + static int input (yyscan_t yyscanner) #endif { int c; - - *(yy_c_buf_p) = (yy_hold_char); + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + *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 ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) /* This was really a NUL. */ - *(yy_c_buf_p) = '\0'; + *yyg->yy_c_buf_p = '\0'; else { /* need more input */ - int offset = (yy_c_buf_p) - (yytext_ptr); - ++(yy_c_buf_p); + int offset = yyg->yy_c_buf_p - yyg->yytext_ptr; + ++yyg->yy_c_buf_p; - switch ( yy_get_next_buffer( ) ) + switch ( yy_get_next_buffer( yyscanner ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() @@ -1199,34 +1219,34 @@ static int yy_get_next_buffer (void) */ /* Reset buffer status. */ - yyrestart(yyin ); + yyrestart(yyin ,yyscanner); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { - if ( yywrap( ) ) + if ( yywrap(yyscanner ) ) return EOF; - if ( ! (yy_did_buffer_switch_on_eof) ) + if ( ! yyg->yy_did_buffer_switch_on_eof ) YY_NEW_FILE; #ifdef __cplusplus - return yyinput(); + return yyinput(yyscanner); #else - return input(); + return input(yyscanner); #endif } case EOB_ACT_CONTINUE_SCAN: - (yy_c_buf_p) = (yytext_ptr) + offset; + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; break; } } } - c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ - *(yy_c_buf_p) = '\0'; /* preserve yytext */ - (yy_hold_char) = *++(yy_c_buf_p); + 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; } @@ -1234,76 +1254,79 @@ static int yy_get_next_buffer (void) /** 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 ) + void yyrestart (FILE * input_file , yyscan_t yyscanner) { - + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! YY_CURRENT_BUFFER ){ - yyensure_buffer_stack (); + yyensure_buffer_stack (yyscanner); YY_CURRENT_BUFFER_LVALUE = - yy_create_buffer(yyin,YY_BUF_SIZE ); + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); } - yy_init_buffer(YY_CURRENT_BUFFER,input_file ); - yy_load_buffer_state( ); + 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 ) + 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 (); + yyensure_buffer_stack (yyscanner); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ - *(yy_c_buf_p) = (yy_hold_char); - YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + *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( ); + 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. */ - (yy_did_buffer_switch_on_eof) = 1; + yyg->yy_did_buffer_switch_on_eof = 1; } -static void yy_load_buffer_state (void) +static void yy_load_buffer_state (yyscan_t yyscanner) { - (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; - (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + 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; - (yy_hold_char) = *(yy_c_buf_p); + 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 ) + 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 ) ); + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); @@ -1312,24 +1335,25 @@ static void yy_load_buffer_state (void) /* 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 ); + 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 ); + 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 ) + void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) { - + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) return; @@ -1337,9 +1361,9 @@ static void yy_load_buffer_state (void) YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) - yyfree((void *) b->yy_ch_buf ); + yyfree((void *) b->yy_ch_buf ,yyscanner ); - yyfree((void *) b ); + yyfree((void *) b ,yyscanner ); } #ifndef __cplusplus @@ -1350,12 +1374,13 @@ extern int isatty (int ); * 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 ) + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) { int oerrno = errno; - - yy_flush_buffer(b ); + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_flush_buffer(b ,yyscanner); b->yy_input_file = file; b->yy_fill_buffer = 1; @@ -1376,11 +1401,12 @@ extern int isatty (int ); /** 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 ) + void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) { - if ( ! b ) + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) return; b->yy_n_chars = 0; @@ -1398,114 +1424,117 @@ extern int isatty (int ); b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) - yy_load_buffer_state( ); + 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 ) +void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) { - if (new_buffer == NULL) + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) return; - yyensure_buffer_stack(); + yyensure_buffer_stack(yyscanner); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ - *(yy_c_buf_p) = (yy_hold_char); - YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + *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) - (yy_buffer_stack_top)++; + yyg->yy_buffer_stack_top++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ - yy_load_buffer_state( ); - (yy_did_buffer_switch_on_eof) = 1; + 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 (void) +void yypop_buffer_state (yyscan_t yyscanner) { - if (!YY_CURRENT_BUFFER) + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) return; - yy_delete_buffer(YY_CURRENT_BUFFER ); + yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner); YY_CURRENT_BUFFER_LVALUE = NULL; - if ((yy_buffer_stack_top) > 0) - --(yy_buffer_stack_top); + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; if (YY_CURRENT_BUFFER) { - yy_load_buffer_state( ); - (yy_did_buffer_switch_on_eof) = 1; + 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 (void) +static void yyensure_buffer_stack (yyscan_t yyscanner) { int num_to_alloc; - - if (!(yy_buffer_stack)) { + 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; - (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) - ); - if ( ! (yy_buffer_stack) ) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); - memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); - (yy_buffer_stack_max) = num_to_alloc; - (yy_buffer_stack_top) = 0; + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; return; } - if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + 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 = (yy_buffer_stack_max) + grow_size; - (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc - ((yy_buffer_stack), + 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*) - ); - if ( ! (yy_buffer_stack) ) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); /* zero only the new slots.*/ - memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); - (yy_buffer_stack_max) = num_to_alloc; + 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 ) +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) { YY_BUFFER_STATE b; @@ -1515,7 +1544,7 @@ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) /* They forgot to leave room for the EOB's. */ return 0; - b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); @@ -1529,7 +1558,7 @@ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; - yy_switch_to_buffer(b ); + yy_switch_to_buffer(b ,yyscanner ); return b; } @@ -1537,25 +1566,25 @@ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) /** 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 ) +YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner) { - return yy_scan_bytes(yystr,strlen(yystr) ); + 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 ) +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner) { YY_BUFFER_STATE b; char *buf; @@ -1564,7 +1593,7 @@ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len ) /* Get memory for full buffer, including space for trailing EOB's. */ n = _yybytes_len + 2; - buf = (char *) yyalloc(n ); + buf = (char *) yyalloc(n ,yyscanner ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); @@ -1573,7 +1602,7 @@ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len ) buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; - b = yy_scan_buffer(buf,n ); + b = yy_scan_buffer(buf,n ,yyscanner); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); @@ -1589,7 +1618,7 @@ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len ) #define YY_EXIT_FAILURE 2 #endif -static void yy_fatal_error (yyconst char* msg ) +static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); @@ -1604,106 +1633,241 @@ static void yy_fatal_error (yyconst char* msg ) /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ - yytext[yyleng] = (yy_hold_char); \ - (yy_c_buf_p) = yytext + yyless_macro_arg; \ - (yy_hold_char) = *(yy_c_buf_p); \ - *(yy_c_buf_p) = '\0'; \ + 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 current line number. - * +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. */ -int yyget_lineno (void) +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 input stream. - * +/** Get the current column number. + * @param yyscanner The scanner object. */ -FILE *yyget_in (void) +int yyget_column (yyscan_t yyscanner) { - return yyin; + 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 (void) +FILE *yyget_out (yyscan_t yyscanner) { - return yyout; + 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 (void) +int yyget_leng (yyscan_t yyscanner) { - return yyleng; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; } /** Get the current token. - * + * @param yyscanner The scanner object. */ -char *yyget_text (void) +char *yyget_text (yyscan_t yyscanner) { - return yytext; + 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 ) +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 ) +void yyset_in (FILE * in_str , yyscan_t yyscanner) { - yyin = in_str ; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = in_str ; } -void yyset_out (FILE * out_str ) +void yyset_out (FILE * out_str , yyscan_t yyscanner) { - yyout = out_str ; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = out_str ; } -int yyget_debug (void) +int yyget_debug (yyscan_t yyscanner) { - return yy_flex_debug; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; } -void yyset_debug (int bdebug ) +void yyset_debug (int bdebug , yyscan_t yyscanner) { - yy_flex_debug = bdebug ; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = bdebug ; } -static int yy_init_globals (void) +/* 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) + { - /* Initialization is the same as for the non-reentrant scanner. + 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. */ - (yy_buffer_stack) = 0; - (yy_buffer_stack_top) = 0; - (yy_buffer_stack_max) = 0; - (yy_c_buf_p) = (char *) 0; - (yy_init) = 0; - (yy_start) = 0; + 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 @@ -1721,24 +1885,32 @@ static int yy_init_globals (void) } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ -int yylex_destroy (void) +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 ); + yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); YY_CURRENT_BUFFER_LVALUE = NULL; - yypop_buffer_state(); + yypop_buffer_state(yyscanner); } /* Destroy the stack itself. */ - yyfree((yy_buffer_stack) ); - (yy_buffer_stack) = NULL; + 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( ); + yy_init_globals( yyscanner); + /* Destroy the main struct (reentrant only). */ + yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; return 0; } @@ -1747,7 +1919,7 @@ int yylex_destroy (void) */ #ifndef yytext_ptr -static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) { register int i; for ( i = 0; i < n; ++i ) @@ -1756,7 +1928,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) #endif #ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * s ) +static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) { register int n; for ( n = 0; s[n]; ++n ) @@ -1766,12 +1938,12 @@ static int yy_flex_strlen (yyconst char * s ) } #endif -void *yyalloc (yy_size_t size ) +void *yyalloc (yy_size_t size , yyscan_t yyscanner) { return (void *) malloc( size ); } -void *yyrealloc (void * ptr, yy_size_t 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 @@ -1783,11 +1955,11 @@ void *yyrealloc (void * ptr, yy_size_t size ) return (void *) realloc( (char *) ptr, size ); } -void yyfree (void * ptr ) +void yyfree (void * ptr , yyscan_t yyscanner) { free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" -#line 55 "shell_lex.l" +#line 53 "shell_lex.l" diff --git a/shell_lex.l b/shell_lex.l index 240b1ef..65f8987 100644 --- a/shell_lex.l +++ b/shell_lex.l @@ -17,12 +17,10 @@ */ %{ -#include "shell.h" +#include "shell_internal.h" #include #include -#define YY_INPUT(buf, result, max_size) result = shell_pull(buf, max_size); - static char *str_append(char *str, const char *src) { if(str) { size_t newlen = strlen(str) + strlen(src) + 1; @@ -39,16 +37,16 @@ static char *str_append(char *str, const char *src) { return strdup(src); } %} -%option noyywrap nounput noinput batch +%option noyywrap nounput noinput batch reentrant %x STR %% -["] { strval = NULL; BEGIN(STR); } +["] { yyextra->strval = NULL; BEGIN(STR); } ; return TOK_SEPARATOR; [[:space:]]+ return TOK_SPACE; [#] return TOK_COMMENT; -[^[:space:];"#]+ { strval = strdup(yytext); return TOK_STRING; } -[^\\"]+ strval = str_append(strval, yytext); -\\["] strval = str_append(strval, "\""); -\\ strval = str_append(strval, "\\"); +[^[: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/spl_cmdset.c b/spl_cmdset.c index 86503e5..f226efa 100644 --- a/spl_cmdset.c +++ b/spl_cmdset.c @@ -26,9 +26,9 @@ #include "config.h" #include "ingenic.h" -static int spl_memtest(int argc, char *argv[]); -static int spl_gpio(int argc, char *argv[]); -static int spl_boot(int argc, char *argv[]); +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", "[BASE ] - SDRAM test", spl_memtest }, @@ -37,14 +37,14 @@ const shell_command_t spl_cmdset[] = { { NULL, NULL, NULL } }; -static int spl_stage1_op(uint32_t op, uint32_t pin, uint32_t base, uint32_t size) { +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(), cfg_getenv("STAGE1_FILE"), op, pin, base, size); + int ret = ingenic_stage1_debugop(shell_device(ctx), cfg_getenv("STAGE1_FILE"), op, pin, base, size); if(ret == -1) perror("ingenic_stage1_debugop"); @@ -52,7 +52,7 @@ static int spl_stage1_op(uint32_t op, uint32_t pin, uint32_t base, uint32_t size return ret; } -static int spl_memtest(int argc, char *argv[]) { +static int spl_memtest(shell_context_t *ctx, int argc, char *argv[]) { if(argc != 1 && argc != 3) { printf("Usage: %s [BASE ]\n", argv[0]); @@ -66,7 +66,7 @@ static int spl_memtest(int argc, char *argv[]) { size = strtoul(argv[2], NULL, 0); } else { start = SDRAM_BASE; - size = ingenic_sdram_size(shell_device()); + size = ingenic_sdram_size(shell_device(ctx)); } if(cfg_getenv("STAGE1_FILE") == NULL) { @@ -77,7 +77,7 @@ static int spl_memtest(int argc, char *argv[]) { uint32_t fail; - int ret = ingenic_memtest(shell_device(), cfg_getenv("STAGE1_FILE"), start, size, &fail); + int ret = ingenic_memtest(shell_device(ctx), cfg_getenv("STAGE1_FILE"), start, size, &fail); if(ret == -1) { if(errno == EFAULT) { @@ -93,7 +93,7 @@ static int spl_memtest(int argc, char *argv[]) { return ret; } -static int spl_gpio(int argc, char *argv[]) { +static int spl_gpio(shell_context_t *ctx, int argc, char *argv[]) { if(argc != 3 || (strcmp(argv[2], "0") && strcmp(argv[2], "1"))) { printf("Usage: %s \n", argv[0]); printf(" STATE := 0 | 1\n"); @@ -101,15 +101,15 @@ static int spl_gpio(int argc, char *argv[]) { return -1; } - return spl_stage1_op(!strcmp(argv[2], "1") ? STAGE1_DEBUG_GPIO_SET : STAGE1_DEBUG_GPIO_CLEAR, atoi(argv[1]), 0, 0); + 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(int argc, char *argv[]) { +static int spl_boot(shell_context_t *ctx, int argc, char *argv[]) { if(argc != 1) { printf("Usage: %s\n", argv[0]); } - int ret = spl_stage1_op(STAGE1_DEBUG_BOOT, 0, 0, 0); + int ret = spl_stage1_op(ctx, STAGE1_DEBUG_BOOT, 0, 0, 0); if(ret == -1) return -1; @@ -120,7 +120,7 @@ static int spl_boot(int argc, char *argv[]) { return -1; } - ret = ingenic_loadstage(shell_device(), INGENIC_STAGE2, cfg_getenv("STAGE2_FILE")); + ret = ingenic_loadstage(shell_device(ctx), INGENIC_STAGE2, cfg_getenv("STAGE2_FILE")); if(ret == -1) { perror("ingenic_loadstage"); @@ -128,7 +128,7 @@ static int spl_boot(int argc, char *argv[]) { return -1; } - ret = ingenic_configure_stage2(shell_device()); + ret = ingenic_configure_stage2(shell_device(ctx)); if(ret == -1) perror("ingenic_configure_stage2"); diff --git a/usbboot_cmdset.c b/usbboot_cmdset.c index e177246..dd723bb 100644 --- a/usbboot_cmdset.c +++ b/usbboot_cmdset.c @@ -25,14 +25,14 @@ #include "ingenic.h" #include "config.h" -static int usbboot_boot(int argc, char *argv[]); -static int usbboot_load(int argc, char *argv[]); -static int usbboot_go(int argc, char *argv[]); -static int usbboot_nquery(int argc, char *argv[]); -static int usbboot_ndump(int argc, char *argv[]); -static int usbboot_nerase(int argc, char *argv[]); -static int usbboot_nprogram(int argc, char *argv[]); -static int usbboot_nload(int argc, char *argv[]); +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_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[] = { @@ -51,8 +51,8 @@ const shell_command_t usbboot_cmdset[] = { { NULL, NULL, NULL } }; -static int usbboot_boot(int argc, char *argv[]) { - int ret = ingenic_configure_stage2(shell_device()); +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"); @@ -60,14 +60,14 @@ static int usbboot_boot(int argc, char *argv[]) { return ret; } -static int usbboot_load(int argc, char *argv[]) { +static int usbboot_load(shell_context_t *ctx, int argc, char *argv[]) { if(argc != 3) { printf("Usage: %s \n", argv[0]); return -1; } - int ret = ingenic_load_sdram_file(shell_device(), strtoul(argv[2], NULL, 0), argv[1]); + int ret = ingenic_load_sdram_file(shell_device(ctx), strtoul(argv[2], NULL, 0), argv[1]); if(ret == -1) perror("ingenic_load_sdram_file"); @@ -75,14 +75,14 @@ static int usbboot_load(int argc, char *argv[]) { return ret; } -static int usbboot_go(int argc, char *argv[]) { +static int usbboot_go(shell_context_t *ctx, int argc, char *argv[]) { if(argc != 2) { printf("Usage: %s

\n", argv[0]); return -1; } - int ret = ingenic_go(shell_device(), strtoul(argv[1], NULL, 0)); + int ret = ingenic_go(shell_device(ctx), strtoul(argv[1], NULL, 0)); if(ret == -1) perror("ingenic_go"); @@ -90,7 +90,7 @@ static int usbboot_go(int argc, char *argv[]) { return ret; } -static int usbboot_nquery(int argc, char *argv[]) { +static int usbboot_nquery(shell_context_t *ctx, int argc, char *argv[]) { if(argc != 2) { printf("Usage: %s \n", argv[0]); @@ -99,7 +99,7 @@ static int usbboot_nquery(int argc, char *argv[]) { nand_info_t info; - int ret = ingenic_query_nand(shell_device(), atoi(argv[1]), &info); + int ret = ingenic_query_nand(shell_device(ctx), atoi(argv[1]), &info); if(ret == -1) { perror("ingenic_query_nand"); @@ -119,7 +119,7 @@ static int usbboot_nquery(int argc, char *argv[]) { return 0; } -static int usbboot_ndump(int argc, char *argv[]) { +static int usbboot_ndump(shell_context_t *ctx, int argc, char *argv[]) { if(argc != 5) { printf("Usage: %s \n", argv[0]); @@ -131,7 +131,7 @@ static int usbboot_ndump(int argc, char *argv[]) { if(cfg_getenv("NAND_RAW")) type |= NAND_RAW; - int ret = ingenic_dump_nand(shell_device(), atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), type, argv[4]); + 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"); @@ -139,14 +139,14 @@ static int usbboot_ndump(int argc, char *argv[]) { return ret; } -static int usbboot_nerase(int argc, char *argv[]) { +static int usbboot_nerase(shell_context_t *ctx, int argc, char *argv[]) { if(argc != 4) { printf("Usage: %s \n", argv[0]); return -1; } - int ret = ingenic_erase_nand(shell_device(), atoi(argv[1]), atoi(argv[2]), atoi(argv[3])); + int ret = ingenic_erase_nand(shell_device(ctx), atoi(argv[1]), atoi(argv[2]), atoi(argv[3])); if(ret == -1) perror("ingenic_erase_nand"); @@ -155,7 +155,7 @@ static int usbboot_nerase(int argc, char *argv[]) { } -static int usbboot_nprogram(int argc, char *argv[]) { +static int usbboot_nprogram(shell_context_t *ctx, int argc, char *argv[]) { if(argc != 4) { printf("Usage: %s \n", argv[0]); @@ -172,7 +172,7 @@ static int usbboot_nprogram(int argc, char *argv[]) { } else type = NO_OOB; - int ret = ingenic_program_nand(shell_device(), atoi(argv[1]), atoi(argv[2]), type, argv[3]); + int ret = ingenic_program_nand(shell_device(ctx), atoi(argv[1]), atoi(argv[2]), type, argv[3]); if(ret == -1) perror("ingenic_program_nand"); @@ -180,14 +180,14 @@ static int usbboot_nprogram(int argc, char *argv[]) { return ret; } -static int usbboot_nload(int argc, char *argv[]) { +static int usbboot_nload(shell_context_t *ctx, int argc, char *argv[]) { if(argc != 5) { printf("Usage: %s \n", argv[0]); return -1; } - int ret = ingenic_load_nand(shell_device(), atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), strtoul(argv[4], NULL, 0)); + 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"); From 7c1d9c0144c53472420f6f1cca62caec0290ef0f Mon Sep 17 00:00:00 2001 From: Sergey Gridassov Date: Fri, 10 Dec 2010 13:38:35 +0300 Subject: [PATCH 23/50] Implemented tab completion --- main.c | 3 +- shell.c | 93 +++++++++++++++++++++++++++++++++++++++++++++--- shell_builtins.c | 8 +++-- 3 files changed, 96 insertions(+), 8 deletions(-) diff --git a/main.c b/main.c index e94aa93..6a6470e 100644 --- a/main.c +++ b/main.c @@ -156,7 +156,7 @@ int main(int argc, char *argv[]) { goto exit_ingenic; } - if(config) + if(config) { if(shell_source(shell, config) == -1) { perror("shell_source"); @@ -164,6 +164,7 @@ int main(int argc, char *argv[]) { goto exit_shell; } + } if(cmd != NULL) { if(shell_execute(shell, cmd) == -1) { diff --git a/shell.c b/shell.c index 32e1d64..7dcf4de 100644 --- a/shell.c +++ b/shell.c @@ -103,7 +103,7 @@ int shell_run(shell_context_t *ctx, int argc, char *argv[]) { int ret = shell_enumerate_commands(ctx, shell_run_function, &data); - if(ret != 0) { + if(ret == 0) { debug(LEVEL_ERROR, "Bad command '%s'\n", argv[0]); errno = EINVAL; @@ -127,12 +127,12 @@ int shell_execute(shell_context_t *ctx, const char *cmd) { int state = STATE_WANTSTR; int argc = 0; char **argv = NULL; - int fret = -1; + int fret = 0; do { int noway = 0; - token = yylex(&scanner); + token = yylex(scanner); if((token == TOK_SEPARATOR || token == TOK_COMMENT || token == 0)) { if(argc > 0) { @@ -203,7 +203,7 @@ int shell_execute(shell_context_t *ctx, const char *cmd) { free(ptr); - yylex_destroy(&scanner); + yylex_destroy(scanner); return fret; } @@ -249,6 +249,88 @@ int shell_source(shell_context_t *ctx, const char *filename) { return 0; } +#ifdef WITH_READLINE +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; @@ -267,9 +349,12 @@ void shell_interactive(shell_context_t *ctx) { 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> "); diff --git a/shell_builtins.c b/shell_builtins.c index 675da32..701f820 100644 --- a/shell_builtins.c +++ b/shell_builtins.c @@ -136,9 +136,11 @@ static int builtin_redetect(shell_context_t *ctx, int argc, char *argv[]) { static int builtin_set(shell_context_t *ctx, int argc, char *argv[]) { - if(argc == 1 && cfg_environ) { - for(int i = 0; cfg_environ[i] != NULL; i++) - printf("%s\n", cfg_environ[i]); + 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]); From 9679d05aa0ff55f44d3dfb1f7303793756db59b1 Mon Sep 17 00:00:00 2001 From: Sergey Gridassov Date: Fri, 10 Dec 2010 14:41:16 +0300 Subject: [PATCH 24/50] Implemented shell argument validation; implemented fancy help printout --- shell.c | 61 ++++++++++++++++++++++++--- shell.h | 1 + shell_builtins.c | 104 +++++++++++++++++++++-------------------------- spl_cmdset.c | 20 +++------ usbboot_cmdset.c | 64 +++++------------------------ 5 files changed, 119 insertions(+), 131 deletions(-) diff --git a/shell.c b/shell.c index 7dcf4de..24a937f 100644 --- a/shell.c +++ b/shell.c @@ -88,12 +88,63 @@ static int shell_run_function(shell_context_t *ctx, const shell_command_t *cmd, shell_run_data_t *data = arg; if(strcmp(cmd->cmd, data->argv[0]) == 0) { - int ret = cmd->handler(ctx, data->argc, data->argv); + int invalid = 0; - if(ret == 0) - return 1; - else - return ret; + 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; } diff --git a/shell.h b/shell.h index 8a77369..f9255a4 100644 --- a/shell.h +++ b/shell.h @@ -27,6 +27,7 @@ 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); diff --git a/shell_builtins.c b/shell_builtins.c index 701f820..8f7f534 100644 --- a/shell_builtins.c +++ b/shell_builtins.c @@ -38,33 +38,62 @@ 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 }, - { "exit", "- Batch: stop current script, interactive: end session", builtin_exit }, - { "source", " - run specified script", builtin_source }, - { "echo", " - output specified string", builtin_echo }, - { "sleep", " - sleep a specified amount of time", builtin_sleep }, - { "set", "[VARIABLE] [VALUE] - print or set configuraton variables", builtin_set }, - { "safe", " [ARG]... - run command ignoring errors", builtin_safe }, + { "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 }, - { "rebuildcfg", " - Rebuild firmware configuration data", builtin_rebuildcfg }, + { "redetect", "Redetect CPU", builtin_redetect, NULL }, + { "rebuildcfg", "Rebuild firmware configuration data", builtin_rebuildcfg, NULL }, { NULL, NULL, NULL } }; -static int builtin_help(shell_context_t *ctx, int argc, char *argv[]) { -/* for(int i = 0; commands[i].cmd != NULL; i++) { - printf("%s %s\n", commands[i].cmd, commands[i].description); - } +static int help_maxwidth_function(shell_context_t *ctx, const shell_command_t *cmd, void *arg) { + int len = strlen(cmd->cmd), *maxlen = arg; - if(set_cmds) { - for(int i = 0; set_cmds[i].cmd != NULL; i++) - printf("%s %s\n", set_cmds[i].cmd, set_cmds[i].description); - }*/ + 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); @@ -72,12 +101,6 @@ static int builtin_exit(shell_context_t *ctx, int argc, char *argv[]) { } static int builtin_source(shell_context_t *ctx, int argc, char *argv[]) { - if(argc != 2) { - printf("Usage: %s \n", argv[0]); - - return -1; - } - int ret = shell_source(ctx, argv[1]); if(ret == -1) { @@ -90,12 +113,6 @@ static int builtin_source(shell_context_t *ctx, int argc, char *argv[]) { } static int builtin_echo(shell_context_t *ctx, int argc, char *argv[]) { - if(argc < 2) { - printf("Usage: %s \n", argv[0]); - - return -1; - } - for(int i = 1; i < argc; i++) { fputs(argv[i], stdout); @@ -106,12 +123,6 @@ static int builtin_echo(shell_context_t *ctx, int argc, char *argv[]) { } static int builtin_sleep(shell_context_t *ctx, int argc, char *argv[]) { - if(argc != 2) { - printf("Usage: %s \n", argv[0]); - - return -1; - } - uint32_t ms = atoi(argv[1]); usleep(ms * 1000); @@ -120,12 +131,6 @@ static int builtin_sleep(shell_context_t *ctx, int argc, char *argv[]) { } static int builtin_redetect(shell_context_t *ctx, int argc, char *argv[]) { - if(argc != 1) { - printf("Usage: %s\n", argv[0]); - - return -1; - } - if(ingenic_redetect(shell_device(ctx)) == -1) { perror("ingenic_redetect"); @@ -147,11 +152,6 @@ static int builtin_set(shell_context_t *ctx, int argc, char *argv[]) { } else if(argc == 3) { cfg_setenv(argv[1], argv[2]); - - } else { - printf("Usage: %s [VARIABLE] [VALUE]\n", argv[0]); - - return -1; } return 0; @@ -159,22 +159,10 @@ static int builtin_set(shell_context_t *ctx, int argc, char *argv[]) { static int builtin_rebuildcfg(shell_context_t *ctx, int argc, char *argv[]) { - if(argc != 1) { - printf("Usage: %s\n", argv[0]); - - return -1; - } - return ingenic_rebuild(shell_device(ctx)); } static int builtin_safe(shell_context_t *ctx, int argc, char *argv[]) { - if(argc < 2) { - printf("Usage: %s [ARG]...\n", argv[0]); - - return -1; - } - if(shell_run(ctx, argc - 1, argv + 1) == -1) perror("shell_run"); diff --git a/spl_cmdset.c b/spl_cmdset.c index f226efa..b988c61 100644 --- a/spl_cmdset.c +++ b/spl_cmdset.c @@ -31,10 +31,10 @@ 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", "[BASE ] - SDRAM test", spl_memtest }, - { "gpio", " - Set GPIO #PIN to STATE 0 or 1", spl_gpio }, - { "boot", " - Load stage2 USB bootloader", spl_boot }, - { NULL, NULL, NULL } + { "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) { @@ -53,12 +53,6 @@ static int spl_stage1_op(shell_context_t *ctx, uint32_t op, uint32_t pin, uint32 } static int spl_memtest(shell_context_t *ctx, int argc, char *argv[]) { - if(argc != 1 && argc != 3) { - printf("Usage: %s [BASE ]\n", argv[0]); - - return -1; - } - uint32_t start, size; if(argc == 3) { @@ -94,7 +88,7 @@ static int spl_memtest(shell_context_t *ctx, int argc, char *argv[]) { } static int spl_gpio(shell_context_t *ctx, int argc, char *argv[]) { - if(argc != 3 || (strcmp(argv[2], "0") && strcmp(argv[2], "1"))) { + if(strcmp(argv[2], "0") && strcmp(argv[2], "1")) { printf("Usage: %s \n", argv[0]); printf(" STATE := 0 | 1\n"); @@ -105,10 +99,6 @@ static int spl_gpio(shell_context_t *ctx, int argc, char *argv[]) { } static int spl_boot(shell_context_t *ctx, int argc, char *argv[]) { - if(argc != 1) { - printf("Usage: %s\n", argv[0]); - } - int ret = spl_stage1_op(ctx, STAGE1_DEBUG_BOOT, 0, 0, 0); if(ret == -1) diff --git a/usbboot_cmdset.c b/usbboot_cmdset.c index dd723bb..86c94b2 100644 --- a/usbboot_cmdset.c +++ b/usbboot_cmdset.c @@ -36,19 +36,19 @@ static int usbboot_nload(shell_context_t *ctx, int argc, char *argv[]); const shell_command_t usbboot_cmdset[] = { - { "boot", "- Reconfigure stage2", usbboot_boot }, - { "load", " - Load file to SDRAM", usbboot_load }, - { "go", "
- Jump to
", usbboot_go }, + { "boot", "Reconfigure stage2", usbboot_boot, NULL }, + { "load", "Load file to SDRAM", usbboot_load, " " }, + { "go", "Jump to
", usbboot_go, "
" }, - { "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 }, + { "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, NULL, NULL, NULL } }; static int usbboot_boot(shell_context_t *ctx, int argc, char *argv[]) { @@ -61,12 +61,6 @@ static int usbboot_boot(shell_context_t *ctx, int argc, char *argv[]) { } static int usbboot_load(shell_context_t *ctx, int argc, char *argv[]) { - if(argc != 3) { - printf("Usage: %s \n", argv[0]); - - return -1; - } - int ret = ingenic_load_sdram_file(shell_device(ctx), strtoul(argv[2], NULL, 0), argv[1]); if(ret == -1) @@ -76,12 +70,6 @@ static int usbboot_load(shell_context_t *ctx, int argc, char *argv[]) { } static int usbboot_go(shell_context_t *ctx, int argc, char *argv[]) { - if(argc != 2) { - printf("Usage: %s
\n", argv[0]); - - return -1; - } - int ret = ingenic_go(shell_device(ctx), strtoul(argv[1], NULL, 0)); if(ret == -1) @@ -91,12 +79,6 @@ static int usbboot_go(shell_context_t *ctx, int argc, char *argv[]) { } static int usbboot_nquery(shell_context_t *ctx, int argc, char *argv[]) { - if(argc != 2) { - printf("Usage: %s \n", argv[0]); - - return -1; - } - nand_info_t info; int ret = ingenic_query_nand(shell_device(ctx), atoi(argv[1]), &info); @@ -120,12 +102,6 @@ static int usbboot_nquery(shell_context_t *ctx, int argc, char *argv[]) { } static int usbboot_ndump(shell_context_t *ctx, int argc, char *argv[]) { - if(argc != 5) { - printf("Usage: %s \n", argv[0]); - - return -1; - } - int type = strcmp(argv[0], "ndump_oob") ? NO_OOB : OOB_ECC; if(cfg_getenv("NAND_RAW")) @@ -140,12 +116,6 @@ static int usbboot_ndump(shell_context_t *ctx, int argc, char *argv[]) { } static int usbboot_nerase(shell_context_t *ctx, int argc, char *argv[]) { - if(argc != 4) { - printf("Usage: %s \n", argv[0]); - - return -1; - } - int ret = ingenic_erase_nand(shell_device(ctx), atoi(argv[1]), atoi(argv[2]), atoi(argv[3])); if(ret == -1) @@ -156,12 +126,6 @@ static int usbboot_nerase(shell_context_t *ctx, int argc, char *argv[]) { } static int usbboot_nprogram(shell_context_t *ctx, int argc, char *argv[]) { - if(argc != 4) { - printf("Usage: %s \n", argv[0]); - - return -1; - } - int type = strcmp(argv[0], "nprogram_oob") ? NO_OOB : OOB_ECC; if(strcmp(argv[0], "nprogram_oob") == 0) { @@ -181,12 +145,6 @@ static int usbboot_nprogram(shell_context_t *ctx, int argc, char *argv[]) { } static int usbboot_nload(shell_context_t *ctx, int argc, char *argv[]) { - if(argc != 5) { - printf("Usage: %s \n", argv[0]); - - return -1; - } - 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) From 9773d34f38157e305778d1c77c6a03979c7e45e2 Mon Sep 17 00:00:00 2001 From: Sergey Gridassov Date: Fri, 10 Dec 2010 15:14:43 +0300 Subject: [PATCH 25/50] Implemented transfer progress --- ingenic.c | 45 +++++++++++++++++++++++++---- ingenic.h | 8 +++++- shell.c | 74 +++++++++++++++++++++++++++++++++++++++++++----- shell_internal.h | 1 + 4 files changed, 114 insertions(+), 14 deletions(-) diff --git a/ingenic.c b/ingenic.c index 30164c5..bb5ec24 100644 --- a/ingenic.c +++ b/ingenic.c @@ -34,6 +34,12 @@ #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; }; handle->cfg.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; }; handle->nand.nand_##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; @@ -138,8 +144,9 @@ int ingenic_redetect(void *hndl) { handle->type = type; - if(CMDSET(prev) != CMDSET(type) && handle->callbacks && handle->callbacks->cmdset_change) - handle->callbacks->cmdset_change(handle->callbacks_data); + if(CMDSET(prev) != CMDSET(type)) { + CALLBACK(cmdset_change, CMDSET(type)); + } return 0; } @@ -169,10 +176,6 @@ void ingenic_close(void *hndl) { free(handle); } -#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; }; handle->cfg.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; }; handle->nand.nand_##var = v; } - int ingenic_rebuild(void *hndl) { HANDLE; @@ -390,6 +393,10 @@ int ingenic_configure_stage2(void *hndl) { 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; @@ -419,7 +426,14 @@ int ingenic_load_sdram(void *hndl, void *data, uint32_t base, uint32_t size) { 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; @@ -505,6 +519,9 @@ int ingenic_dump_nand(void *hndl, int cs, int start, int pages, int type, const 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; @@ -558,11 +575,17 @@ int ingenic_dump_nand(void *hndl, int cs, int start, int pages, int type, const start += chunk; pages -= chunk; + + value += chunk; + + CALLBACK(progress, PROGRESS_UPDATE, value, max); } free(iobuf); fclose(dest); + CALLBACK(progress, PROGRESS_FINI, 0, 0); + return ret; } @@ -612,6 +635,10 @@ int ingenic_program_nand(void *hndl, int cs, int start, int type, const char *fi 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; @@ -658,10 +685,15 @@ int ingenic_program_nand(void *hndl, int cs, int start, int type, const char *fi start += chunk; pages -= chunk; + value += chunk; + + CALLBACK(progress, PROGRESS_UPDATE, value, max); } free(iobuf); fclose(in); + + CALLBACK(progress, PROGRESS_FINI, 0, 0); return ret; } @@ -688,3 +720,4 @@ int ingenic_load_nand(void *hndl, int cs, int start, int pages, uint32_t base) { return 0; } + diff --git a/ingenic.h b/ingenic.h index 5e6b25c..8c09d5f 100644 --- a/ingenic.h +++ b/ingenic.h @@ -54,6 +54,10 @@ #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; @@ -111,8 +115,10 @@ typedef struct { uint8_t plane; } nand_info_t; + typedef struct { - void (*cmdset_change)(void *arg); + 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); diff --git a/shell.c b/shell.c index 24a937f..41b49c5 100644 --- a/shell.c +++ b/shell.c @@ -26,15 +26,18 @@ #include #include #include +#include #include "shell_internal.h" #include "debug.h" #include "ingenic.h" -static void shell_update_cmdset(void *arg); +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 { @@ -60,7 +63,7 @@ shell_context_t *shell_init(void *ingenic) { ingenic_set_callbacks(ingenic, &shell_callbacks, ctx); - shell_update_cmdset(ctx); + shell_update_cmdset(ingenic_cmdset(ingenic), ctx); return ctx; } @@ -424,15 +427,13 @@ void shell_interactive(shell_context_t *ctx) { #endif } -static void shell_update_cmdset(void *arg) { +static void shell_update_cmdset(uint32_t cmdset, void *arg) { shell_context_t *ctx = arg; ctx->set_cmds = NULL; - int set = ingenic_cmdset(ctx->device); - for(int i = 0; cmdsets[i].name != NULL; i++) { - if(cmdsets[i].set == set) { + 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; @@ -441,7 +442,7 @@ static void shell_update_cmdset(void *arg) { } } - debug(LEVEL_ERROR, "Shell: unknown cmdset %d\n", set); + debug(LEVEL_ERROR, "Shell: unknown cmdset %u\n", cmdset); } void *shell_device(shell_context_t *ctx) { @@ -452,3 +453,62 @@ 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/shell_internal.h b/shell_internal.h index e416c20..0378e26 100644 --- a/shell_internal.h +++ b/shell_internal.h @@ -35,6 +35,7 @@ typedef struct { char *line; const struct shell_command *set_cmds; int shell_exit; + int prev_progress; } shell_context_t; From 36cd4414a1588c4f8ad04d6e76644864518062f3 Mon Sep 17 00:00:00 2001 From: Sergey Gridassov Date: Fri, 10 Dec 2010 16:54:35 +0300 Subject: [PATCH 26/50] Implemented padding of NAND images --- ingenic.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/ingenic.c b/ingenic.c index bb5ec24..dd302bc 100644 --- a/ingenic.c +++ b/ingenic.c @@ -628,6 +628,14 @@ int ingenic_program_nand(void *hndl, int cs, int start, int type, const char *fi int file_size = ftell(in); fseek(in, 0, SEEK_SET); + int tail = file_size % page_size; + + if(tail) { + tail = page_size - tail; + + file_size += page_size - tail; + } + int pages = file_size / page_size; int ret = 0; @@ -643,10 +651,14 @@ int ingenic_program_nand(void *hndl, int cs, int start, int type, const char *fi int chunk = pages < chunk_pages ? pages : chunk_pages; int bytes = chunk * page_size; - debug(LEVEL_DEBUG, "Writing %d pages from %d\n", chunk, start); - 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); From aca1d172493a837f12c6609694a4520d82b69648 Mon Sep 17 00:00:00 2001 From: Sergey Gridassov Date: Fri, 10 Dec 2010 17:02:51 +0300 Subject: [PATCH 27/50] Fixed 'unused result' warnings --- Makefile | 2 +- ingenic.c | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index c43c028..c201db8 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ endif CC = gcc TARGET = 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 -CFLAGS = --std=gnu99 -Wall -Werror -O2 $(shell pkg-config libusb-1.0 --cflags) +CFLAGS = --std=gnu99 -Wall -Werror -O2 $(shell pkg-config libusb-1.0 --cflags) -Wunused-result LIBS += $(shell pkg-config libusb-1.0 --libs) OBJECTS = ${SOURCES:.c=.o} diff --git a/ingenic.c b/ingenic.c index dd302bc..5d84253 100644 --- a/ingenic.c +++ b/ingenic.c @@ -290,10 +290,18 @@ int ingenic_loadstage(void *hndl, int id, const char *file) { fseek(fd, 0, SEEK_SET); void *data = malloc(size); - fread(data, size, 1, fd); + size_t read_bytes = fread(data, size, 1, 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) { @@ -452,10 +460,18 @@ int ingenic_load_sdram_file(void *hndl, uint32_t base, const char *file) { fseek(fd, 0, SEEK_SET); void *data = malloc(size); - fread(data, size, 1, fd); + size_t bytes = fread(data, size, 1, fd); fclose(fd); + if(bytes != size) { + free(data); + + errno = EIO; + + return -1; + } + int ret = ingenic_load_sdram(handle, data, base, size); free(data); From 90652cdb75b5ecc244973e8b4a0cd21e40e96bc0 Mon Sep 17 00:00:00 2001 From: Sergey Gridassov Date: Fri, 10 Dec 2010 17:21:15 +0300 Subject: [PATCH 28/50] Fixed loading to memory --- ingenic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ingenic.c b/ingenic.c index 5d84253..368495c 100644 --- a/ingenic.c +++ b/ingenic.c @@ -290,7 +290,7 @@ int ingenic_loadstage(void *hndl, int id, const char *file) { fseek(fd, 0, SEEK_SET); void *data = malloc(size); - size_t read_bytes = fread(data, size, 1, fd); + size_t read_bytes = fread(data, 1, size, fd); fclose(fd); @@ -460,7 +460,7 @@ int ingenic_load_sdram_file(void *hndl, uint32_t base, const char *file) { fseek(fd, 0, SEEK_SET); void *data = malloc(size); - size_t bytes = fread(data, size, 1, fd); + size_t bytes = fread(data, 1, size, fd); fclose(fd); From 0c9dd55ec7b500bd42d4994d1938ebff0cebb20a Mon Sep 17 00:00:00 2001 From: Sergey Gridassov Date: Fri, 10 Dec 2010 17:48:09 +0300 Subject: [PATCH 29/50] Fixed erroneous file size correction --- ingenic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ingenic.c b/ingenic.c index 368495c..02ab79c 100644 --- a/ingenic.c +++ b/ingenic.c @@ -649,7 +649,7 @@ int ingenic_program_nand(void *hndl, int cs, int start, int type, const char *fi if(tail) { tail = page_size - tail; - file_size += page_size - tail; + file_size += tail; } int pages = file_size / page_size; From be5355d74e1926322e269108ee7a0d4b9ed84231 Mon Sep 17 00:00:00 2001 From: Sergey Gridassov Date: Fri, 10 Dec 2010 18:05:47 +0300 Subject: [PATCH 30/50] Inserted load delays --- ingenic.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ingenic.c b/ingenic.c index 02ab79c..aa22d0c 100644 --- a/ingenic.c +++ b/ingenic.c @@ -329,6 +329,8 @@ int ingenic_loadstage(void *hndl, int id, const char *file) { if(ret == -1) return -1; + usleep(250); + if(id == INGENIC_STAGE2) return ingenic_redetect(hndl); else From 2efaff5c6d78e805c01bad62ac25d306f70867dc Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Sat, 11 Dec 2010 21:25:42 +0300 Subject: [PATCH 31/50] Moved message in ingenic_load_sdram to loglevel LEVEL_DEBUG to not distract progressbar. --- ingenic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ingenic.c b/ingenic.c index 02ab79c..2701ad9 100644 --- a/ingenic.c +++ b/ingenic.c @@ -408,8 +408,8 @@ int ingenic_load_sdram(void *hndl, void *data, uint32_t base, uint32_t size) { while(size) { int block = size > STAGE2_IOBUF ? STAGE2_IOBUF : size; - printf("Loading %d bytes from %p to 0x%08X\n", block, data, base); - + 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; From 4a78684cbad084cb3d8d88fba44fee95ff223b06 Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Sat, 11 Dec 2010 21:26:17 +0300 Subject: [PATCH 32/50] Fix dump script. --- dump.scr | 2 -- 1 file changed, 2 deletions(-) diff --git a/dump.scr b/dump.scr index 93d19ac..d5a027a 100644 --- a/dump.scr +++ b/dump.scr @@ -10,8 +10,6 @@ echo "Configured for bootloader IO!" ndump_oob 0 0 128 "dump/nand.bin" -exit - set NAND_RAW set NAND_ECCPOS 8 rebuildcfg From 6a1f4864e446a72be20744e6f78692d65195478d Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Sun, 12 Dec 2010 00:08:05 +0300 Subject: [PATCH 33/50] Reworked directory structure. --- COPYING | 2 +- README | 5 +++++ boot.cfg | 4 ---- config/boot.cfg | 4 ++++ initial.cfg => config/initial.cfg | 4 ++-- fw.bin => firmware/spl_stage1.bin | Bin firmware/spl_stage2_usb.bin | Bin 0 -> 31860 bytes config.h => include/config.h | 0 debug.h => include/debug.h | 0 devmgr.h => include/devmgr.h | 0 ingenic.h => include/ingenic.h | 0 shell.h => include/shell.h | 0 shell_internal.h => include/shell_internal.h | 0 usbdev.h => include/usbdev.h | 0 dump.scr => script/dump_minios.scr | 0 Makefile => src/Makefile | 4 ++-- config.c => src/config.c | 0 debug.c => src/debug.c | 0 devmgr.c => src/devmgr.c | 0 ingenic.c => src/ingenic.c | 0 main.c => src/main.c | 0 shell.c => src/shell.c | 0 shell_builtins.c => src/shell_builtins.c | 0 shell_lex.c => src/shell_lex.c | 0 shell_lex.l => src/shell_lex.l | 0 spl_cmdset.c => src/spl_cmdset.c | 0 usbboot_cmdset.c => src/usbboot_cmdset.c | 0 usbdev.c => src/usbdev.c | 0 usb_boot.bin | Bin 31796 -> 0 bytes 29 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 README delete mode 100644 boot.cfg create mode 100644 config/boot.cfg rename initial.cfg => config/initial.cfg (95%) rename fw.bin => firmware/spl_stage1.bin (100%) create mode 100644 firmware/spl_stage2_usb.bin rename config.h => include/config.h (100%) rename debug.h => include/debug.h (100%) rename devmgr.h => include/devmgr.h (100%) rename ingenic.h => include/ingenic.h (100%) rename shell.h => include/shell.h (100%) rename shell_internal.h => include/shell_internal.h (100%) rename usbdev.h => include/usbdev.h (100%) rename dump.scr => script/dump_minios.scr (100%) rename Makefile => src/Makefile (80%) rename config.c => src/config.c (100%) rename debug.c => src/debug.c (100%) rename devmgr.c => src/devmgr.c (100%) rename ingenic.c => src/ingenic.c (100%) rename main.c => src/main.c (100%) rename shell.c => src/shell.c (100%) rename shell_builtins.c => src/shell_builtins.c (100%) rename shell_lex.c => src/shell_lex.c (100%) rename shell_lex.l => src/shell_lex.l (100%) rename spl_cmdset.c => src/spl_cmdset.c (100%) rename usbboot_cmdset.c => src/usbboot_cmdset.c (100%) rename usbdev.c => src/usbdev.c (100%) delete mode 100644 usb_boot.bin diff --git a/COPYING b/COPYING index 78d994c..e4cc176 100644 --- a/COPYING +++ b/COPYING @@ -1,4 +1,4 @@ -fw.bin, usb_boot.bin are (c) Ingenic Semiconductor Co.,Ltd. +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/README b/README new file mode 100644 index 0000000..e16acdd --- /dev/null +++ b/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/boot.cfg b/boot.cfg deleted file mode 100644 index 7696940..0000000 --- a/boot.cfg +++ /dev/null @@ -1,4 +0,0 @@ -source initial.cfg - -boot - diff --git a/config/boot.cfg b/config/boot.cfg new file mode 100644 index 0000000..e16f9b7 --- /dev/null +++ b/config/boot.cfg @@ -0,0 +1,4 @@ +source script/initial.cfg + +boot + diff --git a/initial.cfg b/config/initial.cfg similarity index 95% rename from initial.cfg rename to config/initial.cfg index 924d485..eb0c30c 100644 --- a/initial.cfg +++ b/config/initial.cfg @@ -1,8 +1,8 @@ # Configuration variables: # STAGE1_FILE, STAGE2_FILE -set STAGE1_FILE fw.bin -set STAGE2_FILE usb_boot.bin +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 diff --git a/fw.bin b/firmware/spl_stage1.bin similarity index 100% rename from fw.bin rename to firmware/spl_stage1.bin diff --git a/firmware/spl_stage2_usb.bin b/firmware/spl_stage2_usb.bin new file mode 100644 index 0000000000000000000000000000000000000000..8f11c6f0f27a111dda04afa5d481763b02e7a4e4 GIT binary patch literal 31860 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

@4CBw<-LSEseJhz z%U1*11?9IdS^258wM&4?h3{6@FG;Mu^Um6fzFWEEo~ho|uUxXKehM5^`P!vGWmUse z?bzSN%GWNv+i!Luo{cN-T()w_?P!X3iVA*-wGOo3y#8V^S#{F8Rf)B1OHdQ~LAj3| z-{^m}8#lJcJ{p64f@M{|KcareVMVgIUcnU~@Vqy1xr3OAdp&OySIu+yvKy{3Ts|mu zThhFFb2 zv;iEdS0qUJ|8TaRx@wy&Rozi>9G0PR+_0@m#tS~fwbNoI&6=H~|$%*kT`_Hy^b{*1l9 z`N3AJzOK${-Lz@rCTn9$%cGddNj41T^y2pQ`Yj5BvX4$tcH0zXADN;oHbvQorzpF1 zin3b@${yZ0j+Qux(3awg;3~&OS~mS}&)b6Q5U!u&!XHBPnsDvGbsAUc&nL>mj2XAz zUiYC@35#FH$K{~dSEa5 zUz|4+>n+oQSjlj5dKk|h1~IMZb1+MhX+;KaWiTozjn8R{FH<8lbbFV#5|KFXu0R%z zqX5T$M^P->aap+7hces+b)e4KRIc&wK1e+M$Ne)UGVcnYyQstK|M|bjL*kbHfw-e4 z?l*|L=6Z1(amD6{>)b4EHx6&Swo2R;s8cy#+&0`BV7Rlm8t^-bKSXoBLfjJmE*JMr zl%G%GH=K^qdb9`p^Pdzqf%l{D6Za6lqC4zG+_zDuyIS0e8REWvow(1S&p7IwT#FL3w{NBG1Z9gsUTL{_{AKotR vIh5lgD6WJ0C3ISFKN3S9xMTCjJr@zT=@HNe&lR}Jah(E=YtZNE2gLoqO;^PA From 8c9d1a8300c91346b9de9e42d1a524ba3a7f292e Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Sun, 12 Dec 2010 00:08:29 +0300 Subject: [PATCH 34/50] Added scripts for easy setting of XZ0032 ECC modes. --- script/ecc_boot.scr | 3 +++ script/ecc_normal.scr | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 script/ecc_boot.scr create mode 100644 script/ecc_normal.scr diff --git a/script/ecc_boot.scr b/script/ecc_boot.scr new file mode 100644 index 0000000..a895357 --- /dev/null +++ b/script/ecc_boot.scr @@ -0,0 +1,3 @@ +set NAND_ECCPOS 3 +rebuildcfg +boot diff --git a/script/ecc_normal.scr b/script/ecc_normal.scr new file mode 100644 index 0000000..7f54054 --- /dev/null +++ b/script/ecc_normal.scr @@ -0,0 +1,3 @@ +set NAND_ECCPOS 8 +rebuildcfg +boot From 56cd69db56c1775fbab8327e9ccf99c910053552 Mon Sep 17 00:00:00 2001 From: Dmitriy Beykun Date: Sun, 12 Dec 2010 00:27:37 +0300 Subject: [PATCH 35/50] Added minios restore script. --- script/restore_minios.scr | 42 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 script/restore_minios.scr diff --git a/script/restore_minios.scr b/script/restore_minios.scr new file mode 100644 index 0000000..c104bd9 --- /dev/null +++ b/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 script/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 ----" From 64290a8df006a42afc118fef18e0048e97d5535a Mon Sep 17 00:00:00 2001 From: Dmitriy Beykun Date: Sun, 12 Dec 2010 00:30:03 +0300 Subject: [PATCH 36/50] Added typical XZ0032 linux flash script. --- script/flash_xz0032_linux.scr | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 script/flash_xz0032_linux.scr diff --git a/script/flash_xz0032_linux.scr b/script/flash_xz0032_linux.scr new file mode 100644 index 0000000..3c858ef --- /dev/null +++ b/script/flash_xz0032_linux.scr @@ -0,0 +1,34 @@ +#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 "Configuring for bootloader IO" +source script/ecc_boot.scr +echo "Configured for bootloader IO" + +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 2048 uImage +echo "Flashed kernel" + +echo "Configuring for standard IO" +source script/ecc_normal.scr +echo "Configured for standard IO" + +echo "Flashing rootfs" +nprogram 0 4096 rootfs.yaffs2 +echo "Flashed rootfs" + +echo "---- All done ----" From 1b0126410f92d095a02dd8a5b875ff7e5aee8aa0 Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Sun, 12 Dec 2010 02:53:58 +0300 Subject: [PATCH 37/50] Fixed paths. --- config/boot.cfg | 2 +- script/restore_minios.scr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/boot.cfg b/config/boot.cfg index e16f9b7..15993e7 100644 --- a/config/boot.cfg +++ b/config/boot.cfg @@ -1,4 +1,4 @@ -source script/initial.cfg +source config/initial.cfg boot diff --git a/script/restore_minios.scr b/script/restore_minios.scr index c104bd9..cb8f369 100644 --- a/script/restore_minios.scr +++ b/script/restore_minios.scr @@ -4,7 +4,7 @@ echo "---- Restore MINIOS script ----" echo "Including initial config for 4750 XZ0032 board" -source script/boot.cfg +source config/boot.cfg echo "jzboot successfully configured for XZ0032" echo "Erasing all flash" From 27d48e973438c1165a384be6475dd64b65c400b9 Mon Sep 17 00:00:00 2001 From: Ivan Epifanov Date: Sun, 12 Dec 2010 04:20:37 +0300 Subject: [PATCH 38/50] Fixed rootfs NAND settings in XZ0032 sample flashing script. --- script/flash_xz0032_linux.scr | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/script/flash_xz0032_linux.scr b/script/flash_xz0032_linux.scr index 3c858ef..a1edd82 100644 --- a/script/flash_xz0032_linux.scr +++ b/script/flash_xz0032_linux.scr @@ -23,12 +23,16 @@ echo "Flashing kernel" nprogram 0 2048 uImage echo "Flashed kernel" -echo "Configuring for standard IO" -source script/ecc_normal.scr -echo "Configured for standard IO" +echo "Configuring for rootfs IO" +set NAND_ECCPOS 24 # Specify the ECC offset inside the oob data (0-[oobsize-1]) +set NAND_BADBLOCKPAGE 127 # Specify the page number of badblock flag inside a block(0-[PAGEPERBLOCK-1]) +set NAND_BCHBIT 4 # Specify the hardware BCH algorithm for 4750 (4|8) +rebuildcfg +boot +echo "Configured for rootfs IO" echo "Flashing rootfs" -nprogram 0 4096 rootfs.yaffs2 +nprogram_oob 0 4096 rootfs.yaffs2 echo "Flashed rootfs" echo "---- All done ----" From cfab51e6781325d1c8fe700c62439b8e0b2857ba Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Sun, 12 Dec 2010 20:30:05 +0300 Subject: [PATCH 39/50] Removed unneeded -Wunused-result flag. --- src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index b917479..09c994f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,7 +9,7 @@ endif CC = gcc TARGET = ../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 -CFLAGS = --std=gnu99 -Wall -Werror -I../include -O2 $(shell pkg-config libusb-1.0 --cflags) -Wunused-result +CFLAGS = --std=gnu99 -Wall -Werror -I../include -O2 $(shell pkg-config libusb-1.0 --cflags) LIBS += $(shell pkg-config libusb-1.0 --libs) OBJECTS = ${SOURCES:.c=.o} From f5075c8f8dd5eb19fb248c6cbc92e40d67185829 Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Tue, 21 Dec 2010 21:47:07 +0300 Subject: [PATCH 40/50] Removed -Werror from GCC flags, as it causes problems on a lot of GCC versions. --- src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index 09c994f..e7d34c4 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,7 +9,7 @@ endif CC = gcc TARGET = ../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 -CFLAGS = --std=gnu99 -Wall -Werror -I../include -O2 $(shell pkg-config libusb-1.0 --cflags) +CFLAGS = --std=gnu99 -Wall -I../include -O2 $(shell pkg-config libusb-1.0 --cflags) LIBS += $(shell pkg-config libusb-1.0 --libs) OBJECTS = ${SOURCES:.c=.o} From 743cae0cc6bfafbf6e462fc084256cef36115df3 Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Mon, 7 Mar 2011 03:16:13 +0300 Subject: [PATCH 41/50] Updated ECC settings to support new Linux kernel. --- config/initial.cfg | 2 +- script/flash_xz0032_linux.scr | 25 +++++++------------------ 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/config/initial.cfg b/config/initial.cfg index eb0c30c..a2c9370 100644 --- a/config/initial.cfg +++ b/config/initial.cfg @@ -23,7 +23,7 @@ set NAND_PAGESIZE 2048 # The page size of the NAND chip in bytes(512|2048| 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 8 # Specify the ECC offset inside the oob data (0-[oobsize-1]) +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 diff --git a/script/flash_xz0032_linux.scr b/script/flash_xz0032_linux.scr index a1edd82..0c55582 100644 --- a/script/flash_xz0032_linux.scr +++ b/script/flash_xz0032_linux.scr @@ -3,36 +3,25 @@ # 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 "Configuring for bootloader IO" -source script/ecc_boot.scr -echo "Configured for bootloader IO" - 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 2048 uImage -echo "Flashed kernel" +echo "Flashed loader" -echo "Configuring for rootfs IO" -set NAND_ECCPOS 24 # Specify the ECC offset inside the oob data (0-[oobsize-1]) -set NAND_BADBLOCKPAGE 127 # Specify the page number of badblock flag inside a block(0-[PAGEPERBLOCK-1]) -set NAND_BCHBIT 4 # Specify the hardware BCH algorithm for 4750 (4|8) -rebuildcfg -boot -echo "Configured for rootfs IO" +echo "Flashing kernel" +nprogram 0 512 uImage +echo "Flashed kernel" echo "Flashing rootfs" -nprogram_oob 0 4096 rootfs.yaffs2 +nprogram_oob 0 8192 rootfs.ubifs echo "Flashed rootfs" echo "---- All done ----" From da72c356388a3b64c5969cdddd2e48011c268d5c Mon Sep 17 00:00:00 2001 From: Xiangfu Liu Date: Tue, 5 Apr 2011 21:08:08 +0800 Subject: [PATCH 42/50] add Makefile.am for xburst-tools autoconf --- Makefile.am | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Makefile.am diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..7aed521 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,3 @@ +bin_PROGRAMS = jzboot +jzboot: + $(MAKE) -C ./src \ No newline at end of file From ce7446fd4c4743a685aa1d85b852743874c034c3 Mon Sep 17 00:00:00 2001 From: Xiangfu Liu Date: Tue, 5 Apr 2011 21:25:55 +0800 Subject: [PATCH 43/50] those file auto created by automake system --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 7735af4..873057c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +/.deps/ +/Makefile +/Makefile.in + jzboot *.o *.d From 8b4338fc90376ed10d814f8ae2ca1a0a4436c049 Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Tue, 5 Apr 2011 19:53:12 +0400 Subject: [PATCH 44/50] Changed everything to use autotools. --- .gitignore | 7 +++---- Makefile.am | 4 +--- src/Makefile | 31 ------------------------------- src/Makefile.am | 5 +++++ src/shell.c | 7 ++++--- 5 files changed, 13 insertions(+), 41 deletions(-) delete mode 100644 src/Makefile create mode 100644 src/Makefile.am diff --git a/.gitignore b/.gitignore index 873057c..53c644c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ -/.deps/ -/Makefile -/Makefile.in - +.deps +Makefile +Makefile.in jzboot *.o *.d diff --git a/Makefile.am b/Makefile.am index 7aed521..f963eff 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,3 +1 @@ -bin_PROGRAMS = jzboot -jzboot: - $(MAKE) -C ./src \ No newline at end of file +SUBDIRS = src \ No newline at end of file diff --git a/src/Makefile b/src/Makefile deleted file mode 100644 index e7d34c4..0000000 --- a/src/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -READLINE ?= 0 - - -ifneq (${READLINE},0) - LIBS += -lreadline - CPPFLAGS += -DWITH_READLINE -endif - -CC = gcc -TARGET = ../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 -CFLAGS = --std=gnu99 -Wall -I../include -O2 $(shell pkg-config libusb-1.0 --cflags) -LIBS += $(shell pkg-config libusb-1.0 --libs) - -OBJECTS = ${SOURCES:.c=.o} - -all: ${TARGET} - -${TARGET}: ${OBJECTS} - ${CC} ${LDFLAGS} -o $@ $^ ${LIBS} - -clean: - rm -f ${TARGET} ${OBJECTS} ${SOURCES:.c=.d} - -%.o: %.c - ${CC} ${CPPFLAGS} ${CFLAGS} -o $@ -MD -c $< - -%.c: %.l - flex -o $@ $< - --include ${SOURCES:.c=.d} diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..ac76761 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,5 @@ +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 \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index 41b49c5..4520ca3 100644 --- a/src/shell.c +++ b/src/shell.c @@ -17,9 +17,10 @@ * along with this program. If not, see . */ +#include #include #include -#ifdef WITH_READLINE +#ifdef HAVE_LIBREADLINE #include #include #endif @@ -51,7 +52,7 @@ static const struct { }; shell_context_t *shell_init(void *ingenic) { -#ifdef WITH_READLINE +#ifdef HAVE_LIBREADLINE rl_initialize(); #endif @@ -303,7 +304,7 @@ int shell_source(shell_context_t *ctx, const char *filename) { return 0; } -#ifdef WITH_READLINE +#ifdef HAVE_LIBREADLINE static shell_context_t *completion_context; static char **completion_matches; static int completion_matches_count = 0; From 04ed523633082c0bc49fd23f8424bdf1523b1ec4 Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Thu, 7 Apr 2011 14:11:22 +0400 Subject: [PATCH 45/50] Rename config.h to app_config.h, as old name conflicts with autoconf. --- include/{config.h => app_config.h} | 0 src/config.c | 2 +- src/ingenic.c | 2 +- src/shell_builtins.c | 2 +- src/spl_cmdset.c | 2 +- src/usbboot_cmdset.c | 4 ++-- 6 files changed, 6 insertions(+), 6 deletions(-) rename include/{config.h => app_config.h} (100%) diff --git a/include/config.h b/include/app_config.h similarity index 100% rename from include/config.h rename to include/app_config.h diff --git a/src/config.c b/src/config.c index cc94566..d58294c 100644 --- a/src/config.c +++ b/src/config.c @@ -21,7 +21,7 @@ #include #include -#include "config.h" +#include "app_config.h" #include "debug.h" char **cfg_environ = NULL; diff --git a/src/ingenic.c b/src/ingenic.c index 02989fe..60f8096 100644 --- a/src/ingenic.c +++ b/src/ingenic.c @@ -27,7 +27,7 @@ #include "ingenic.h" #include "usbdev.h" #include "debug.h" -#include "config.h" +#include "app_config.h" #define HANDLE ingenic_handle_t *handle = hndl #define BUILDTYPE(cmdset, id) (((cmdset) << 16) | (0x##id & 0xFFFF)) diff --git a/src/shell_builtins.c b/src/shell_builtins.c index 8f7f534..e85fb40 100644 --- a/src/shell_builtins.c +++ b/src/shell_builtins.c @@ -24,7 +24,7 @@ #include #include "shell.h" -#include "config.h" +#include "app_config.h" #include "ingenic.h" static int builtin_help(shell_context_t *ctx, int argc, char *argv[]); diff --git a/src/spl_cmdset.c b/src/spl_cmdset.c index b988c61..76a3c77 100644 --- a/src/spl_cmdset.c +++ b/src/spl_cmdset.c @@ -23,7 +23,7 @@ #include #include "shell.h" -#include "config.h" +#include "app_config.h" #include "ingenic.h" static int spl_memtest(shell_context_t *ctx, int argc, char *argv[]); diff --git a/src/usbboot_cmdset.c b/src/usbboot_cmdset.c index 86c94b2..4296456 100644 --- a/src/usbboot_cmdset.c +++ b/src/usbboot_cmdset.c @@ -21,9 +21,9 @@ #include #include "shell.h" -#include "config.h" +#include "app_config.h" #include "ingenic.h" -#include "config.h" +#include static int usbboot_boot(shell_context_t *ctx, int argc, char *argv[]); static int usbboot_load(shell_context_t *ctx, int argc, char *argv[]); From c9f7c85607ecd507e0366cefa2b29ea88be85140 Mon Sep 17 00:00:00 2001 From: Xiangfu Liu Date: Fri, 8 Apr 2011 16:08:20 +0800 Subject: [PATCH 46/50] remove useless config.h --- src/shell.c | 1 - src/usbboot_cmdset.c | 1 - 2 files changed, 2 deletions(-) diff --git a/src/shell.c b/src/shell.c index 4520ca3..37434b6 100644 --- a/src/shell.c +++ b/src/shell.c @@ -17,7 +17,6 @@ * along with this program. If not, see . */ -#include #include #include #ifdef HAVE_LIBREADLINE diff --git a/src/usbboot_cmdset.c b/src/usbboot_cmdset.c index 4296456..af6b43a 100644 --- a/src/usbboot_cmdset.c +++ b/src/usbboot_cmdset.c @@ -23,7 +23,6 @@ #include "shell.h" #include "app_config.h" #include "ingenic.h" -#include static int usbboot_boot(shell_context_t *ctx, int argc, char *argv[]); static int usbboot_load(shell_context_t *ctx, int argc, char *argv[]); From 2a49d7162782141e2d86b4c5500b50df3c4cf623 Mon Sep 17 00:00:00 2001 From: Xiangfu Liu Date: Fri, 8 Apr 2011 16:36:51 +0800 Subject: [PATCH 47/50] add print version --- src/main.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main.c b/src/main.c index 6a6470e..c304be9 100644 --- a/src/main.c +++ b/src/main.c @@ -24,6 +24,7 @@ #include "devmgr.h" #include "ingenic.h" #include "shell.h" +#include "xburst-tools-config.h" static void usage(const char *app) { printf( @@ -39,7 +40,8 @@ static void usage(const char *app) { " -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\n", app); + " -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) { @@ -51,7 +53,7 @@ int main(int argc, char *argv[]) { int idx = -1, enumerate = 0; char *cmd = NULL, *script = NULL, *config = NULL; - while((ch = getopt(argc, argv, "b:i:ec:d:C:")) != -1) { + while((ch = getopt(argc, argv, "b:i:ec:d:C:v")) != -1) { switch(ch) { case 'e': enumerate = 1; @@ -83,6 +85,11 @@ int main(int argc, char *argv[]) { break; + case 'v': + printf("%s %s\n", argv[0], PACKAGE_VERSION); + + return 0; + default: usage(argv[0]); From c7395700e4595dd40b67bc833303ab844d898216 Mon Sep 17 00:00:00 2001 From: Sergey Gridassov Date: Sun, 22 May 2011 17:59:12 +0400 Subject: [PATCH 48/50] Added Linux loader. --- include/debug.h | 1 + include/elf.h | 78 +++++++++++ include/elfldr.h | 10 ++ src/Makefile.am | 3 +- src/debug.c | 35 +++++ src/elfldr.c | 318 +++++++++++++++++++++++++++++++++++++++++++ src/ingenic.c | 34 ----- src/usbboot_cmdset.c | 9 ++ 8 files changed, 453 insertions(+), 35 deletions(-) create mode 100644 include/elf.h create mode 100644 include/elfldr.h create mode 100644 src/elfldr.c diff --git a/include/debug.h b/include/debug.h index 3998e84..c5eabbd 100644 --- a/include/debug.h +++ b/include/debug.h @@ -21,6 +21,7 @@ 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, ...); diff --git a/include/elf.h b/include/elf.h new file mode 100644 index 0000000..591047c --- /dev/null +++ b/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/include/elfldr.h b/include/elfldr.h new file mode 100644 index 0000000..b4a0b9a --- /dev/null +++ b/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/src/Makefile.am b/src/Makefile.am index ac76761..cee8e39 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,4 +2,5 @@ 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 \ No newline at end of file + 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/src/debug.c b/src/debug.c index 8506073..d9fa13b 100644 --- a/src/debug.c +++ b/src/debug.c @@ -45,3 +45,38 @@ void debug(int level, const char *fmt, ...) { 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/src/elfldr.c b/src/elfldr.c new file mode 100644 index 0000000..fc72573 --- /dev/null +++ b/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/src/ingenic.c b/src/ingenic.c index 60f8096..2c35d61 100644 --- a/src/ingenic.c +++ b/src/ingenic.c @@ -67,40 +67,6 @@ static const struct { { NULL, 0 } }; -static 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"); - } -} - static uint32_t ingenic_probe(void *usb_hndl) { char magic[9]; diff --git a/src/usbboot_cmdset.c b/src/usbboot_cmdset.c index af6b43a..6d9ec2c 100644 --- a/src/usbboot_cmdset.c +++ b/src/usbboot_cmdset.c @@ -23,10 +23,12 @@ #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[]); @@ -38,6 +40,7 @@ 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, " " }, @@ -151,3 +154,9 @@ static int usbboot_nload(shell_context_t *ctx, int argc, char *argv[]) { 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); +} + From 1cfb149d351c6e20bfa387de4dafdbc81cd5df11 Mon Sep 17 00:00:00 2001 From: Ignacio Garcia Perez Date: Sun, 22 May 2011 15:43:58 +0200 Subject: [PATCH 49/50] FIXED: values of CPUSPEED greater than 255 were misread because the value was directly read into handle->cfg.cpu_speed (uint8_t) before dividing it by the external crystal frequency, and overflow resulted. Now intermediate variable is used and only the final result of the division is placed in handle->cfg.cpu_speed. --- src/ingenic.c | 66 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/src/ingenic.c b/src/ingenic.c index 2c35d61..2be21ed 100644 --- a/src/ingenic.c +++ b/src/ingenic.c @@ -34,9 +34,22 @@ #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; }; handle->cfg.var = v; } +#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; }; handle->nand.nand_##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) @@ -144,24 +157,25 @@ void ingenic_close(void *hndl) { 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", ext_clk, v <= 27 && v >= 12); + CFGOPT("EXTCLK", handle->cfg.ext_clk, v <= 27 && v >= 12); CFGOPT("CPUSPEED", cpu_speed, (v % 12) == 0); - handle->cfg.cpu_speed /= handle->cfg.ext_clk; - CFGOPT("PHMDIV", phm_div, v <= 32 && v >= 2); - CFGOPT("USEUART", use_uart, 1); - CFGOPT("BAUDRATE", baudrate, 1); + 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", bus_width, (v == 16) || (v == 32)); + 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", bank_num, (v >= 4) && ((v % 4) == 0)); + CFGOPT("SDRAM_BANKS", handle->cfg.bank_num, (v >= 4) && ((v % 4) == 0)); handle->cfg.bank_num /= 4; - CFGOPT("SDRAM_ROWADDR", row_addr, 1); - CFGOPT("SDRAM_COLADDR", col_addr, 1); - CFGOPT("SDRAM_ISMOBILE", is_mobile, v == 0 || v == 1); - CFGOPT("SDRAM_ISBUSSHARE", is_busshare, v == 0 || v == 1); + 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)); @@ -172,20 +186,20 @@ int ingenic_rebuild(void *hndl) { handle->nand.cpuid = CPUID(handle->type); - NOPT("BUSWIDTH", bw, 1); - NOPT("ROWCYCLES", rc, 1); - NOPT("PAGESIZE", ps, 1); - NOPT("PAGEPERBLOCK", ppb, 1); - NOPT("FORCEERASE", force_erase, 1); + 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", os, 1); - NOPT("ECCPOS", eccpos, 1); - NOPT("BADBLOCKPOS", bbpos, 1); - NOPT("BADBLOCKPAGE", bbpage, 1); - NOPT("PLANENUM", plane, 1); - NOPT("BCHBIT", bchbit, 1); - NOPT("WPPIN", wppin, 1); - NOPT("BLOCKPERCHIP", bpc, 1); + 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; } From 792376fcbe4d1ece13c64382d46e3473e48a6044 Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Fri, 27 May 2011 12:06:59 +0400 Subject: [PATCH 50/50] Fix -v to be less ugly. --- src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index c304be9..0d9c151 100644 --- a/src/main.c +++ b/src/main.c @@ -86,7 +86,7 @@ int main(int argc, char *argv[]) { break; case 'v': - printf("%s %s\n", argv[0], PACKAGE_VERSION); + printf("JZboot version %s\n", PACKAGE_VERSION); return 0;