Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ClusterM/hakchi.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormadmonkey <madfkingmonkey@gmail.com>2017-01-01 06:14:20 +0300
committermadmonkey <madfkingmonkey@gmail.com>2017-01-03 14:17:58 +0300
commitde29903f48d7428c982e3bc80950b043a0d518e0 (patch)
treea97dd47f6edd272bcf85f82c071d01f9fff347b6
Initial commitv1.0
-rw-r--r--.gitignore12
-rw-r--r--.gitmodules6
-rw-r--r--3rdparty/busybox.url1
m---------3rdparty/mkbootimg0
m---------3rdparty/sunxi-tools0
-rw-r--r--3rdparty/sunxi-tools.diff28
-rw-r--r--LICENSE674
-rw-r--r--Makefile31
-rwxr-xr-xbin/extractimg17
-rw-r--r--bin/extractimg.bat35
-rwxr-xr-xbin/felboot11
-rwxr-xr-xbin/makeimg31
-rw-r--r--bin/makeimg.bat38
-rw-r--r--hakchi-gui/hakchi-gui.pro17
-rw-r--r--hakchi-gui/src/fel.cpp299
-rw-r--r--hakchi-gui/src/fel.h62
-rw-r--r--hakchi-gui/src/main.cpp31
-rw-r--r--hakchi-gui/src/mainwindow.cpp141
-rw-r--r--hakchi-gui/src/mainwindow.h39
-rw-r--r--hakchi-gui/src/mainwindow.ui265
-rw-r--r--hakchi-gui/src/md5int.c211
-rw-r--r--hakchi-gui/src/md5int.h27
-rw-r--r--hakchi-gui/src/wincon.cpp59
-rw-r--r--hakchi-gui/src/wincon.h20
-rw-r--r--hakchi-gui/src/worker.cpp408
-rw-r--r--hakchi-gui/src/worker.h51
-rw-r--r--importpath4
l---------mod/bin/chroot1
l---------mod/bin/cp1
l---------mod/bin/dd1
l---------mod/bin/gzip1
l---------mod/bin/ls1
l---------mod/bin/mkdir1
l---------mod/bin/mv1
l---------mod/bin/poweroff1
l---------mod/bin/rm1
-rw-r--r--mod/hakchi/backup39
-rw-r--r--mod/hakchi/config3
-rw-r--r--mod/hakchi/init80
-rw-r--r--mod/hakchi/rootfs/etc/inittab16
-rw-r--r--mod/hakchi/rootfs/etc/preinit8
-rw-r--r--mod/hakchi/rootfs/etc/profile35
-rwxr-xr-xmod/sbin/init39
-rw-r--r--r16-uboot/r16-uboot.diff243
-rw-r--r--r16-uboot/readme.md5
-rw-r--r--sntool/sntool.cpp245
-rw-r--r--udev/50-sunxi-fel.rules2
47 files changed, 3242 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2ef27f1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,12 @@
+*.pro.user
+*.img
+bin/mkbootimg
+bin/sntool
+bin/sunxi-fel
+bin/unpackbootimg
+build*/
+kernel*/
+data/
+dump/
+mod/bin/busybox
+mod/hakchi/transfer/
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..8bc2372
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,6 @@
+[submodule "3rdparty/mkbootimg"]
+ path = 3rdparty/mkbootimg
+ url = git@github.com:osm0sis/mkbootimg.git
+[submodule "3rdparty/sunxi-tools"]
+ path = 3rdparty/sunxi-tools
+ url = git@github.com:linux-sunxi/sunxi-tools.git
diff --git a/3rdparty/busybox.url b/3rdparty/busybox.url
new file mode 100644
index 0000000..96fedc5
--- /dev/null
+++ b/3rdparty/busybox.url
@@ -0,0 +1 @@
+https://busybox.net/downloads/binaries/latest/busybox-armv7l
diff --git a/3rdparty/mkbootimg b/3rdparty/mkbootimg
new file mode 160000
+Subproject f7472523d6195fa756db4e2cdac7bdeecec8bad
diff --git a/3rdparty/sunxi-tools b/3rdparty/sunxi-tools
new file mode 160000
+Subproject 1e219c0bb9051cb6252e7fb9e52c552e4aa21a2
diff --git a/3rdparty/sunxi-tools.diff b/3rdparty/sunxi-tools.diff
new file mode 100644
index 0000000..887b755
--- /dev/null
+++ b/3rdparty/sunxi-tools.diff
@@ -0,0 +1,28 @@
+diff --git a/fel_lib.c b/fel_lib.c
+index a484b4c..8d4d651 100644
+--- a/fel_lib.c
++++ b/fel_lib.c
+@@ -42,8 +42,14 @@ struct _felusb_handle {
+ bool iface_detached;
+ };
+
++void no_exit(int ec)
++{
++ (void)ec;
++}
++#define exit(x) {no_exit(x);return 0;}
++
+ /* a helper function to report libusb errors */
+-void usb_error(int rc, const char *caption, int exitcode)
++void no_usb_error(int rc, const char *caption, int exitcode)
+ {
+ if (caption)
+ fprintf(stderr, "%s ", caption);
+@@ -58,6 +64,7 @@ void usb_error(int rc, const char *caption, int exitcode)
+ if (exitcode != 0)
+ exit(exitcode);
+ }
++#define usb_error(x,y,z) {no_usb_error(x,y,z);if(z!=0)return 0;}
+
+ /*
+ * AW_USB_MAX_BULK_SEND and the timeout constant USB_TIMEOUT are related.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..9cecc1d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ 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.
+
+ {one line to give the program's name and a brief idea of what it does.}
+ Copyright (C) {year} {name of author}
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 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 <http://www.gnu.org/licenses/>.
+
+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:
+
+ {project} Copyright (C) {year} {fullname}
+ 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
+<http://www.gnu.org/licenses/>.
+
+ 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
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..0bef372
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,31 @@
+all: bin/sunxi-fel bin/mkbootimg bin/unpackbootimg mod/bin/busybox build/hakchi-gui bin/sntool
+
+bin/sunxi-fel: 3rdparty/sunxi-tools/sunxi-fel
+ @cp 3rdparty/sunxi-tools/sunxi-fel bin/
+
+3rdparty/sunxi-tools/sunxi-fel: 3rdparty/sunxi-tools/fel.c
+ @make -C 3rdparty/sunxi-tools sunxi-fel
+
+bin/mkbootimg: 3rdparty/mkbootimg/mkbootimg
+ @cp 3rdparty/mkbootimg/mkbootimg bin/
+
+3rdparty/mkbootimg/mkbootimg: 3rdparty/mkbootimg/mkbootimg.c
+ @make -C 3rdparty/mkbootimg
+
+bin/unpackbootimg: 3rdparty/mkbootimg/unpackbootimg
+ @cp 3rdparty/mkbootimg/unpackbootimg bin/
+
+3rdparty/mkbootimg/unpackbootimg: 3rdparty/mkbootimg/unpackbootimg.c
+ @make -C 3rdparty/mkbootimg
+
+mod/bin/busybox: 3rdparty/busybox.url
+ wget --no-use-server-timestamps $(shell cat $<) -O $@ && chmod +x $@ && upx -qq --best $@
+
+build/hakchi-gui: build/Makefile hakchi-gui/src/*
+ @make -C build
+
+build/Makefile: hakchi-gui/hakchi-gui.pro
+ @mkdir -p build && (cd build; qmake ../$< CONFIG+=release)
+
+bin/sntool: sntool/sntool.cpp
+ @g++ -std=gnu++11 -Wall -Wextra $< -o $@
diff --git a/bin/extractimg b/bin/extractimg
new file mode 100755
index 0000000..8d5d631
--- /dev/null
+++ b/bin/extractimg
@@ -0,0 +1,17 @@
+#!/bin/bash
+set -e
+
+img=$1
+if [ -z "$img" ]; then
+ img=./dump/kernel.img
+fi
+
+infile=$(basename "$img")
+inpath=./$(basename "$infile" .img)
+
+rm -rf "$inpath"
+mkdir "$inpath"
+unpackbootimg -i "$img" -o "$inpath"
+lzop -d "$inpath/$infile-ramdisk.gz" -o "$inpath/initramfs.cpio"
+mkdir "$inpath/initramfs"
+(cd "$inpath/initramfs";cpio -imd --no-preserve-owner --quiet -I "../initramfs.cpio")
diff --git a/bin/extractimg.bat b/bin/extractimg.bat
new file mode 100644
index 0000000..c6c7a2c
--- /dev/null
+++ b/bin/extractimg.bat
@@ -0,0 +1,35 @@
+@echo off
+
+set img=%~f1
+if "%img%"=="" goto error
+
+set infile=%~nx1
+set inpath=.\%~n1
+
+if exist "%inpath%" rd /s /q "%inpath%"
+if %errorlevel% neq 0 goto error
+
+md "%inpath%"
+if %errorlevel% neq 0 goto error
+
+unpackbootimg -i "%img%" -o "%inpath%"
+if %errorlevel% neq 0 goto error
+
+lzop -d "%inpath%\%infile%-ramdisk.gz" -o "%inpath%\initramfs.cpio"
+if %errorlevel% neq 0 goto error
+
+md "%inpath%\initramfs"
+if %errorlevel% neq 0 goto error
+
+cd "%inpath%\initramfs"
+if %errorlevel% neq 0 goto error
+
+cpio -imd --no-preserve-owner --quiet -I "..\initramfs.cpio"
+if %errorlevel% neq 0 goto error
+
+exit /b %errorlevel%
+
+:error
+if %errorlevel% equ 0 set errorlevel=7
+echo %0 %1 -^> exit %errorlevel% ?!?
+exit /b %errorlevel%
diff --git a/bin/felboot b/bin/felboot
new file mode 100755
index 0000000..9c22814
--- /dev/null
+++ b/bin/felboot
@@ -0,0 +1,11 @@
+#!/bin/bash
+set -e
+
+sunxi-fel version
+
+sunxi-fel write 0x2000 data/fes1.bin
+sunxi-fel exe 0x2000
+
+sunxi-fel -p write 0x43800000 kernel.img
+sunxi-fel -p write 0x47000000 data/uboot.bin
+sunxi-fel exe 0x47000000
diff --git a/bin/makeimg b/bin/makeimg
new file mode 100755
index 0000000..4f3a5f4
--- /dev/null
+++ b/bin/makeimg
@@ -0,0 +1,31 @@
+#!/bin/bash
+set -e
+
+inpath=$1
+if [ -z "$inpath" ]; then
+ inpath=./kernel
+fi
+
+infile=$(basename "$inpath").img
+img=./$infile
+
+rm -rf "$inpath/initramfs/hakchi/transfer"
+(cd "$inpath/../mod";cp -a * "../$inpath/initramfs/")
+if [ "$2" == "notx" ]; then
+ rm -rf "$inpath/initramfs/hakchi/transfer"
+fi
+upx -qq --best "$inpath/initramfs/sbin/cryptsetup" || true
+(cd "$inpath/initramfs";find . -print0 | sort -z | cpio -0o -H newc -R root:root --quiet > ../initramfs.cpio)
+lzop --best -f -o "$inpath/$infile-ramdisk.gz" "$inpath/initramfs.cpio"
+
+mkbootimg \
+--kernel "$inpath/$infile-zImage" \
+--ramdisk "$inpath/$infile-ramdisk.gz" \
+--cmdline "$(cat $inpath/$infile-cmdline)" \
+--board "$(cat $inpath/$infile-board)" \
+--base "$(cat $inpath/$infile-base)" \
+--pagesize "$(cat $inpath/$infile-pagesize)" \
+--kernel_offset "$(cat $inpath/$infile-kerneloff)" \
+--ramdisk_offset "$(cat $inpath/$infile-ramdiskoff)" \
+--tags_offset "$(cat $inpath/$infile-tagsoff)" \
+-o "$img"
diff --git a/bin/makeimg.bat b/bin/makeimg.bat
new file mode 100644
index 0000000..8d7959d
--- /dev/null
+++ b/bin/makeimg.bat
@@ -0,0 +1,38 @@
+@echo off
+
+set inpath=%~f1
+if "%inpath%"=="" goto error
+
+set infile=%~nx1.img
+set img=.\%~nx1.img
+
+if exist "%inpath%\initramfs\hakchi\transfer" rd /s /q "%inpath%\initramfs\hakchi\transfer"
+xcopy "%inpath%\..\mod" "%inpath%\initramfs" /h /y /c /r /s /q || cd >nul
+if "%2"=="notx" if exist "%inpath%\initramfs\hakchi\transfer" rd /s /q "%inpath%\initramfs\hakchi\transfer"
+if %errorlevel% neq 0 goto error
+
+upx -qq --best "%inpath%\initramfs\sbin\cryptsetup" || cd >nul
+
+mkbootfs "%inpath%\initramfs" > "%inpath%\initramfs.cpio"
+if %errorlevel% neq 0 goto error
+
+lzop --best -f -o "%inpath%\%infile%-ramdisk.gz" "%inpath%\initramfs.cpio"
+if %errorlevel% neq 0 goto error
+
+set /p cmdline=<"%inpath%\%infile%-cmdline"
+set /p board=<"%inpath%\%infile%-board"
+set /p base=<"%inpath%\%infile%-base"
+set /p pagesize=<"%inpath%\%infile%-pagesize"
+set /p kerneloff=<"%inpath%\%infile%-kerneloff"
+set /p ramdiskoff=<"%inpath%\%infile%-ramdiskoff"
+set /p tagsoff=<"%inpath%\%infile%-tagsoff"
+
+mkbootimg --kernel "%inpath%\%infile%-zImage" --ramdisk "%inpath%\%infile%-ramdisk.gz" --cmdline "%cmdline%" --board "%board%" --base "%base%" --pagesize "%pagesize%" --kernel_offset "%kerneloff%" --ramdisk_offset "%ramdiskoff%" --tags_offset "%tagsoff%" -o "%img%"
+if %errorlevel% neq 0 goto error
+
+exit /b %errorlevel%
+
+:error
+if %errorlevel% equ 0 set errorlevel=7
+echo %0 %1 %2 -^> exit %errorlevel% ?!?
+exit /b %errorlevel%
diff --git a/hakchi-gui/hakchi-gui.pro b/hakchi-gui/hakchi-gui.pro
new file mode 100644
index 0000000..8505b8a
--- /dev/null
+++ b/hakchi-gui/hakchi-gui.pro
@@ -0,0 +1,17 @@
+QT+=core gui
+greaterThan(QT_MAJOR_VERSION,4):QT+=widgets
+TARGET=hakchi-gui
+TEMPLATE=app
+
+INCLUDEPATH+=$${PWD}/../3rdparty/sunxi-tools $${PWD}/../3rdparty/sunxi-tools/include $${PWD}/../3rdparty/mkbootimg
+DEPENDPATH+=$${PWD}/src $${PWD}/../3rdparty/sunxi-tools $${PWD}/../3rdparty/sunxi-tools/include
+LIBS += $$system(pkg-config --libs \"libusb-1.0 >= 1.0.0\" --static)
+QMAKE_CFLAGS += $$system(pkg-config --cflags \"libusb-1.0 >= 1.0.0\") -std=gnu99 -DNDEBUG -Wall -Wextra
+QMAKE_CXXFLAGS += $$system(pkg-config --cflags \"libusb-1.0 >= 1.0.0\") -Wall -Wextra
+
+SOURCES += fel_lib.c soc_info.c progress.c
+
+SOURCES += $${PWD}/src/*.cpp
+SOURCES += $${PWD}/src/*.c
+HEADERS += $${PWD}/src/*.h
+FORMS += $${PWD}/src/*.ui
diff --git a/hakchi-gui/src/fel.cpp b/hakchi-gui/src/fel.cpp
new file mode 100644
index 0000000..67387b8
--- /dev/null
+++ b/hakchi-gui/src/fel.cpp
@@ -0,0 +1,299 @@
+#include "fel.h"
+#include <QScopedPointer>
+extern "C" {
+#include "fel_lib.h"
+}
+#include "md5int.h"
+#include <stdio.h>
+
+struct FeldevHandle:public feldev_handle{};
+static const char*fastboot="fastboot_test";
+
+struct spFree
+{
+ static inline void cleanup(void*pointer)
+ {
+ free(pointer);
+ }
+};
+
+uboot_t::uboot_t()
+{
+ memset(&md5,0,sizeof(md5));
+ cmdOffset=0;
+}
+
+void uboot_t::init(const QByteArray&ba)
+{
+ data=ba;
+ md5calc(data.data(),data.size(),md5);
+ cmdOffset=0;
+ QByteArray pattern("bootcmd=");
+ for(int i=0;i<(data.size()-pattern.size());i++)
+ {
+ if(memcmp(data.data()+i,pattern.data(),pattern.size())==0)
+ {
+ cmdOffset=i+pattern.size();
+ cmd=QByteArray(data.data()+cmdOffset);
+ break;
+ }
+ }
+ if(cmdOffset==0)
+ {
+ *this=uboot_t();
+ }
+}
+
+void uboot_t::doCmd(const char*str)
+{
+ size_t size=strlen(str);
+ Q_ASSERT(size<(size_t)cmd.size());
+ memset(data.data()+cmdOffset,0,cmd.size());
+ memcpy(data.data()+cmdOffset,str,size);
+}
+
+Fel::Fel(QObject*parent):QObject(parent)
+{
+ dev=0;
+ dramInitOk=false;
+ feldev_init();
+}
+
+Fel::~Fel()
+{
+ feldev_done(dev);
+}
+
+bool Fel::init()
+{
+ if(dev==0)
+ {
+#if 0
+ size_t size=0;
+ QScopedPointer<feldev_list_entry,spFree>devs(list_fel_devices(&size));
+ if(size==0)
+ {
+ return false;
+ }
+ if(size>1)
+ {
+ return false;
+ }
+#endif
+ dev=static_cast<FeldevHandle*>(feldev_open(-1,-1,AW_USB_VENDOR_ID,AW_USB_PRODUCT_ID));
+ while((dev!=0)&&(dev->soc_info->soc_id!=0x1667))
+ {
+ release();
+ sleep(2);
+ dev=static_cast<FeldevHandle*>(feldev_open(-1,-1,AW_USB_VENDOR_ID,AW_USB_PRODUCT_ID));
+ }
+ }
+ return dev!=0;
+}
+
+bool Fel::initDram(bool force)
+{
+ if(dramInitOk&&!force)
+ return true;
+
+ uint8_t buf[0x80];
+ if((size_t)fes1bin.size()<sizeof(buf))
+ return false;
+ if(!force)emit dataFlow(-sizeof(buf));
+ if((force)||(readMemory(fes1_base_m+fes1bin.size()-sizeof(buf),sizeof(buf),buf)==sizeof(buf)))
+ {
+ if((!force)&&(memcmp(buf,fes1bin.data()+fes1bin.size()-sizeof(buf),sizeof(buf))==0))
+ {
+ dramInitOk=true;
+ return true;
+ }
+ printf("uploading fes1.bin ...");
+ emit dataFlow(-fes1bin.size());
+ if(writeMemory(fes1_base_m,fes1bin.size(),fes1bin.data())==(size_t)fes1bin.size())
+ {
+ printf(" done\n");
+ dramInitOk=true;
+ return runCode(fes1_base_m,2);
+ }
+ printf(" failed\n");
+ }
+ return false;
+}
+
+void Fel::release()
+{
+ feldev_close(dev);
+ dev=0;
+}
+
+void Fel::setFes1bin(const QByteArray&data)
+{
+ fes1bin=data;
+}
+
+void Fel::setUboot(const QByteArray&data)
+{
+ uboot.init(data);
+}
+
+bool Fel::haveUboot()const
+{
+ return uboot.cmdOffset>0;
+}
+
+bool Fel::runCode(uint32_t addr,uint32_t s)
+{
+ if(init())
+ {
+ aw_fel_execute(dev,addr);
+ release();
+ if(s==0xffffffff)
+ {
+ dramInitOk=false;
+ return true;
+ }
+ sleep(s);
+ for(int i=0;i<8;i++)
+ if(init())
+ break;
+ return init();
+ }
+ return false;
+}
+
+bool Fel::runUbootCmd(const char*str,bool noreturn)
+{
+ if(init()&&haveUboot())
+ {
+ uboot.doCmd(str);
+ uint8_t buf[0x20];
+ emit dataFlow(-sizeof(buf));
+ if(!readMemory(uboot_base_m,sizeof(buf),buf)==sizeof(buf))
+ return false;
+ if(memcmp(buf,uboot.data.data(),sizeof(buf))==0)
+ {
+ size_t size=(uboot.cmd.size()+3)/4;
+ size*=4;
+ emit dataFlow(-size);
+ if(writeMemory(uboot_base_m+uboot.cmdOffset,size,uboot.data.data()+uboot.cmdOffset)!=size)
+ return false;
+ }
+ else
+ {
+ printf("uploading uboot.bin ...");
+ emit dataFlow(-uboot.data.size());
+ if(writeMemory(uboot_base_m,uboot.data.size(),uboot.data.data())!=(size_t)uboot.data.size())
+ {
+ printf(" failed\n");
+ return false;
+ }
+ printf(" done\n");
+ }
+ printf("%s\n",str);
+ return runCode(uboot_base_m,noreturn?0xffffffff:10);
+ }
+ return false;
+}
+
+static const size_t maxTransfer=0x10000;
+
+size_t Fel::readMemory(uint32_t addr,size_t size,void*buf)
+{
+ if(init())
+ {
+ if((addr>=dram_base)&&(!initDram()))
+ return 0;
+ size&=(~3);
+ size_t transfer=size;
+ while(transfer)
+ {
+ size_t b=qMin(transfer,maxTransfer);
+ aw_fel_read(dev,addr,buf,b);
+ emit dataFlow(b);
+ addr+=b;
+ buf=((uint8_t*)buf)+b;
+ transfer-=b;
+ }
+ return size;
+ }
+ return 0;
+}
+
+size_t Fel::writeMemory(uint32_t addr,size_t size,void*buf)
+{
+ if(init())
+ {
+ if((addr>=dram_base)&&(!initDram()))
+ return 0;
+ size&=(~3);
+ size_t transfer=size;
+ while(transfer)
+ {
+ size_t b=qMin(transfer,maxTransfer);
+ aw_fel_write(dev,buf,addr,b);
+ emit dataFlow(b);
+ addr+=b;
+ buf=((uint8_t*)buf)+b;
+ transfer-=b;
+ }
+ return size;
+ }
+ return 0;
+}
+
+size_t Fel::readFlash(uint32_t addr,size_t size,void*buf)
+{
+ if((!init())||(!haveUboot()))
+ return 0;
+ if(((size+addr%sector_size+sector_size-1)/sector_size)>flash_mem_size)
+ {
+ size_t sectors=(size+addr%sector_size+sector_size-1)/sector_size-flash_mem_size;
+ size_t read=readFlash(addr,sectors*sector_size-addr%sector_size,buf);
+ addr+=read;
+ size-=read;
+ buf=static_cast<uint8_t*>(buf)+read;
+ }
+ if(((size+addr%sector_size+sector_size-1)/sector_size)>flash_mem_size)
+ {
+ return 0;
+ }
+ char cmd[1024];
+ sprintf(cmd,"sunxi_flash phy_read %x %x %x;%s",flash_mem_base,addr/sector_size,(size+addr%sector_size+sector_size-1)/sector_size,fastboot);
+ if(runUbootCmd(cmd))
+ {
+ return readMemory(flash_mem_base+addr%sector_size,size,buf);
+ }
+ return 0;
+}
+
+size_t Fel::writeFlash(uint32_t addr,size_t size,void*buf)
+{
+ if((!init())||(!haveUboot()))
+ return 0;
+ if((addr%sector_size)!=0)
+ return 0;
+ if((size%sector_size)!=0)
+ return 0;
+ if((size/sector_size)>flash_mem_size)
+ {
+ size_t sectors=(size/sector_size)-flash_mem_size;
+ size_t write=writeFlash(addr,sectors*sector_size,buf);
+ if((write%sector_size)!=0)
+ return 0;
+ addr+=write;
+ size-=write;
+ buf=static_cast<uint8_t*>(buf)+write;
+ }
+ if((size/sector_size)>flash_mem_size)
+ {
+ return 0;
+ }
+ if(writeMemory(flash_mem_base,size,buf)==size)
+ {
+ char cmd[1024];
+ sprintf(cmd,"sunxi_flash phy_write %x %x %x;%s",flash_mem_base,addr/sector_size,size/sector_size,fastboot);
+ if(runUbootCmd(cmd))
+ return size;
+ }
+ return 0;
+}
diff --git a/hakchi-gui/src/fel.h b/hakchi-gui/src/fel.h
new file mode 100644
index 0000000..2bebb4a
--- /dev/null
+++ b/hakchi-gui/src/fel.h
@@ -0,0 +1,62 @@
+#ifndef FEL_H
+#define FEL_H
+
+#include <stdint.h>
+#include <unistd.h>
+#include <QObject>
+#include <QByteArray>
+
+struct FeldevHandle;
+
+struct uboot_t
+{
+ QByteArray data;
+ uint8_t md5[16];
+ QByteArray cmd;
+ uint32_t cmdOffset;
+
+ uboot_t();
+ void init(const QByteArray&ba);
+ void doCmd(const char*str);
+};
+
+#define fes1_base_m 0x2000u
+#define dram_base 0x40000000u
+#define uboot_base_m 0x47000000u
+#define uboot_base_f 0x100000u
+#define flash_mem_base 0x43800000u
+#define flash_mem_size 0x20u
+#define sector_size 0x20000u
+#define kernel_base_f (sector_size*0x30)
+#define kernel_base_m flash_mem_base
+#define kernel_max_size (uboot_base_m-flash_mem_base)
+#define kernel_max_flash_size (sector_size*0x20)
+
+class Fel:public QObject
+{
+ Q_OBJECT
+public:
+ Fel(QObject*parent=0);
+ ~Fel();
+ bool init();
+ bool initDram(bool force=false);
+ void release();
+ void setFes1bin(const QByteArray&data);
+ void setUboot(const QByteArray&data);
+ bool haveUboot()const;
+ bool runCode(uint32_t addr,uint32_t s);
+ bool runUbootCmd(const char*str,bool noreturn=false);
+ size_t readMemory(uint32_t addr,size_t size,void*buf);
+ size_t writeMemory(uint32_t addr,size_t size,void*buf);
+ size_t readFlash(uint32_t addr,size_t size,void*buf);
+ size_t writeFlash(uint32_t addr,size_t size,void*buf);
+signals:
+ void dataFlow(int flow);
+private:
+ FeldevHandle*dev;
+ QByteArray fes1bin;
+ uboot_t uboot;
+ bool dramInitOk;
+};
+
+#endif // FEL_H
diff --git a/hakchi-gui/src/main.cpp b/hakchi-gui/src/main.cpp
new file mode 100644
index 0000000..d41a131
--- /dev/null
+++ b/hakchi-gui/src/main.cpp
@@ -0,0 +1,31 @@
+#include "mainwindow.h"
+#include <QApplication>
+#include <QDir>
+#include <stdlib.h>
+
+int main(int argc,char*argv[])
+{
+ QDir dir(".");
+ for(int i=0;i<4;i++)
+ {
+ if(dir.exists("bin"))
+ break;
+ else
+ dir.cdUp();
+ }
+ if(dir.exists("bin"))
+ dir.setCurrent(dir.absolutePath());
+ QString path=QString::fromLocal8Bit(getenv("PATH"));
+#ifdef WIN32
+ path=QString("PATH=%1\\bin;%2").arg(dir.absolutePath()).arg(path);
+ _putenv(path.toLocal8Bit());
+#else
+ path=QString("%1/bin:%2").arg(dir.absolutePath()).arg(path);
+ setenv("PATH",path.toLocal8Bit(),1);
+#endif
+
+ QApplication a(argc,argv);
+ MainWindow w;
+ w.show();
+ return a.exec();
+}
diff --git a/hakchi-gui/src/mainwindow.cpp b/hakchi-gui/src/mainwindow.cpp
new file mode 100644
index 0000000..810acdb
--- /dev/null
+++ b/hakchi-gui/src/mainwindow.cpp
@@ -0,0 +1,141 @@
+#include "mainwindow.h"
+#include "ui_mainwindow.h"
+#include <QTimer>
+#include <QThread>
+#include <QPointer>
+#include <QMessageBox>
+#include <QElapsedTimer>
+#include "worker.h"
+#include "wincon.h"
+
+class CThreadWaiter
+{
+public:
+ CThreadWaiter(QObject*o)
+ {
+ obj=o;
+ thread=new QThread();
+ thread->start();
+ o->moveToThread(thread);
+ QObject::connect(o,SIGNAL(destroyed()),thread,SLOT(quit()));
+ }
+ ~CThreadWaiter()
+ {
+ QElapsedTimer timer;
+ timer.start();
+ static const qint64 maxWait=0x600,i1=0x100;
+ if(!obj.isNull())
+ {
+ obj->deleteLater();
+ while((!obj.isNull())&&(timer.elapsed()<maxWait))
+ if(thread->wait(10))
+ break;
+ }
+ thread->quit();
+ if(!thread->wait(qMax(maxWait-timer.elapsed(),i1)))
+ exit(1);
+ delete thread;
+ }
+private:
+ QPointer<QObject> obj;
+ QThread*thread;
+};
+
+MainWindow::MainWindow(QWidget *parent) :
+ QMainWindow(parent),
+ ui(new Ui::MainWindow)
+{
+ ui->setupUi(this);
+
+ ui->progressBar->setVisible(false);
+ Worker*worker=new Worker();
+ waiter[0]=new CThreadWaiter(worker);
+ connect(worker,SIGNAL(busy(bool)),ui->mainToolBar,SLOT(setDisabled(bool)));
+ connect(worker,SIGNAL(progress(int)),this,SLOT(progress(int)));
+ connect(this,SIGNAL(doWork(int)),worker,SLOT(doWork(int)));
+
+ CWinCon*winCon=new CWinCon();
+ waiter[1]=new CThreadWaiter(winCon);
+ connect(winCon,SIGNAL(msg(QString)),this,SLOT(showMessage(QString)));
+ connect(this,SIGNAL(readNext()),winCon,SLOT(readOutput()));
+ QTimer::singleShot(256,this,SIGNAL(readNext()));
+
+ srand(0);
+ printf("Knock, knock ");
+}
+
+MainWindow::~MainWindow()
+{
+ disconnect(SIGNAL(readNext()));
+ printf("bye!\n");
+ delete waiter[0];
+ delete waiter[1];
+ delete ui;
+}
+
+void MainWindow::progress(int p)
+{
+ bool visible=false;
+ if((p>0)&&(p<100))
+ visible=true;
+ if(ui->progressBar->isVisible()!=visible)
+ ui->progressBar->setVisible(visible);
+ if((visible)&&(ui->progressBar->value()!=p))
+ ui->progressBar->setValue(p);
+}
+
+void MainWindow::showMessage(const QString&msg)
+{
+ static int mm[2]={0x18,0x60};
+ static int knock=14;
+ if(knock<32)
+ {
+ if(--knock==0)
+ {
+ knock=32;
+ mm[0]/=6;
+ mm[1]/=6;
+ ui->plainTextEdit->clear();
+ }
+ }
+ ui->plainTextEdit->moveCursor(QTextCursor::End);
+ ui->plainTextEdit->insertPlainText(msg);
+ QTimer::singleShot(mm[0]+(rand()%(mm[1]-mm[0])),this,SIGNAL(readNext()));
+}
+
+void MainWindow::on_actionDump_uboot_triggered()
+{
+ emit doWork(Worker::dumpUboot);
+}
+
+void MainWindow::on_actionDump_kernel_img_triggered()
+{
+ emit doWork(Worker::dumpKernel);
+}
+
+void MainWindow::on_actionUnpack_kernel_img_triggered()
+{
+ emit doWork(Worker::unpackKernel);
+}
+
+void MainWindow::on_actionRebuild_kernel_img_triggered()
+{
+ emit doWork(Worker::packKernel);
+}
+
+void MainWindow::on_actionFlash_kernel_triggered()
+{
+ if(QMessageBox::warning(this,"","sure?",QMessageBox::Yes|QMessageBox::Abort,QMessageBox::Abort)!=QMessageBox::Yes)
+ return;
+ emit doWork(Worker::flashKernel);
+}
+
+void MainWindow::on_actionMemboot_triggered()
+{
+ emit doWork(Worker::memboot);
+}
+
+void MainWindow::on_actionShutdown_triggered()
+{
+ emit doWork(Worker::shutdown);
+}
diff --git a/hakchi-gui/src/mainwindow.h b/hakchi-gui/src/mainwindow.h
new file mode 100644
index 0000000..1ca2917
--- /dev/null
+++ b/hakchi-gui/src/mainwindow.h
@@ -0,0 +1,39 @@
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+
+namespace Ui {
+class MainWindow;
+}
+
+class CThreadWaiter;
+
+class MainWindow:public QMainWindow
+{
+ Q_OBJECT
+public:
+ explicit MainWindow(QWidget*parent=0);
+ ~MainWindow();
+
+signals:
+ void doWork(int work);
+ void readNext();
+
+private slots:
+ void progress(int p);
+ void showMessage(const QString&msg);
+ void on_actionDump_uboot_triggered();
+ void on_actionDump_kernel_img_triggered();
+ void on_actionUnpack_kernel_img_triggered();
+ void on_actionRebuild_kernel_img_triggered();
+ void on_actionFlash_kernel_triggered();
+ void on_actionMemboot_triggered();
+ void on_actionShutdown_triggered();
+
+private:
+ Ui::MainWindow*ui;
+ CThreadWaiter*waiter[2];
+};
+
+#endif // MAINWINDOW_H
diff --git a/hakchi-gui/src/mainwindow.ui b/hakchi-gui/src/mainwindow.ui
new file mode 100644
index 0000000..d7ade2c
--- /dev/null
+++ b/hakchi-gui/src/mainwindow.ui
@@ -0,0 +1,265 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>860</width>
+ <height>480</height>
+ </rect>
+ </property>
+ <widget class="QWidget" name="centralWidget">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPlainTextEdit" name="plainTextEdit">
+ <property name="palette">
+ <palette>
+ <active>
+ <colorrole role="Text">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>14</red>
+ <green>186</green>
+ <blue>14</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </active>
+ <inactive>
+ <colorrole role="Text">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>14</red>
+ <green>186</green>
+ <blue>14</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </inactive>
+ <disabled>
+ <colorrole role="Text">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>14</red>
+ <green>185</green>
+ <blue>14</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </disabled>
+ </palette>
+ </property>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QProgressBar" name="progressBar">
+ <property name="palette">
+ <palette>
+ <active>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Highlight">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>14</red>
+ <green>185</green>
+ <blue>14</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </active>
+ <inactive>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Highlight">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>14</red>
+ <green>185</green>
+ <blue>14</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </inactive>
+ <disabled>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Highlight">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>14</red>
+ <green>185</green>
+ <blue>14</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </disabled>
+ </palette>
+ </property>
+ <property name="value">
+ <number>50</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QToolBar" name="mainToolBar">
+ <property name="movable">
+ <bool>true</bool>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextOnly</enum>
+ </property>
+ <property name="floatable">
+ <bool>false</bool>
+ </property>
+ <attribute name="toolBarArea">
+ <enum>RightToolBarArea</enum>
+ </attribute>
+ <attribute name="toolBarBreak">
+ <bool>false</bool>
+ </attribute>
+ <addaction name="actionDump_uboot"/>
+ <addaction name="actionDump_kernel_img"/>
+ <addaction name="actionUnpack_kernel_img"/>
+ <addaction name="actionRebuild_kernel_img"/>
+ <addaction name="actionFlash_kernel"/>
+ <addaction name="actionMemboot"/>
+ <addaction name="actionShutdown"/>
+ </widget>
+ <widget class="QStatusBar" name="statusBar"/>
+ <action name="actionDump_uboot">
+ <property name="text">
+ <string>dump uboot</string>
+ </property>
+ </action>
+ <action name="actionDump_kernel_img">
+ <property name="text">
+ <string>dump kernel.img</string>
+ </property>
+ </action>
+ <action name="actionRebuild_kernel_img">
+ <property name="text">
+ <string>rebuild kernel.img</string>
+ </property>
+ </action>
+ <action name="actionMemboot">
+ <property name="text">
+ <string>memboot</string>
+ </property>
+ </action>
+ <action name="actionUnpack_kernel_img">
+ <property name="text">
+ <string>unpack kernel.img</string>
+ </property>
+ </action>
+ <action name="actionFlash_kernel">
+ <property name="text">
+ <string>flash kernel</string>
+ </property>
+ </action>
+ <action name="actionShutdown">
+ <property name="text">
+ <string>shutdown</string>
+ </property>
+ </action>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/hakchi-gui/src/md5int.c b/hakchi-gui/src/md5int.c
new file mode 100644
index 0000000..716862f
--- /dev/null
+++ b/hakchi-gui/src/md5int.c
@@ -0,0 +1,211 @@
+#include "md5int.h"
+#include <string.h>
+#include <stdio.h>
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+#define F(x,y,z) (((x)&(y))|((~x)&(z)))
+#define G(x,y,z) (((x)&(z))|((y)&(~z)))
+#define H(x,y,z) ((x)^(y)^(z))
+#define I(x,y,z) ((y)^((x)|(~z)))
+
+#define _lrotl(x,n) ((((unsigned long)(x)) << ((int) ((n) & 31))) | (((unsigned long)(x)) >> ((int) ((-(n)) & 31))))
+#define ROTATE_LEFT(x,n) _lrotl(x,n)
+
+#define FF(a,b,c,d,x,s,ac) {\
+ (a)+=F((b),(c),(d))+(x)+(uint32_t)(ac);\
+ (a)=ROTATE_LEFT((a),(s));\
+ (a)+=(b);}
+#define GG(a,b,c,d,x,s,ac) {\
+ (a)+=G((b),(c),(d))+(x)+(uint32_t)(ac);\
+ (a)=ROTATE_LEFT((a),(s));\
+ (a)+=(b);}
+#define HH(a,b,c,d,x,s,ac) {\
+ (a)+=H((b),(c),(d))+(x)+(uint32_t)(ac);\
+ (a)=ROTATE_LEFT((a),(s));\
+ (a)+=(b);}
+#define II(a,b,c,d,x,s,ac) {\
+ (a)+=I((b),(c),(d))+(x)+(uint32_t)(ac);\
+ (a)=ROTATE_LEFT((a),(s));\
+ (a)+=(b);}
+
+void md5init(md5context*context)
+{
+ context->count[0]=context->count[1]=0;
+ context->state[0]=0x67452301;
+ context->state[1]=0xefcdab89;
+ context->state[2]=0x98badcfe;
+ context->state[3]=0x10325476;
+}
+
+void md5final(md5context*context,void*_digest_)
+{
+ uint8_t*digest=(uint8_t*)_digest_;
+
+ uint8_t bits[8];
+ uint8_t PADDING[64];
+ uint32_t index, padLen;
+
+ /* Save number of bits */
+ memcpy (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64. */
+ index = (uint32_t)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ memset(PADDING,0,64);
+ PADDING[0]=0x80;
+ md5update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ md5update (context, bits, 8);
+
+ /* Store state in digest */
+ memcpy (digest, context->state, 16);
+
+ /* Zeroize sensitive information. */
+ memset ((uint8_t*)context, 0, sizeof (*context));
+}
+
+static void md5transform(uint32_t state[4],const uint8_t block[64])
+{
+ uint32_t a=state[0],b=state[1],c=state[2],d=state[3];
+ const uint32_t*x=(const uint32_t*)(&block[0]);
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+ state[0]+=a;
+ state[1]+=b;
+ state[2]+=c;
+ state[3]+=d;
+}
+
+void md5update(md5context*context,const void*_input_,uint32_t inputLen)
+{
+ const uint8_t*const input=(const uint8_t*)_input_;
+
+ uint32_t i, index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (uint32_t)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((uint32_t)inputLen << 3)) < ((uint32_t)inputLen << 3))
+ context->count[1]++;
+
+ context->count[1] += ((uint32_t)inputLen >> 29);
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.*/
+ if (inputLen >= partLen)
+ {
+ memcpy(&context->buffer[index], input, partLen);
+ md5transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ md5transform (context->state, &input[i]);
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ memcpy(&context->buffer[index], &input[i], inputLen-i);
+}
+
+void md5calc(const void*_input_,uint32_t inputLen,void*_digest_)
+{
+ md5context context;
+ md5init(&context);
+ md5update(&context,_input_,inputLen);
+ md5final(&context,_digest_);
+}
+
+char*md5print(const void*md5,char*str)
+{
+ const uint8_t*src=md5;
+ for(int i=0;i<16;i++)
+ {
+ str+=sprintf(str,"%.2x",*src++);
+ }
+ return str-32;
+}
diff --git a/hakchi-gui/src/md5int.h b/hakchi-gui/src/md5int.h
new file mode 100644
index 0000000..719abc5
--- /dev/null
+++ b/hakchi-gui/src/md5int.h
@@ -0,0 +1,27 @@
+#ifndef MD5INT_H
+#define MD5INT_H
+
+#include <stdint.h>
+
+typedef struct
+{
+ uint8_t buffer[64];
+ uint32_t state[4];
+ uint32_t count[2];
+} md5context;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void md5init(md5context*);
+void md5update(md5context*,const void*,uint32_t);
+void md5final(md5context*,void*);
+void md5calc(const void*,uint32_t,void*);
+char*md5print(const void*md5,char*str);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/hakchi-gui/src/wincon.cpp b/hakchi-gui/src/wincon.cpp
new file mode 100644
index 0000000..bce5a3a
--- /dev/null
+++ b/hakchi-gui/src/wincon.cpp
@@ -0,0 +1,59 @@
+#include "wincon.h"
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef WIN32
+#include <io.h>
+#endif
+
+CWinCon::CWinCon(QObject*parent):QObject(parent)
+{
+ con=0;
+ int filedes[2];
+#ifdef WIN32
+ if(_pipe(filedes,0x10000,O_BINARY|O_NOINHERIT)>=0)
+#else
+ if(pipe(filedes)>=0)
+#endif
+ {
+ fflush(stdout);
+ fflush(stderr);
+#ifdef WIN32
+ while((_dup2(filedes[1],STDOUT_FILENO)<0)&&(errno==EINTR)){}
+ while((_dup2(filedes[1],STDERR_FILENO)<0)&&(errno==EINTR)){}
+ _close(filedes[1]);
+ *stdout=*_fdopen(STDOUT_FILENO,"wb");
+ *stderr=*_fdopen(STDERR_FILENO,"wb");
+ con=_fdopen(filedes[0],"rb");
+#else
+ while((dup2(filedes[1],STDOUT_FILENO)<0)&&(errno==EINTR)){}
+ while((dup2(filedes[1],STDERR_FILENO)<0)&&(errno==EINTR)){}
+ ::close(filedes[1]);
+ con=fdopen(filedes[0],"rb");
+#endif
+ setvbuf(stdout,0,_IONBF,0);
+ setvbuf(stderr,0,_IONBF,0);
+ }
+}
+
+CWinCon::~CWinCon()
+{
+ if(con)
+ {
+ fclose(con);
+ con=0;
+ }
+}
+
+void CWinCon::readOutput()
+{
+ if(con)
+ {
+ //fucking windows
+ char buffer[1];
+ ssize_t size=fread(buffer,1,sizeof(buffer),con);
+ if(size>0)
+ emit msg(QString::fromLocal8Bit(buffer,size));
+ }
+}
diff --git a/hakchi-gui/src/wincon.h b/hakchi-gui/src/wincon.h
new file mode 100644
index 0000000..a51a857
--- /dev/null
+++ b/hakchi-gui/src/wincon.h
@@ -0,0 +1,20 @@
+#ifndef WINCON_H
+#define WINCON_H
+
+#include <QObject>
+
+class CWinCon:public QObject
+{
+ Q_OBJECT
+public:
+ explicit CWinCon(QObject*parent=0);
+ ~CWinCon();
+signals:
+ void msg(const QString&msg);
+public slots:
+ void readOutput();
+private:
+ FILE*con;
+};
+
+#endif // WINCON_H
diff --git a/hakchi-gui/src/worker.cpp b/hakchi-gui/src/worker.cpp
new file mode 100644
index 0000000..4b9d3bb
--- /dev/null
+++ b/hakchi-gui/src/worker.cpp
@@ -0,0 +1,408 @@
+#include "worker.h"
+#include "fel.h"
+#include <QDir>
+#include "bootimg.h"
+#include "md5int.h"
+
+#ifdef WIN32
+#include <windows.h>
+#define le32toh(x) (x)
+#endif
+
+static const QString kernelFile("dump/kernel.img");
+
+#ifdef WIN32
+int system_hidden(const char*cmd)
+{
+ int result=7;
+ STARTUPINFOA si;
+ PROCESS_INFORMATION pi;
+ memset(&si,0,sizeof(si));
+ memset(&pi,0,sizeof(pi));
+ si.cb=sizeof(STARTUPINFO);
+ si.dwFlags=STARTF_USESTDHANDLES;
+ si.hStdOutput=(HANDLE)_get_osfhandle(_fileno(stdout));
+ si.hStdError=(HANDLE)_get_osfhandle(_fileno(stderr));
+ QString cmdl("cmd /c ");
+ cmdl+=QString::fromLocal8Bit(cmd).replace('/','\\');
+ if(CreateProcessA(getenv("COMSPEC"),cmdl.toLocal8Bit().data(),0,0,TRUE,NORMAL_PRIORITY_CLASS|CREATE_NO_WINDOW,0,0,&si,&pi))
+ {
+ CloseHandle(pi.hThread);
+ WaitForSingleObject(pi.hProcess,INFINITE);
+ GetExitCodeProcess(pi.hProcess,(LPDWORD)&result);
+ CloseHandle(pi.hProcess);
+ }
+ return result;
+}
+#define system(x) system_hidden(x)
+#endif
+
+int saveFile(const char*fileName,void*X,size_t fs)
+{
+ int rv=0;
+ FILE*hf=fopen(fileName,"wb");
+ if(hf)
+ {
+ if(fwrite(X,1,fs,hf)==fs)
+ {
+ rv=1;
+ }
+ fclose(hf);
+ }
+ return rv;
+}
+
+size_t loadFile(const char*fileName,void*X)
+{
+ size_t fs=0;
+ FILE*hf=fopen(fileName,"rb");
+ if(hf)
+ {
+ fseek(hf,0,SEEK_END);
+ fs=ftell(hf);
+ if(X)
+ {
+ fseek(hf,0,SEEK_SET);
+ if(fread(X,1,fs,hf)!=fs)
+ {
+ fs=0;
+ }
+ }
+ fclose(hf);
+ }
+ return fs;
+}
+
+QByteArray loadFile(const char*fileName)
+{
+ size_t fs=loadFile(fileName,0);
+ if(fs)
+ {
+ QByteArray data(fs,Qt::Uninitialized);
+ if(loadFile(fileName,data.data())==fs)
+ return data;
+ }
+ return QByteArray();
+}
+
+Worker::Worker(QObject*parent):QObject(parent)
+{
+ fel=0;
+ progressFlow=0;
+ progressTotal=0;
+}
+
+Worker::~Worker()
+{
+ delete fel;
+}
+
+void flushOutput()
+{
+ fflush(stdout);
+ fflush(stderr);
+#ifdef WIN32
+ FlushFileBuffers((HANDLE)_get_osfhandle(STDOUT_FILENO));
+ FlushFileBuffers((HANDLE)_get_osfhandle(STDERR_FILENO));
+#endif
+}
+
+void Worker::doWork(int work)
+{
+ progressFlow=0;
+ progressTotal=0;
+ emit busy(true);
+ emit progress(0);
+ flushOutput();
+ switch(work)
+ {
+ case dumpUboot:
+ do_dumpUboot();
+ break;
+ case dumpKernel:
+ do_dumpKernel();
+ break;
+ case unpackKernel:
+ do_unpackKernel();
+ break;
+ case packKernel:
+ do_packKernel();
+ break;
+ case flashKernel:
+ do_flashKernel();
+ break;
+ case memboot:
+ do_memboot();
+ break;
+ case shutdown:
+ do_shutdown();
+ break;
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+ printf("\n");
+ flushOutput();
+ emit progress(100);
+ emit busy(false);
+}
+
+void Worker::calcProgress(int flow)
+{
+ if(flow<0)
+ {
+ progressTotal-=flow;
+ return;
+ }
+ progressFlow+=flow;
+ if((progressFlow>0)&&(progressTotal>0))
+ {
+ int p=qMin(100*progressFlow/progressTotal,100);
+ emit progress(p);
+ }
+}
+
+bool Worker::init()
+{
+ if(fel)
+ return fel->init();
+ fel=new Fel(this);
+ connect(fel,SIGNAL(dataFlow(int)),this,SLOT(calcProgress(int)));
+ QByteArray data=loadFile("data/fes1.bin");
+ if(data.size())
+ fel->setFes1bin(data);
+ else
+ printf("fes1.bin not found\n");
+ data=loadFile("data/uboot.bin");
+ if(data.size())
+ fel->setUboot(data);
+ else
+ printf("uboot.bin not found\n");
+ return fel->init();
+}
+
+void Worker::do_dumpUboot()
+{
+ if((!init())||(!fel->haveUboot()))
+ {
+ return;
+ }
+ size_t size=0;
+ QByteArray buf(sector_size*6,Qt::Uninitialized);
+ calcProgress(-buf.size());
+ if(fel->readFlash(uboot_base_f,buf.size(),buf.data())==(size_t)buf.size())
+ size=le32toh(*reinterpret_cast<uint32_t*>(buf.data()+0x14u));
+ else
+ return;
+ if((size==0)||(size>kernel_max_size))
+ {
+ printf("uboot: invalid size in header\n");
+ return;
+ }
+ if(size>(size_t)buf.size())
+ {
+ size_t oldSize=buf.size();
+ buf.resize(size);
+ calcProgress(-(size-oldSize));
+ if(fel->readFlash(uboot_base_f+oldSize,size-oldSize,buf.data()+oldSize)!=(size-oldSize))
+ {
+ printf("uboot: read error\n");
+ return;
+ }
+ }
+ QDir(".").mkdir("dump");
+ saveFile("dump/uboot.bin",buf.data(),size);
+ uint8_t md5[16];
+ md5calc(buf.data(),size,md5);
+ char md5str[40];
+ printf("%s\n",md5print(md5,md5str));
+ printf("%s - OK\n",Q_FUNC_INFO);
+}
+
+static size_t kernelSize(const QByteArray&data)
+{
+ size_t size=0;
+ const boot_img_hdr*h=reinterpret_cast<const boot_img_hdr*>(data.constData());
+ if(memcmp(h->magic,BOOT_MAGIC,BOOT_MAGIC_SIZE)==0)
+ {
+ size_t pages=1;
+ pages+=(h->kernel_size+h->page_size-1)/h->page_size;
+ pages+=(h->ramdisk_size+h->page_size-1)/h->page_size;
+ pages+=(h->second_size+h->page_size-1)/h->page_size;
+ pages+=(h->dt_size+h->page_size-1)/h->page_size;
+ size_t ks=pages*h->page_size;
+ if(ks<=kernel_max_size)
+ size=ks;
+ }
+ return size;
+}
+
+void Worker::do_dumpKernel()
+{
+ if((!init())||(!fel->haveUboot()))
+ {
+ return;
+ }
+ size_t size=0;
+ QByteArray buf(sector_size*0x20,Qt::Uninitialized);
+ calcProgress(-buf.size());
+ if(fel->readFlash(kernel_base_f,buf.size(),buf.data())==(size_t)buf.size())
+ size=kernelSize(buf);
+ else
+ return;
+ if((size==0)||(size>kernel_max_size))
+ {
+ printf("kernel: invalid size in header\n");
+ return;
+ }
+ if(size>(size_t)buf.size())
+ {
+ size_t oldSize=buf.size();
+ buf.resize(size);
+ calcProgress(-(size-oldSize));
+ if(fel->readFlash(kernel_base_f+oldSize,size-oldSize,buf.data()+oldSize)!=(size-oldSize))
+ {
+ printf("kernel: read error\n");
+ return;
+ }
+ }
+ QDir(".").mkdir("dump");
+ saveFile(kernelFile.toLocal8Bit(),buf.data(),size);
+ uint8_t md5[16];
+ md5calc(buf.data(),size,md5);
+ char md5str[40];
+ printf("%s\n",md5print(md5,md5str));
+ printf("%s - OK\n",Q_FUNC_INFO);
+}
+
+void Worker::do_unpackKernel()
+{
+ if(::system(QString("extractimg \"%1\"").arg(kernelFile).toLocal8Bit())==0)
+ printf("%s - OK\n",Q_FUNC_INFO);
+}
+
+void Worker::do_packKernel()
+{
+ if(::system(QString("makeimg kernel").toLocal8Bit())==0)
+ printf("%s - OK\n",Q_FUNC_INFO);
+}
+
+void Worker::do_flashKernel()
+{
+ if((!init())||(!fel->haveUboot()))
+ {
+ return;
+ }
+ if(::system(QString("makeimg kernel notx").toLocal8Bit())!=0)
+ {
+ printf("cannot build kernel.img\n");
+ return;
+ }
+ QByteArray k=loadFile("kernel.img");
+ if(k.size()==0)
+ {
+ printf("kernel.img not found\n");
+ return;
+ }
+ size_t ksize=kernelSize(k);
+ if((ksize>(size_t)k.size())||((size_t)k.size()>kernel_max_flash_size))
+ {
+ printf("kernel: invalid size in header\n");
+ return;
+ }
+ ksize=(ksize+sector_size-1)/sector_size;
+ ksize=ksize*sector_size;
+ if((size_t)k.size()!=ksize)
+ {
+ const size_t oldSize=k.size();
+ k.resize(ksize);
+ memset(k.data()+oldSize,0,k.size()-oldSize);
+ }
+ calcProgress(-k.size()*2);
+ if(fel->writeFlash(kernel_base_f,k.size(),k.data())!=(size_t)k.size())
+ {
+ printf("kernel: write error\n");
+ return;
+ }
+ printf("kernel: write ok\n");
+ QByteArray baver(k.size(),Qt::Uninitialized);
+ if(fel->readFlash(kernel_base_f,k.size(),baver.data())!=(size_t)k.size())
+ {
+ printf("kernel: read error\n");
+ return;
+ }
+ if(memcmp(k.data(),baver.data(),k.size())==0)
+ printf("kernel: verify ok\n");
+ else
+ printf("kernel: verify fuck\n");
+#if 0
+ if(fel->writeFlash(sector_size*(0x30+0x20-2),sector_size,k.data())==sector_size)
+ {
+ QByteArray baver(sector_size,Qt::Uninitialized);
+ if(fel->readFlash(sector_size*(0x30+0x20-2),sector_size,baver.data())==sector_size)
+ {
+ if(memcmp(k.data(),baver.data(),sector_size)==0)
+ f_printf("kernel: ok\n");
+ else
+ f_printf("kernel: fuck\n");
+ }
+ return;
+ }
+#endif
+ char cmd[1024];
+ sprintf(cmd,"boota %x",kernel_base_m);
+ if(!fel->runUbootCmd(cmd,true))
+ {
+ printf("kernel: runcmd error\n");
+ return;
+ }
+ printf("%s - OK\n",Q_FUNC_INFO);
+}
+
+void Worker::do_memboot()
+{
+ if((!init())||(!fel->haveUboot()))
+ {
+ return;
+ }
+ QByteArray k=loadFile("kernel.img");
+ if(k.size()==0)
+ {
+ printf("kernel.img not found\n");
+ return;
+ }
+ const size_t ksize=kernelSize(k);
+ if((ksize>(size_t)k.size())||((size_t)k.size()>kernel_max_size))
+ {
+ printf("kernel: invalid size in header\n");
+ return;
+ }
+ calcProgress(-k.size());
+ if(fel->writeMemory(kernel_base_m,k.size(),k.data())!=(size_t)k.size())
+ {
+ printf("kernel: write error\n");
+ return;
+ }
+ char cmd[1024];
+ sprintf(cmd,"boota %x",kernel_base_m);
+ if(!fel->runUbootCmd(cmd,true))
+ {
+ printf("kernel: runcmd error\n");
+ return;
+ }
+ printf("%s - OK\n",Q_FUNC_INFO);
+}
+
+void Worker::do_shutdown()
+{
+ if((!init())||(!fel->haveUboot()))
+ {
+ return;
+ }
+ if(!fel->runUbootCmd("shutdown",true))
+ {
+ printf("shutdown: runcmd error\n");
+ return;
+ }
+ printf("%s - OK\n",Q_FUNC_INFO);
+}
diff --git a/hakchi-gui/src/worker.h b/hakchi-gui/src/worker.h
new file mode 100644
index 0000000..121177f
--- /dev/null
+++ b/hakchi-gui/src/worker.h
@@ -0,0 +1,51 @@
+#ifndef WORKER_H
+#define WORKER_H
+
+#include <QObject>
+#include <QString>
+#include "fel.h"
+
+class Worker:public QObject
+{
+ Q_OBJECT
+public:
+ enum Work
+ {
+ dumpUboot,
+ dumpKernel,
+ unpackKernel,
+ packKernel,
+ flashKernel,
+ memboot,
+ shutdown
+ };
+ explicit Worker(QObject*parent=0);
+ ~Worker();
+
+signals:
+ void busy(bool b);
+ void progress(int p);
+
+public slots:
+ void doWork(int work);
+
+private slots:
+ void calcProgress(int flow);
+
+private:
+ bool init();
+ void do_dumpUboot();
+ void do_dumpKernel();
+ void do_unpackKernel();
+ void do_packKernel();
+ void do_flashKernel();
+ void do_memboot();
+ void do_shutdown();
+
+private:
+ Fel*fel;
+ int progressFlow;
+ int progressTotal;
+};
+
+#endif // WORKER_H
diff --git a/importpath b/importpath
new file mode 100644
index 0000000..36ebba7
--- /dev/null
+++ b/importpath
@@ -0,0 +1,4 @@
+if [ -z "$(which felboot)" ]; then
+ export PATH=$(pwd)/bin:$(pwd)/build:$PATH
+ echo PATH=$PATH
+fi
diff --git a/mod/bin/chroot b/mod/bin/chroot
new file mode 120000
index 0000000..c3fa810
--- /dev/null
+++ b/mod/bin/chroot
@@ -0,0 +1 @@
+busybox \ No newline at end of file
diff --git a/mod/bin/cp b/mod/bin/cp
new file mode 120000
index 0000000..c3fa810
--- /dev/null
+++ b/mod/bin/cp
@@ -0,0 +1 @@
+busybox \ No newline at end of file
diff --git a/mod/bin/dd b/mod/bin/dd
new file mode 120000
index 0000000..c3fa810
--- /dev/null
+++ b/mod/bin/dd
@@ -0,0 +1 @@
+busybox \ No newline at end of file
diff --git a/mod/bin/gzip b/mod/bin/gzip
new file mode 120000
index 0000000..c3fa810
--- /dev/null
+++ b/mod/bin/gzip
@@ -0,0 +1 @@
+busybox \ No newline at end of file
diff --git a/mod/bin/ls b/mod/bin/ls
new file mode 120000
index 0000000..c3fa810
--- /dev/null
+++ b/mod/bin/ls
@@ -0,0 +1 @@
+busybox \ No newline at end of file
diff --git a/mod/bin/mkdir b/mod/bin/mkdir
new file mode 120000
index 0000000..c3fa810
--- /dev/null
+++ b/mod/bin/mkdir
@@ -0,0 +1 @@
+busybox \ No newline at end of file
diff --git a/mod/bin/mv b/mod/bin/mv
new file mode 120000
index 0000000..c3fa810
--- /dev/null
+++ b/mod/bin/mv
@@ -0,0 +1 @@
+busybox \ No newline at end of file
diff --git a/mod/bin/poweroff b/mod/bin/poweroff
new file mode 120000
index 0000000..c3fa810
--- /dev/null
+++ b/mod/bin/poweroff
@@ -0,0 +1 @@
+busybox \ No newline at end of file
diff --git a/mod/bin/rm b/mod/bin/rm
new file mode 120000
index 0000000..c3fa810
--- /dev/null
+++ b/mod/bin/rm
@@ -0,0 +1 @@
+busybox \ No newline at end of file
diff --git a/mod/hakchi/backup b/mod/hakchi/backup
new file mode 100644
index 0000000..4325fe4
--- /dev/null
+++ b/mod/hakchi/backup
@@ -0,0 +1,39 @@
+backup_nandc(){
+ if [ "$cf_backup_nandc" == "y" ]; then
+ echo backup nandc
+ dd if=/dev/nandc bs=128K | gzip > /nandc.gz
+ fi
+ return 0
+}
+
+backup(){
+ backupdir=$installdir/backup
+ if [ -f /nandc.gz ]; then
+ if [ ! -f $backupdir/nandc.gz ]; then
+ echo move nandc
+ mkdir -p $backupdir
+ mv /nandc.gz $backupdir/
+ fi
+ fi
+ if [ "$cf_backup" != "y" ]; then
+ return 0
+ fi
+ mkdir -p $backupdir
+ if [ ! -f $backupdir/nanda.gz ]; then
+ echo backup nanda
+ dd if=/dev/nanda bs=128K | gzip > $backupdir/nanda.gz
+ fi
+ if [ ! -f $backupdir/nandb ]; then
+ echo backup nandb
+ dd if=/dev/nandb bs=128K > $backupdir/nandb
+ fi
+ if [ ! -f $backupdir/nandd.gz ]; then
+ echo backup nandd
+ dd if=/dev/nandd bs=128K | gzip > $backupdir/nandd.gz
+ fi
+ if [ ! -f $backupdir/nande.gz ]; then
+ echo backup nande
+ dd if=/dev/nande bs=128K | gzip > $backupdir/nande.gz
+ fi
+ return 0
+}
diff --git a/mod/hakchi/config b/mod/hakchi/config
new file mode 100644
index 0000000..13dbd9c
--- /dev/null
+++ b/mod/hakchi/config
@@ -0,0 +1,3 @@
+cf_shutdown=y
+cf_backup=n
+cf_backup_nandc=n
diff --git a/mod/hakchi/init b/mod/hakchi/init
new file mode 100644
index 0000000..41f2dfe
--- /dev/null
+++ b/mod/hakchi/init
@@ -0,0 +1,80 @@
+init(){
+echo
+
+modname=hakchi
+mountpoint=/newroot
+installdir=$mountpoint/var/lib/$modname
+rootfs=$installdir/rootfs
+
+. /$modname/config
+. /$modname/backup
+
+backup_nandc
+
+mount -t tmpfs -o mode=0755,nosuid,nodev tmpfs $mountpoint/var
+mkdir $mountpoint/var/lib
+mount -o defaults,nosuid,nodev,noatime /dev/nandc $mountpoint/var/lib
+
+if [ ! -f $rootfs/etc/preinit ]; then
+ backup
+
+ echo installing $modname...
+
+ rm -rf $rootfs
+ mkdir -p $rootfs/usr/share/games/nes
+
+ cp -a $mountpoint/bin $rootfs/
+ cp -a $mountpoint/etc $rootfs/
+ cp -a $mountpoint/usr/share/games/nes/kachikachi $rootfs/usr/share/games/nes/
+
+ cp -a /$modname/rootfs/* $rootfs/
+ cp -a /bin/busybox $rootfs/bin/
+ cp -a /sbin/cryptsetup $rootfs/bin/
+
+ chroot $rootfs /bin/busybox --install -s /bin/
+
+ if [ "$cf_shutdown" == "y" ]; then
+ cf_shutdown=yy
+ fi
+else
+ echo $modname already installed
+fi
+
+if [ -d $modname/transfer ]; then
+ echo transferring data...
+ if [ -f $modname/transfer/transfer ]; then
+ . $modname/transfer/transfer
+ rm $modname/transfer/transfer
+ else
+ docopy=y
+ fi
+ if [ "$docopy" == "y" ]; then
+ cp -a $modname/transfer/* $installdir/
+ fi
+ if [ "$cf_shutdown" == "y" ]; then
+ cf_shutdown=yy
+ fi
+fi
+
+if [ "$cf_shutdown" == "yy" ]; then
+ echo shutting down...
+ umount $mountpoint/var/lib
+ umount $mountpoint/var
+ poweroff -f
+ return 0
+fi
+
+if [ ! -f $mountpoint/var/lib/clover/profiles/0/CLV-P-NAAAE/1.state ]; then
+ echo loading stock shell
+ umount $mountpoint/var/lib
+ umount $mountpoint/var
+ return 0
+fi
+
+echo loading $modname
+. $rootfs/etc/preinit
+preinit
+return $?
+}
+
+init
diff --git a/mod/hakchi/rootfs/etc/inittab b/mod/hakchi/rootfs/etc/inittab
new file mode 100644
index 0000000..8bba354
--- /dev/null
+++ b/mod/hakchi/rootfs/etc/inittab
@@ -0,0 +1,16 @@
+null::sysinit:/bin/mount -t proc proc /proc
+null::sysinit:/bin/mkdir -p /dev/pts /dev/shm
+null::sysinit:/bin/mount -a
+null::sysinit:/bin/mkdir -p /var/cache /var/lock /var/log /var/spool
+null::sysinit:/bin/ln -s /tmp /var/tmp
+null::sysinit:/bin/ln -s /run /var/run
+
+null::sysinit:/bin/mkdir -p /var/cache/clover/reed-libs/tmp /var/lib/clover/profiles/0/home-menu /var/lib/clover/config/reed-libs
+
+null::sysinit:/etc/init.d/rcS
+
+null::respawn:/sbin/getty 115200 ttyS0
+
+null::ctrlaltdel:/sbin/reboot
+null::shutdown:/etc/init.d/rcK
+null::shutdown:/bin/umount -a -r
diff --git a/mod/hakchi/rootfs/etc/preinit b/mod/hakchi/rootfs/etc/preinit
new file mode 100644
index 0000000..f908ebc
--- /dev/null
+++ b/mod/hakchi/rootfs/etc/preinit
@@ -0,0 +1,8 @@
+preinit(){
+
+mount -o bind $rootfs/bin $mountpoint/bin
+mount -o bind $rootfs/etc $mountpoint/etc
+mount -o bind $rootfs/usr/share/games/nes/kachikachi $mountpoint/usr/share/games/nes/kachikachi
+
+return 0
+}
diff --git a/mod/hakchi/rootfs/etc/profile b/mod/hakchi/rootfs/etc/profile
new file mode 100644
index 0000000..b719793
--- /dev/null
+++ b/mod/hakchi/rootfs/etc/profile
@@ -0,0 +1,35 @@
+# /etc/profile: system-wide .profile file for the Bourne shell (sh(1))
+# and Bourne compatible shells (bash(1), ksh(1), ash(1), ...).
+
+PATH="/usr/local/bin:/usr/bin:/bin"
+EDITOR="vi" # needed for packages like cron, git-commit
+test -z "$TERM" && TERM="vt100" # Basic terminal capab. For screen etc.
+
+if [ "$HOME" = "/root" ]; then
+ PATH=$PATH:/usr/local/sbin:/usr/sbin:/sbin
+fi
+if [ "$PS1" ]; then
+# works for bash and ash (no other shells known to be in use here)
+ PS1='\u@\h:\w\$ '
+fi
+
+if [ -d /etc/profile.d ]; then
+ for i in /etc/profile.d/*.sh ; do
+ if [ -f $i -a -r $i ]; then
+ . $i
+ fi
+ done
+ unset i
+fi
+
+if [ -x /usr/bin/resize ] && termpath="`tty`"; then
+ # Make sure we are on a serial console (i.e. the device used starts with /dev/tty),
+ # otherwise we confuse e.g. the eclipse launcher which tries do use ssh
+ case "$termpath" in
+ /dev/tty*) resize >/dev/null
+ esac
+fi
+
+export PATH PS1 OPIEDIR QPEDIR QTDIR EDITOR TERM
+
+umask 022
diff --git a/mod/sbin/init b/mod/sbin/init
new file mode 100755
index 0000000..52cc5fa
--- /dev/null
+++ b/mod/sbin/init
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+/bin/mount -t proc proc /proc
+/bin/mount -t sysfs sys /sys
+
+for i in $(cat /proc/cmdline); do
+ if [ "$i" = "ro" ] ; then
+ READONLY="y"
+ elif [ "${i#root=}" != "$i" ] ; then
+ ROOTFS="${i#root=}"
+ elif [ "$i" = "decrypt" ] ; then
+ DECRYPT="y"
+ fi
+done
+
+MOUNT_OPTS="noatime"
+if [ "${DECRYPT}" = "y" ]; then
+ if [ "${READONLY}" == "y" ]; then
+ READONLY="--readonly"
+ else
+ READONLY=""
+ fi
+
+ /sbin/cryptsetup open ${ROOTFS} root-crypt ${READONLY} --type plain --cipher aes-xts-plain --key-file /key-file
+ /bin/mount -o "${MOUNT_OPTS}" /dev/mapper/root-crypt /newroot
+else
+ if [ "${READONLY}" == "y" ]; then
+ MOUNT_OPTS="ro,${MOUNT_OPTS}"
+ fi
+
+ /bin/mount -o "${MOUNT_OPTS}" ${ROOTFS} /newroot
+fi
+
+. /hakchi/init
+
+/bin/mount --move /dev /newroot/dev
+/bin/umount /proc
+/bin/umount /sys
+exec /sbin/switch_root /newroot /sbin/init
diff --git a/r16-uboot/r16-uboot.diff b/r16-uboot/r16-uboot.diff
new file mode 100644
index 0000000..2c7d6de
--- /dev/null
+++ b/r16-uboot/r16-uboot.diff
@@ -0,0 +1,243 @@
+diff --git a/Makefile b/Makefile
+index 1c696db..f911894 100644
+--- a/Makefile
++++ b/Makefile
+@@ -441,7 +441,7 @@ $(obj)u-boot.ubl: $(obj)u-boot-nand.bin
+ -e $(CONFIG_SYS_TEXT_BASE) -d $< $@
+
+ $(obj)u-boot-$(TARGET).bin: $(obj)u-boot.bin
+- @git show HEAD --pretty=format:"%H" | head -n 1 > cur.log
++ @$(TOPDIR)/fake_git show HEAD --pretty=format:"%H" | head -n 1 > cur.log
+ @./add_hash.sh -f u-boot.bin -m uboot
+
+ GEN_UBOOT = \
+@@ -466,30 +466,30 @@ spl_lib: $(TIMESTAMP_FILE) $(VERSION_FILE) depend
+
+ fes: spl_lib depend
+ $(MAKE) -C sunxi_spl/fes_init all
+- @git show HEAD --pretty=format:"%H" | head -n 1 > cur.log
++ @$(TOPDIR)/fake_git show HEAD --pretty=format:"%H" | head -n 1 > cur.log
+ @./add_hash.sh -f sunxi_spl/fes_init/fes1.bin -m boot0
+ @$(TOPDIR)/tools/gen_check_sum sunxi_spl/fes_init/fes1.bin fes1.bin > /dev/null
+
+ boot0: spl_lib depend
+ $(MAKE) -C sunxi_spl/boot0 all
+ ifdef CONFIG_STORAGE_MEDIA_NAND
+- @git show HEAD --pretty=format:"%H" | head -n 1 > cur.log
++ @$(TOPDIR)/fake_git show HEAD --pretty=format:"%H" | head -n 1 > cur.log
+ @./add_hash.sh -f sunxi_spl/boot0/boot0_nand.bin -m boot0
+ @$(TOPDIR)/tools/gen_check_sum sunxi_spl/boot0/boot0_nand.bin boot0_nand.bin > /dev/null
+ endif
+ ifdef CONFIG_STORAGE_MEDIA_MMC
+- @git show HEAD --pretty=format:"%H" | head -n 1 > cur.log
++ @$(TOPDIR)/fake_git show HEAD --pretty=format:"%H" | head -n 1 > cur.log
+ @./add_hash.sh -f sunxi_spl/boot0/boot0_sdcard.bin -m boot0
+ @$(TOPDIR)/tools/gen_check_sum sunxi_spl/boot0/boot0_sdcard.bin boot0_sdcard.bin > /dev/null
+ endif
+ ifdef CONFIG_STORAGE_MEDIA_SPINOR
+- @git show HEAD --pretty=format:"%H" | head -n 1 > cur.log
++ @$(TOPDIR)/fake_git show HEAD --pretty=format:"%H" | head -n 1 > cur.log
+ @./add_hash.sh -f sunxi_spl/boot0/boot0_spinor.bin -m boot0
+ @$(TOPDIR)/tools/gen_check_sum sunxi_spl/boot0/boot0_spinor.bin boot0_spinor.bin > /dev/null
+ endif
+ sboot: spl_lib depend
+ $(MAKE) -C sunxi_spl/sbrom all
+- @git show HEAD --pretty=format:"%H" | head -n 1 > cur.log
++ @$(TOPDIR)/fake_git show HEAD --pretty=format:"%H" | head -n 1 > cur.log
+ @./add_hash.sh -f sunxi_spl/sbrom/sboot.bin -m sboot
+ @$(TOPDIR)/tools/gen_check_sum sunxi_spl/sbrom/sboot.bin sboot.bin > /dev/null
+
+@@ -671,7 +671,7 @@ tools-all: easylogo env gdb $(VERSION_FILE)
+
+ .PHONY : CHANGELOG
+ CHANGELOG:
+- git log --no-merges U-Boot-1_1_5.. | \
++ $(TOPDIR)/fake_git log --no-merges U-Boot-1_1_5.. | \
+ unexpand -a | sed -e 's/\s\s*$$//' > $@
+
+ include/license.h: tools/bin2header COPYING
+diff --git a/board/sunxi/load_check.c b/board/sunxi/load_check.c
+old mode 100755
+new mode 100644
+diff --git a/build.sh b/build.sh
+index 98ebdbb..3c3a86e 100755
+--- a/build.sh
++++ b/build.sh
+@@ -16,10 +16,10 @@ show_help()
+
+ build_uboot()
+ {
+- make ARCH=arm CROSS_COMPILE=arm-clover-linux-gnueabihf- distclean
+- make ARCH=arm CROSS_COMPILE=arm-clover-linux-gnueabihf- ${PLATFORM}_config
+- make ARCH=arm CROSS_COMPILE=arm-clover-linux-gnueabihf- CONFIG_SPL=y spl fes -j16
+- make ARCH=arm CROSS_COMPILE=arm-clover-linux-gnueabihf- -B -j16
++ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
++ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- ${PLATFORM}_config
++ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- CONFIG_SPL=y spl fes -j1
++ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -B -j1
+ }
+
+ while getopts p:m: OPTION
+diff --git a/common/cmd_sunxi_flash.c b/common/cmd_sunxi_flash.c
+index 77e5580..863f492 100644
+--- a/common/cmd_sunxi_flash.c
++++ b/common/cmd_sunxi_flash.c
+@@ -176,6 +176,27 @@ int do_sunxi_flash(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+
+ return ret == 0 ? 1 : 0;
+ }
++ else if(strncmp(cmd, "phy_write", strlen("phy_write")) == 0)
++ {
++ skip_init = 1;
++ sunxi_flash_handle_init();
++
++ u32 start_block;
++ u32 rblock;
++
++ printf("write physical\n");
++
++ addr = (ulong)simple_strtoul(argv[2], NULL, 16);
++ start_block = (ulong)simple_strtoul(argv[3], NULL, 16);
++ rblock = (ulong)simple_strtoul(argv[4], NULL, 16);
++
++ ret = sunxi_flash_phywrite(start_block, rblock, (void *)addr);
++
++ tick_printf("sunxi flash phy_write :offset %x, %d sectors %s\n", start_block, rblock,
++ ret ? "OK" : "ERROR");
++
++ return ret == 0 ? 1 : 0;
++ }
+
+ usage:
+ return cmd_usage(cmdtp);
+diff --git a/config.mk b/config.mk
+index 42849d5..e560a94 100644
+--- a/config.mk
++++ b/config.mk
+@@ -115,8 +115,8 @@ cc-option = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \
+ #
+ AS = $(CROSS_COMPILE)as
+ LD = $(CROSS_COMPILE)ld
+-CC = $(CROSS_COMPILE)gcc
+-CPP = $(CC) -E
++CC = $(CROSS_COMPILE)gcc -std=gnu89
++CPP = $(CROSS_COMPILE)gcc -E
+ AR = $(CROSS_COMPILE)ar
+ NM = $(CROSS_COMPILE)nm
+ LDR = $(CROSS_COMPILE)ldr
+diff --git a/fake_git b/fake_git
+new file mode 100755
+index 0000000..beb8867
+--- /dev/null
++++ b/fake_git
+@@ -0,0 +1,2 @@
++#!/bin/bash
++echo fc3061df4dbd4153819b2d2f141d82b88fea51cf
+diff --git a/include/configs/clover.h b/include/configs/clover.h
+index a79af7e..467c34f 100644
+--- a/include/configs/clover.h
++++ b/include/configs/clover.h
+@@ -29,6 +29,8 @@
+ #define __KERNEL__
+ #endif
+
++#define CONFIG_FINAL
++
+ #define LINUX_MACHINE_ID 4137
+
+ #define UBOOT_VERSION "1.1.0"
+diff --git a/include/linux/compiler-gcc5.h b/include/linux/compiler-gcc5.h
+new file mode 100644
+index 0000000..94dea3f
+--- /dev/null
++++ b/include/linux/compiler-gcc5.h
+@@ -0,0 +1,61 @@
++#ifndef __LINUX_COMPILER_H
++#error "Please don't include <linux/compiler-gcc4.h> directly, include <linux/compiler.h> instead."
++#endif
++
++/* GCC 4.1.[01] miscompiles __weak */
++#ifdef __KERNEL__
++# if __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ <= 1
++# error Your version of gcc miscompiles the __weak directive
++# endif
++#endif
++
++#define __used __attribute__((__used__))
++#define __must_check __attribute__((warn_unused_result))
++#define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
++#define __always_inline inline __attribute__((always_inline))
++
++/*
++ * A trick to suppress uninitialized variable warning without generating any
++ * code
++ */
++#define uninitialized_var(x) x = x
++
++#if __GNUC_MINOR__ >= 3
++/* Mark functions as cold. gcc will assume any path leading to a call
++ to them will be unlikely. This means a lot of manual unlikely()s
++ are unnecessary now for any paths leading to the usual suspects
++ like BUG(), printk(), panic() etc. [but let's keep them for now for
++ older compilers]
++
++ Early snapshots of gcc 4.3 don't support this and we can't detect this
++ in the preprocessor, but we can live with this because they're unreleased.
++ Maketime probing would be overkill here.
++
++ gcc also has a __attribute__((__hot__)) to move hot functions into
++ a special section, but I don't see any sense in this right now in
++ the kernel context */
++#define __cold __attribute__((__cold__))
++
++
++#if __GNUC_MINOR__ >= 5
++/*
++ * Mark a position in code as unreachable. This can be used to
++ * suppress control flow warnings after asm blocks that transfer
++ * control elsewhere.
++ *
++ * Early snapshots of gcc 4.5 don't support this and we can't detect
++ * this in the preprocessor, but we can live with this because they're
++ * unreleased. Really, we need to have autoconf for the kernel.
++ */
++#define unreachable() __builtin_unreachable()
++#endif
++
++#endif
++
++#if __GNUC_MINOR__ > 0
++#define __compiletime_object_size(obj) __builtin_object_size(obj, 0)
++#endif
++#if __GNUC_MINOR__ >= 4
++#define __compiletime_warning(message) __attribute__((warning(message)))
++#define __compiletime_error(message) __attribute__((error(message)))
++#endif
+diff --git a/sunxi_spl/boot0/main/boot0_main.c b/sunxi_spl/boot0/main/boot0_main.c
+old mode 100755
+new mode 100644
+diff --git a/sunxi_spl/fes_init/main/fes_head.c b/sunxi_spl/fes_init/main/fes_head.c
+index 3cee7f6..0f647d3 100644
+--- a/sunxi_spl/fes_init/main/fes_head.c
++++ b/sunxi_spl/fes_init/main/fes_head.c
+@@ -50,6 +50,17 @@ const boot0_file_head_t fes1_head = {
+ 0, 0, '3','.','0','.','0',0
+ },
+ },
++ {
++ sizeof(boot0_private_head_t),
++ 0,
++ {
++ 600,3,0x3bbb,1,
++ 283246848,0,
++ 7280,64,24,0,
++ 0x47a14f,0x1c2294c,0x69049,0x0,0x0,0x0,0x0,
++ 0x0,0x0,0x0,0x0,0x0,0xa8,0x10901
++ }
++ }
+ };
+
+
+diff --git a/tools/gen_check_sum b/tools/gen_check_sum
+index 6af1447..5040838 100755
+Binary files a/tools/gen_check_sum and b/tools/gen_check_sum differ
diff --git a/r16-uboot/readme.md b/r16-uboot/readme.md
new file mode 100644
index 0000000..65d5315
--- /dev/null
+++ b/r16-uboot/readme.md
@@ -0,0 +1,5 @@
+1. get r16-uboot-fc3061df4dbd4153819b2d2f141d82b88fea51cf.tar.gz from http://data.nintendo.co.jp/oss/NintendoEntertainmentSystemNESClassicEdition_OSS.zip
+2. apply patch
+3. ./build.sh
+4. use sntool check -f to set checksum in fes1.bin
+5. use sntool split/join to cut script.bin from stock uboot and paste into freshly compiled one
diff --git a/sntool/sntool.cpp b/sntool/sntool.cpp
new file mode 100644
index 0000000..27d3703
--- /dev/null
+++ b/sntool/sntool.cpp
@@ -0,0 +1,245 @@
+// #########################################################################
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+
+// #########################################################################
+
+int saveFile(const char*fileName,uint8_t*X,size_t fs)
+{
+ int rv=0;
+ FILE*hf=fopen(fileName,"wb");
+ if(hf)
+ {
+ if(fwrite(X,1,fs,hf)==fs)
+ {
+ rv=1;
+ }
+ fclose(hf);
+ }
+ return rv;
+}
+
+// #########################################################################
+
+size_t loadFile(const char*fileName,uint8_t*X)
+{
+ size_t fs=0;
+ FILE*hf=fopen(fileName,"rb");
+ if(hf)
+ {
+ fseek(hf,0,SEEK_END);
+ fs=ftell(hf);
+ if(X)
+ {
+ fseek(hf,0,SEEK_SET);
+ if(fread(X,1,fs,hf)!=fs)
+ {
+ fs=0;
+ }
+ }
+ fclose(hf);
+ }
+ return fs;
+}
+
+// #########################################################################
+// dd if=/dev/mapper/root-crypt | gzip | hexdump -v -e '64/1 "%02x""\n"'
+int dehex(const char*in,const char*out)
+{
+ size_t fs=loadFile(in,0);
+ if(fs)
+ {
+ printf("input: %s, fs: %u\n",in,fs);
+ uint8_t b_in[fs+16];
+ uint8_t b_out[fs+16];
+ uint8_t b_tmp[4*1024];
+ fs=loadFile(in,b_in);
+ size_t outLen=0;
+ size_t lineLen=0;
+ uint8_t octet=0,value=0;
+ int fileNumber=0;
+ for(size_t i=0;i<fs;++i)
+ {
+ uint8_t c=b_in[i];
+ switch(c)
+ {
+ case 'A'...'F':
+ c=c-'A'+'a';
+ case 'a'...'f':
+ c=c-'a'+'0'+10;
+ case '0'...'9':
+ c=c-'0';
+ octet=1-octet;
+ value=(value<<4)|(c&0xf);
+ if(octet==0)
+ {
+ b_tmp[lineLen++]=value;
+ }
+ break;
+ case '\n':
+ if(lineLen)
+ {
+ memcpy(b_out+outLen,b_tmp,lineLen);
+ outLen+=lineLen;
+ }
+ case ':':
+ lineLen=0;
+ case ' ':
+ octet=0;
+ break;
+ default:
+ if(outLen)
+ {
+ char fout[1024];
+ sprintf(fout,"%s_%i.bin",out,++fileNumber);
+ printf("output: %s, fs: %u\n",fout,outLen);
+ saveFile(fout,b_out,outLen);
+ outLen=0;
+ }
+ lineLen=0;
+ octet=2;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+// #########################################################################
+
+int checksum(const char*in,int fix)
+{
+ size_t fs=loadFile(in,0);
+ if(fs)
+ {
+ printf("input: %s, fs: %u\n",in,fs);
+ uint8_t data[fs+3];
+ fs=loadFile(in,data);
+ uint32_t*data32=reinterpret_cast<uint32_t*>(data);
+
+ if((fs<32)||(memcmp(data+4,"eGON.BT",7)!=0))
+ {
+ printf("eGON header is not found\n");
+ return 1;
+ }
+
+ uint32_t l=le32toh(data32[4]);
+ if((l>fs)||((l%4)!=0))
+ {
+ printf("bad length in the eGON header\n");
+ return 1;
+ }
+ l/=4;
+
+ uint32_t c=0x5F0A6C39-le32toh(data32[3]);
+ for(uint32_t i=0;i<l;++i)
+ c+=le32toh(data32[i]);
+
+ if(c!=le32toh(data32[3]))
+ {
+ if(fix!=0)
+ {
+ data32[3]=htole32(c);
+ saveFile(in,data,fs);
+ printf("checksum updated\n");
+ return 0;
+ }
+ printf("checksum check failed\n");
+ return 1;
+ }
+
+ printf("checksum OK\n");
+ return 0;
+ }
+ return 1;
+}
+
+// #########################################################################
+
+int split(const char*in)
+{
+ size_t fs=loadFile(in,0);
+ if(fs)
+ {
+ printf("input: %s, fs: %u\n",in,fs);
+ uint8_t data[fs+3];
+ fs=loadFile(in,data);
+ while(data[fs-1]==0xff)
+ --fs;
+ uint32_t*data32=reinterpret_cast<uint32_t*>(data);
+ uint32_t offs=le32toh(data32[6]);
+ saveFile("script.bin",data+offs,fs-offs);
+ fs=offs;
+ while(data[fs-1]==0xff)
+ --fs;
+ data32[5]=0;
+ data32[6]=0;
+ saveFile(in,data,fs);
+ return 0;
+ }
+ return 1;
+}
+
+// #########################################################################
+
+int join(const char*in0,const char*in1)
+{
+ size_t fs0=loadFile(in0,0);
+ size_t fs1=loadFile(in1,0);
+ if(fs0&&fs1)
+ {
+ printf("input: %s, fs: %u\n",in0,fs0);
+ printf("input: %s, fs: %u\n",in1,fs1);
+ uint8_t data[fs0*2+fs1];
+ fs0=loadFile(in0,data);
+ while(fs0&(0x10000-1))
+ data[fs0++]=0xff;
+ uint32_t*data32=reinterpret_cast<uint32_t*>(data);
+ data32[6]=htole32(fs0);
+ fs0+=loadFile(in1,data+fs0);
+ while(fs0&(0x2000-1))
+ data[fs0++]=0xff;
+ data32[5]=htole32(fs0);
+ saveFile(in0,data,fs0);
+ return 0;
+ }
+ return 1;
+}
+
+// #########################################################################
+
+int main(int argc,const char*argv[])
+{
+ int ret=0;
+ for(int i=1;i<argc;++i)
+ {
+ if(strcmp(argv[i],"dehex")==0)
+ {
+ const char*in=(argc>(i+1))?(++i,argv[i]):"capture";
+ const char*out=(argc>(i+1))?(++i,argv[i]):"dehexout";
+ ret+=dehex(in,out);
+ }
+ if(strcmp(argv[i],"check")==0)
+ {
+ const int fix=((argc>(i+1))&&(strcmp(argv[i+1],"-f")==0))?++i:0;
+ const char*in=(argc>(i+1))?(++i,argv[i]):"fes1.bin";
+ ret+=in?checksum(in,fix):1;
+ }
+ if(strcmp(argv[i],"split")==0)
+ {
+ const char*in=(argc>(i+1))?(++i,argv[i]):"uboot.bin";
+ ret+=split(in);
+ }
+ if(strcmp(argv[i],"join")==0)
+ {
+ const char*in0=(argc>(i+1))?(++i,argv[i]):"uboot.bin";
+ const char*in1=(argc>(i+1))?(++i,argv[i]):"script.bin";
+ ret+=join(in0,in1);
+ }
+ }
+}
+
+// #########################################################################
diff --git a/udev/50-sunxi-fel.rules b/udev/50-sunxi-fel.rules
new file mode 100644
index 0000000..d4545e7
--- /dev/null
+++ b/udev/50-sunxi-fel.rules
@@ -0,0 +1,2 @@
+# /etc/udev/rules.d/
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="1f3a", ATTRS{idProduct}=="efe8", MODE:="0666"