summaryrefslogtreecommitdiffstats
path: root/debian/grub-extras/ntldr-img
diff options
context:
space:
mode:
Diffstat (limited to 'debian/grub-extras/ntldr-img')
-rw-r--r--debian/grub-extras/ntldr-img/COPYING674
-rw-r--r--debian/grub-extras/ntldr-img/Makefile.core.common38
-rw-r--r--debian/grub-extras/ntldr-img/Makefile.core.def32
-rw-r--r--debian/grub-extras/ntldr-img/README11
-rw-r--r--debian/grub-extras/ntldr-img/bin2h.c69
-rw-r--r--debian/grub-extras/ntldr-img/g2hdr.S98
-rw-r--r--debian/grub-extras/ntldr-img/grldrstart.S5793
-rw-r--r--debian/grub-extras/ntldr-img/grubinst.c1043
-rw-r--r--debian/grub-extras/ntldr-img/ntfsbs.S1508
-rw-r--r--debian/grub-extras/ntldr-img/utils.c392
-rw-r--r--debian/grub-extras/ntldr-img/utils.h88
-rw-r--r--debian/grub-extras/ntldr-img/version.h3
12 files changed, 9749 insertions, 0 deletions
diff --git a/debian/grub-extras/ntldr-img/COPYING b/debian/grub-extras/ntldr-img/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/debian/grub-extras/ntldr-img/COPYING
@@ -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:
+
+ <program> Copyright (C) <year> <name of author>
+ 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/debian/grub-extras/ntldr-img/Makefile.core.common b/debian/grub-extras/ntldr-img/Makefile.core.common
new file mode 100644
index 0000000..f5c0c60
--- /dev/null
+++ b/debian/grub-extras/ntldr-img/Makefile.core.common
@@ -0,0 +1,38 @@
+if COND_i386_pc
+# Compatibility symlink.
+g2hdr.bin: g2hdr.img
+ rm -f $@
+ $(LN_S) $< $@
+platform_DATA += g2hdr.bin
+CLEANFILES += g2hdr.bin
+
+g2ldr.mbr: g2ldr.img
+ head -c 8192 $< > $@
+platform_DATA += g2ldr.mbr
+CLEANFILES += g2ldr.mbr
+
+grldr.mbr: grldr.img
+ head -c 8192 $< > $@
+CLEANFILES += grldr.mbr
+
+bin2h: contrib/ntldr-img/bin2h.c
+ $(BUILD_CC) $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(BUILD_LDFLAGS) $^ -o $@
+CLEANFILES += bin2h
+
+grub_mbr.h: grldr.mbr bin2h
+ ./bin2h grub_mbr 8192 < $< > $@
+CLEANFILES += grub_mbr.h
+
+grub-ntldr-img$(EXEEXT): contrib/ntldr-img/grubinst.c contrib/ntldr-img/utils.c grub_mbr.h
+ $(HOST_CC) $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(HOST_LDFLAGS) -DGRUB_UTIL=1 -I. -I$(srcdir)/contrib/ntldr-img -DLINUX -o $@ $(srcdir)/contrib/ntldr-img/grubinst.c $(srcdir)/contrib/ntldr-img/utils.c
+bin_PROGRAMS += grub-ntldr-img
+CLEANFILES += grub-ntldr-img
+
+# Compatibility symlink.
+grubinst$(EXEEXT): grub-ntldr-img$(EXEEXT)
+ rm -f $@
+ $(LN_S) $< $@
+noinst_PROGRAMS += grubinst
+CLEANFILES += grubinst
+
+endif
diff --git a/debian/grub-extras/ntldr-img/Makefile.core.def b/debian/grub-extras/ntldr-img/Makefile.core.def
new file mode 100644
index 0000000..59dd44b
--- /dev/null
+++ b/debian/grub-extras/ntldr-img/Makefile.core.def
@@ -0,0 +1,32 @@
+AutoGen definitions Makefile.tpl;
+
+image = {
+ name = g2hdr;
+ i386_pc = contrib/ntldr-img/g2hdr.S;
+ i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
+ i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x0';
+ objcopyflags = '-O binary';
+ enable = i386_pc;
+};
+
+image = {
+ name = grldr;
+ i386_pc = contrib/ntldr-img/grldrstart.S;
+ i386_pc = contrib/ntldr-img/ntfsbs.S;
+ i386_pc_ccasflags = -DGRLDR_MBR;
+ i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
+ i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x7c00';
+ objcopyflags = '-O binary';
+ enable = i386_pc;
+};
+
+image = {
+ name = g2ldr;
+ i386_pc = contrib/ntldr-img/grldrstart.S;
+ i386_pc = contrib/ntldr-img/ntfsbs.S;
+ i386_pc_ccasflags = '-DGRLDR_MBR -DBOOTGRUB2';
+ i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
+ i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x7c00';
+ objcopyflags = '-O binary';
+ enable = i386_pc;
+};
diff --git a/debian/grub-extras/ntldr-img/README b/debian/grub-extras/ntldr-img/README
new file mode 100644
index 0000000..874bd08
--- /dev/null
+++ b/debian/grub-extras/ntldr-img/README
@@ -0,0 +1,11 @@
+
+grub-extras is meant to be used as an overlay on grub2 source tree.
+
+Build instructions:
+
+ - Copy grub-extras in a subdirectory of your grub2 checkout.
+ For example, "grub-extras".
+
+ - Export GRUB_CONTRIB environment variable to point to this directory.
+
+ - Build GRUB as usual.
diff --git a/debian/grub-extras/ntldr-img/bin2h.c b/debian/grub-extras/ntldr-img/bin2h.c
new file mode 100644
index 0000000..f713b55
--- /dev/null
+++ b/debian/grub-extras/ntldr-img/bin2h.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2008 Robert Millan
+ *
+ * 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/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (int argc, char *argv[])
+{
+ int b, i;
+ char *sym;
+ unsigned int len;
+
+ if (argc != 3)
+ {
+ fprintf (stderr, "Usage: %s symbol_name length\n", argv[0]);
+ exit (1);
+ }
+
+ sym = argv[1];
+ len = atoi (argv[2]);
+
+ b = getchar ();
+ if (b == EOF)
+ goto abort;
+
+ printf ("/* THIS CHUNK OF BYTES IS AUTOMATICALY GENERATED */\n"
+ "unsigned char %s[%u] =\n{\n", sym, len);
+
+ while (1)
+ {
+ printf ("0x%02x", b);
+
+ b = getchar ();
+ if (b == EOF)
+ goto end;
+
+ for (i = 0; i < 16 - 1; i++)
+ {
+ printf (", 0x%02x", b);
+
+ b = getchar ();
+ if (b == EOF)
+ goto end;
+ }
+
+ printf (",\n");
+ }
+
+end:
+ printf ("\n};\n");
+
+abort:
+ exit (0);
+}
diff --git a/debian/grub-extras/ntldr-img/g2hdr.S b/debian/grub-extras/ntldr-img/g2hdr.S
new file mode 100644
index 0000000..4b8e0e6
--- /dev/null
+++ b/debian/grub-extras/ntldr-img/g2hdr.S
@@ -0,0 +1,98 @@
+/*
+ * GRUB Utilities -- Utilities for GRUB Legacy, GRUB2 and GRUB for DOS
+ * Copyright (C) 2007 Bean (bean123@126.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <grub/machine/kernel.h>
+
+ .file "g2hdr.S"
+
+ .text
+
+ .code16
+
+ .globl start, _start
+
+start:
+_start:
+
+ // We are at 0x2000:0
+ // Move itself to 0x800:0
+ // Don't modify dx
+
+ cld
+ movw %cs, %ax
+ movw %ax, %ds
+ movw $0x800, %ax
+ movw %ax, %es
+ xorw %si, %si
+ movw %si, %di
+ movw $0x80, %cx
+
+ rep
+ movsl
+
+ ljmp $0, $(jump_start-start+0x8000)
+
+jump_start:
+ // Move data from 0x2040:0 to 0x820:0
+
+ movw $0x2040, %ax
+ movw %ax, %ds
+ movw $0x820, %ax
+ movw %ax, %es
+ xorl %eax, %eax
+ movb %dh, (GRUB_DECOMPRESSOR_I386_PC_BOOT_DEVICE + 2)
+ movl GRUB_DECOMPRESSOR_MACHINE_COMPRESSED_SIZE, %eax
+ addl $GRUB_DECOMPRESSOR_I386_PC_MAX_DECOMPRESSOR_SIZE, %eax
+ xorl %ecx, %ecx
+
+1:
+ xorw %si, %si
+ movw %si, %di
+
+ movw $0x8000, %cx
+ cmpl %ecx, %eax
+ jae 2f
+ movw %ax, %cx
+2:
+
+ pushw %cx
+ addw $3, %cx
+ shrw $2, %cx
+
+ rep
+ movsl
+
+ popw %cx
+
+ movw %ds, %si
+ addw $0x800, %si
+ movw %si, %ds
+
+ movw %es, %si
+ addw $0x800, %si
+ movw %si, %es
+
+ subl %ecx, %eax
+ jnz 1b
+
+ ljmp $0, $(0x8000 + 0x200)
+
+ . = _start + 0x200 - 2
+
+ .word 0xAA55
diff --git a/debian/grub-extras/ntldr-img/grldrstart.S b/debian/grub-extras/ntldr-img/grldrstart.S
new file mode 100644
index 0000000..1751338
--- /dev/null
+++ b/debian/grub-extras/ntldr-img/grldrstart.S
@@ -0,0 +1,5793 @@
+/*
+ * grldrstart.S -- Startup code for GRLDR
+ * Copyright (C) 2004-2007 Tinybit(tinybit@tom.com)
+ * Copyright (C) 2007 Bean(bean@windrv.net)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This program is used to generate the GRLDR file.
+ *
+ * Use the following shell command to generate the GRLDR file:
+ *
+ * cat grldrstart pre_stage2 > grldr
+ *
+ */
+
+#ifndef STAGE1_5
+//#include <stage2_size.h>
+#else
+#error cannot compile with STAGE1_5
+#endif
+
+#ifdef GRLDR_MBR
+ .file "mbrstart.S"
+#elif defined(GRLDR_INSTALL)
+ .file "bootlacestart.S"
+#else
+ .file "grldrstart.S"
+#endif
+
+#ifdef GRLDR_INSTALL
+ //.data
+#else
+ .text
+
+ .globl start, _start
+
+start:
+_start:
+#endif
+
+_start1:
+
+ /* Tell GAS to generate 16-bit real mode instructions */
+
+ .code16
+
+ . = _start1 + 0x00
+
+ /* 1 byte at offset 0x00 will be overwritten for the EBIOS indicator
+ * later. This is safe because the jmp instruction only get executed
+ * once. The write happens after the jmp instruction have got
+ * executed.
+ *
+ * The value written would be 0x42 for EBIOS present(LBA) and 0x02
+ * for non-present(CHS).
+ *
+ */
+
+ /* No cli, we use stack! BIOS or caller usually sets SS:SP=0000:0400 */
+
+ jmp 1f /* FAT32/NTFS routine comes to offset 0 */
+
+ . = _start1 + 0x02
+
+ .byte 0x80 /* bit0=1: disable GRLDR search on floppy */
+ /* bit1=1: disable the boot of the previous MBR with
+ * invalid partition table */
+ /* bit2=1: disable the feature of unconditional
+ * entrance to the command-line */
+ /* bit7=1: disable the boot of the previous MBR prior
+ to the search for GRLDR */
+
+ /* GRLDR.MBR uses offset 0x03 to indicate a timer counter. */
+
+ /* 0xff indicates waiting forever,
+ * other value specifies the time in seconds to wait */
+
+ . = _start1 + 0x03
+
+ .byte 5
+
+ /* a key press to wait. if AX returned from int16 equals this word,
+ * the desired action will occur. */
+
+ . = _start1 + 0x04
+
+ .word 0x3920 /* the space bar */
+
+ . = _start1 + 0x06
+
+ .byte 0xff /* preferred boot drive number, 0xff for no-drive(i.e., drive not defined) */
+ .byte 0xff /* preferred partition number, 0xff for whole drive(a floppy that has no partition table) */
+
+ . = _start1 + 8
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+
+ /* filled in by mkisofs using the -boot-info-table option */
+
+#;bi_pvd: .long 0xDEADBEEF /* LBA of primary volume descript */
+#;bi_file: .long 0xDEADBEEF /* LBA of boot file */
+#;bi_length: .long 0xDEADBEEF /* Length of boot file */
+#;bi_csum: .long 0xDEADBEEF /* Checksum of boot file */
+#;bi_reserved: .space (10*4) /* Reserved */
+
+ . = _start1 + 0x40
+
+#else
+
+ /* filled in with BPB in case the drive(typically USB) is treated as floppy by buggy BIOSes */
+
+ . = _start1 + 0x60
+
+#endif /* ! defined(GRLDR_MBR) && (! defined(GRLDR_INSTALL)) */
+
+1:
+ call 1f
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+
+ . = _start1 + 0x43
+
+#else
+
+ . = _start1 + 0x63
+
+#endif /* ! defined(GRLDR_MBR) && (! defined(GRLDR_INSTALL)) */
+
+1:
+ popw %bx /* Instruction Pointer of 1b */
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+
+ subw $(1b - _start1), %bx /* CS:BX=_start1 */
+
+#else
+
+ subw $(1b - _start1), %bx /* CS:BX=_start1 */
+
+#endif /* ! defined(GRLDR_MBR) && (! defined(GRLDR_INSTALL)) */
+
+ shrw $4, %bx
+ movw %cs, %ax
+ addw %ax, %bx /* BX:0000=_start1 */
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+
+ /* we are booted from BOOT.INI, or whole GRLDR image already loaded */
+
+ pushw %bx /* BX:0000=_start1 */
+ addw $((grldr_signature - _start1 + 4 + STAGE2_SIZE - 4) >> 4), %bx
+ movw %bx, %ds
+
+ cmpl $0xCE1A02B0, ((STAGE2_SIZE - 4) & 0x0F)
+ popw %ds /* DS:0000=_start1 */
+ je grldr_real_start /* whole image loaded. boot it! */
+
+ /* bad! we might be loaded by a buggy BIOS with a no-emulation-mode
+ * bootable CD. The buggy BIOS might load only 1 CD-ROM sector(2048
+ * bytes) of our grldr image. So we need this check.
+ */
+
+ /* Our cdrom_check code begins at 0x1BE and overlaps the partition
+ * table. Just in case someone replace it with a partition table and
+ * use this sector as an MBR, we do this additional test for safety.
+ */
+
+ /* We should avoid using opcode 0x00 and 0x80 at cdrom_check. */
+
+ /* Note that if cdrom_check code is present, then we are booting from
+ * no-emulation mode cdrom.
+ */
+
+ testb $0x7F, cdrom_check - _start1 /* is it 0x00 or 0x80? */
+ jz 1f /* yes, cdrom_check not found */
+ call cdrom_check /* no, cdrom_check is present */
+1:
+ /* DS:0000=_start1 */
+
+ /* Let CS:0000=_start1 */
+ pushw %ds
+
+ #;pushw $(1f - _start1)
+ .byte 0x6A, (1f - _start1)
+
+ lret
+ . = . - (. - _start1) / 0x80
+1:
+#else
+ /* BX:0000=_start1 */
+
+ movw %bx, %ds
+
+ /* Let CS:0000=_start1 */
+ pushw %bx
+
+ #;pushw $(1f - _start1)
+ .byte 0x6A, (1f - _start1)
+
+ lret
+ . = . - (. - _start1) / 0x80
+1:
+ testb $0x04, 0x02
+ jz 1f
+
+ /* set the DUCE indicator */
+ xorw %ax, %ax
+ movw %ax, %es
+ movw $0x5FC, %di
+ movl $0x45435544, %eax
+ stosl
+1:
+#endif
+
+ /* CS:0000=DS:0000=_start1 */
+
+ /* we are loaded by BIOS or another boot loader */
+
+#define GRLDR_CS 0x2000 /* grldr code segment */
+ /* hope this segment never be used by all */
+ /* subsequent partition boot records */
+#if 0
+ /* for single sector boot record */
+#define MONITOR 0x7e10
+#else
+ /* for 4-sector NTFS boot record */
+#define MONITOR 0x8410
+#endif
+
+// cli
+ pushw $GRLDR_CS
+ popw %ss
+ movw $0x9000, %sp /* SS:SP=0x9d000, keep away from EBDA data */
+// sti
+
+ /* Extended BIOS Data Area should not take up space below 0x9d000 */
+
+ /*
+ * 0x07c00-0x07dff This sector. Another boot loader load us here
+ * 0x0d000-0x14dff partition/floppy boot track(bootsector,etc)
+ * 0x94000-0x9bdff master boot track(MBR,etc,usually 63 sectors)
+ * 0x9be00-0x9c3ff 3 sectors for temp extended partition entries
+ * 0x9c400-0x9cfff 6 sectors for stack
+ */
+
+#define FS_BOOT 0xd00 /* segment of partition boot track */
+
+ xorw %cx, %cx
+ pushw %cx /* CX=0 */
+ movw $0x0080, %dx
+ pushw %dx
+ movb $8, %ah /* read drive parameters changes DX,ES,DI */
+ stc
+ int $0x13
+ popw %dx
+ popw %ax /* AX=0 */
+
+ pushw %ss /* SS=0x9400 */
+ popw %es /* ES=0x9400 */
+
+ jc Error1
+
+ andb $63, %cl /* AL=sectors per track, CF cleared */
+
+ stc
+ jz Error1
+
+ xchgw %ax, %cx /* this moves CL to AL, and CX=0 */
+ movb $0x02, %ah
+ movw %ax, %bp /* save AX to BP: read 1 track */
+ xorw %bx, %bx /* ES already has a known value of 0x9400 */
+ incw %cx
+ pushw %dx
+ stc
+ int $0x13 /* read master boot track to ES:0000 */
+ popw %dx
+ jc Error1
+ negb %ah /* set CF=1 if non-zero */
+Error1:
+ pushw %cs /* DS=0 */
+ popw %ds /* DS=CS */
+ pushfw /* CF=1 on error */
+
+ /* CS=DS=old segment. ES=SS=new segment. */
+
+ /* Move the code and error messages from DS:0000 to 9400:0000, do not
+ * touch the partition table
+ */
+ xorw %si, %si
+ xorw %di, %di
+ movw $223, %cx /* 223 words = 446 bytes = 0x1be bytes */
+ cld
+ repz movsw /* SI=DI=0x1be, CX=0 */
+
+ movw $(grldr_signature - _start1), %bx
+
+ /* if the boot loader has loaded more than one sector, we use them */
+ movl $0xAA555247, %eax /* "GR" 0x55 0xAA */
+//#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+ cmpl %eax, (%bx) /* DS=old segment! */
+ jne 1f
+
+ /* The MOVE_HELPER code is in the old segment! */
+
+ call move_helper /* SI=0x1be, CX=0 */
+1:
+//#endif
+
+ /* Jump to new segment! */
+#if 1
+ ljmp $GRLDR_CS, $(1f - _start1)
+#else
+ pushw %ss /* 0x9400 */
+
+ //pushw $(1f - _start1)
+ .byte 0x6A, (1f - _start1)
+
+ lret
+ . = . - (. - _start1) / 0x80
+#endif
+1:
+
+ /* We are at the new segment. CS=ES=SS=new segment. */
+
+ /* But DS is still old segment. */
+
+ pushw %ss
+ popw %ds
+
+ /* CS=DS=ES=SS=new segment. */
+
+ //movw $0x01be, %si
+
+ /* check the existence of helper */
+ cmpl %eax, (%bx)
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+
+ jne Error_or_prev_MBR /* Missing helper */
+
+#else
+
+ je 1f
+
+ /* try to load helper from floppy */
+
+ pushal
+
+ movw 0x18, %ax /* BPB sectors per track at offset 0x18 */
+
+ cmpw $0x3F, %ax
+ ja 3f
+
+ cmpb $((pre_stage2_start - _start1) >> 9), %al
+ jb 3f
+
+ decw %ax /* skip the first sector already loaded */
+
+ movw $3, %di /* retry 3 times on read failure */
+2:
+ movb $2, %ah /* BIOS disk read */
+ cwd /* DX=0 for floppy head 0 */
+ movw $0x200, %bx /* ES:BX immediately follow this sector */
+ movw $2, %cx /* skip the first sector already loaded */
+
+ pushaw
+ int $0x13
+ popaw
+
+ jnc 3f
+
+ pushaw
+ xorw %ax, %ax
+ int $0x13
+ popaw
+
+ decw %di
+ jnz 2b
+3:
+ popal
+ cmpl %eax, (%bx) /* helper loaded? */
+
+ jne Error_or_prev_MBR /* Missing helper */
+
+1:
+#endif
+
+ popfw /* CF=1 on error */
+ jc try_floppy /* harddisk (hd0) failed, try floppy (fd0) */
+1:
+ pushw %cs
+ popw %ds
+ lodsw
+ movb %ah, %dh /* head number */
+ lodsw
+ movw %ax, %cx /* sector and cylinder number */
+ andb $63, %al
+ //stc
+ jz helper_call_c
+
+ /* use BP to calculate the sectors to read within 1 track */
+ subw %bp, %ax
+ decw %ax /* decb %al */
+ negb %al /* AL=sectors upto the end of the track */
+7:
+ movw $3, %di /* retry 3 times on read failure */
+2:
+ movb $2, %ah
+ pushw $FS_BOOT
+ popw %es /* ES=FS_BOOT */
+ xorw %bx, %bx
+
+ pushaw
+ int $0x13 /* read partition boot track to FS_BOOT:0000 */
+ popaw
+
+ jnc helper_call
+
+ pushaw
+ xorw %ax, %ax
+ int $0x13
+ popaw
+
+ decw %di
+ jnz 2b
+
+helper_call_c:
+
+ stc
+
+helper_call:
+ /* find GRLDR in this partition
+ * before the call:
+ * CF=1 : indicates an invalid or corrupt entry
+ * CF=0 : indicates a valid entry
+ *
+ * on return:
+ * CF=1 : means "below", try next entry
+ * CF=0,ZF=1 : means "equal", helper did nothing, so we need
+ * a further try to boot via NT bootsector
+ * CF=0,ZF=0 : means "above", helper succeeded, boot it now
+ */
+ call helper_start /* change to jmp 6f if helper not present */
+ ja filesystem_boot /* helper succeeded, directly boot it */
+6:
+
+add_sub_si:
+
+ /* extended partition check routine will adjust this to
+ *
+ * 0x83, 0xEE, 0x04 for "subw $4, %si"
+ *
+ * or
+ *
+ * 0x83, 0xC6, 0xFC for "addw $-4, %si"
+ *
+ * so that SI keeps the value 0x1fe.
+ */
+ addw $12, %si /* 0x83, 0xC6, 0x0C */
+
+ . = add_sub_si + 3
+
+ /* extended partition check routine will adjust the word 0x1fe at
+ * (add_sub_si + 5). The value 0x1ff or greater indicates there are
+ * entries need to be treated. The value 0x1fe indicates no entries
+ * left, and the floppy should be checked.
+ */
+
+ cmpw $0x01fe, %si /* 0x81, 0xFE, 0xfe, 0x01 */
+ /* All entries checked done? */
+ jb 1b /* No, check the next entry */
+ ja 5f /* floppy already checked. Fail and hang */
+
+try_floppy:
+
+ movw $0x31b2, %si /* a value big enough */
+ movb $0x08, %ah /* read drive parameters changes DX,ES,DI */
+ cwd /* DL=0 for floppy */
+ pushw %dx /* DX=0 */
+ int $0x13
+ popw %ax /* AX=0 */
+ jc 5f /* floppy failure, issue "Error" and hang */
+ cwd /* DX=0 */
+ xchgw %ax, %cx /* this moves CL to AL, and CX=0 */
+ andb $63, %al /* AL=sectors per track */
+ jz 5f /* invalid value. floppy failure. hangs */
+ //movw $1, %cx
+ incw %cx
+ jmp 7b
+
+5:
+Error_or_prev_MBR:
+
+ /* GRLDR not found, print "Error" or launch previous MBR */
+ movw $(message_string - _start1), %si
+Error2:
+ call print_message /* CS:SI points to message string */
+3: jmp 3b
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+filesystem_boot:
+ /* The partition boot record successfully modified, just boot it */
+
+ /*
+ * The boot might fail, but we want to take back the control.
+ * So we save the registers now.
+ */
+ pushw %ds
+ pushw %es
+ pushal
+
+ /* DS=CS=GRLDR_CS, ES=FS_BOOT */
+
+ /* save GRLDR_CS */
+
+ movw %es, %bx # save old ES to BX
+
+ cli
+ lgdt gdt - _start1
+ movl %cr0, %eax
+ orb $1, %al
+ movl %eax, %cr0
+
+ movw $8, %si
+ movw %si, %es
+
+ xorl %esi, %esi
+ xorl %edi, %edi
+ movl $(0x9000 / 4), %ecx
+
+ cld
+ repz movsl
+
+ movw $16, %si
+ movw %si, %es
+
+ andb $0xfe, %al
+ movl %eax, %cr0
+
+ movw %bx, %es # restore ES from BX
+
+ /* move FS_BOOT:0000 to 0:7c00 */
+#if 0
+ /* for single sector boot record */
+ movw $0x0200, %cx /* move 2 sectors, the old FS_BOOT:0000 will
+ * keep untouched. */
+#else
+ /* for 4-sector NTFS boot record */
+ movw $0x0400, %cx /* move 4 sectors, the old FS_BOOT:0000 will
+ * keep untouched. */
+#endif
+ xorw %si, %si
+ pushw %si /* SI=0, for the segment of 0000:7c00 */
+ movw $0x7c00, %di
+ pushw %di /* DI=0x7c00, for the offset of 0000:7c00 */
+ pushw %es /* ES=FS_BOOT */
+ popw %ds /* DS=FS_BOOT */
+ pushw %si /* SI=0 */
+ popw %es /* ES=0 */
+ cld
+ repz movsw
+
+ movw $MONITOR, %di
+ movw $(restore_GRLDR_CS - _start1), %si
+ movw $((gdt_end - restore_GRLDR_CS) / 4), %cx
+ cld
+ repz cs movsl /* CS segment override prefix(=0x2E) */
+
+ pushw %es /* ES=0 */
+ popw %ds /* DS=0 */
+ sti
+ lret //ljmp $0, $0x7c00
+#endif
+
+try_next_partition:
+
+ cli
+ movw $GRLDR_CS, %ax
+ movw %ax, %ss
+ movw $(0x9000-36), %sp
+ sti
+
+ /* restore the registers and continue */
+ popal
+ popw %es
+ popw %ds
+ jmp add_sub_si
+
+ /* prints string CS:SI (modifies AX BX SI) */
+3:
+ //xorw %bx, %bx /* video page 0 */
+ movb $0x0e, %ah /* print char in AL */
+ int $0x10 /* via TTY mode */
+
+print_message:
+
+ lodsb %cs:(%si), %al /* get token */
+ cmpb $0, %al /* end of string? */
+ jne 3b
+ ret
+
+message_string:
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+ .ascii "\r\nMissing helper.\0"
+#else
+ .ascii "\r\nMissing MBR-helper.\0"
+#endif
+
+#;buggy_bios_string:
+#;
+#; .ascii "\r\nBuggy BIOS!\0"
+
+ /* Make sure the above code does not occupy the partition table */
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+ /* offset value here must be less than or equal to 0x1be */
+ . = . - ((. - _start1) / 0x1bf)
+#else
+ /* offset value here must be less than or equal to 0x1b8 */
+ . = . - ((. - _start1) / 0x1b9)
+#endif
+
+ /* The following code may occupy the same area as the partition table */
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+
+ /* we are not booted from MBR. So we can reuse the area of partition
+ * table for our code.
+ */
+
+ . = _start1 + 0x1be
+
+cdrom_check:
+
+ /* DS points to the sector start, but CS does not. */
+
+ /* BX segment points to near the end of GRLDR image. */
+
+ popw %ax /* old return IP */
+
+ /* set BX as the new safe stack. */
+ movw %bx, %ss
+ movw $0xFFF0, %sp
+
+ pushw %ax /* old return IP */
+
+ /* check if DL is no-emulation-mode bootable CDROM. */
+ pushw %ds
+
+ cmpb $0x80, %dl
+ jb 1f /* not a valid no-emulation-mode cdrom drive number */
+
+ cmpw $0xAA55, 0x7FE /* 2048 bytes loaded? */
+ jne 1f
+
+// cmpw $0xAA55, 0x5FE /* 2048 bytes loaded? */
+// jne 1f
+
+ movw $0x0180, %si
+ movw $0x4B01, %ax
+ pushw $0x0040
+ //.byte 0x6A, 0x40
+ popw %ds
+ pushw %ds
+ popw %es
+ movb $0x13, (%si)
+ int $0x13
+
+ /* ignore CF */
+#; jc 2f /* not in emulation mode */
+ xorl %eax, %eax
+ xorw %bp, %bp
+ testb $0x0F, 1(%si) /* boot media type is No Emulation? */
+ jnz 2f /* no, it simulates floppy or hard disk. */
+ cmpb %dl, 2(%si) /* drive number */
+ jnz 2f /* invalid drive */
+
+ /* OK! it is no-emulation-mode cdrom drive. */
+ movl 4(%si), %eax /* LBA of GRLDR */
+ incw %bp
+
+2:
+ jmp cdrom_helper
+1:
+ popw %ds
+ ret
+
+
+#endif /* ! defined(GRLDR_MBR) && (! defined(GRLDR_INSTALL)) */
+
+ . = _start1 + 0x1fe /* boot signature */
+
+/* partition entries in the extended partitions will overwrite code here upto
+ * 0x3fd.
+ *
+ * the extended partition entries will occupy a temp area at 0x9be00-0x9c3ff
+ */
+
+#if (defined(GRLDR_MBR)) || (defined(GRLDR_INSTALL))
+ .word 0xaa55
+#endif
+
+ . = _start1 + 0x200
+
+/* if it is in the Master Boot Track, the second sector can be used to backup
+ * the previously working MBR, typically, the MS MBR. if the backup copy of
+ * the MBR cannot boot(because, e.g., it depends on another sector of code
+ * that does not exist for now), then please do not set the ending signature
+ * to 0xAA55, that is to say, if the signature is already 0xAA55, you should
+ * change it to another value(for example, 0x0000).
+ */
+
+#if (! defined(GRLDR_INSTALL))
+#if 0
+print_cl:
+ pushaw
+
+ movw %cx, %ax
+ movb $16, %cl
+ divb %cl # quo=AL, rem=AH
+ orw $0x3030, %ax
+
+ cmpb $0x39, %ah
+ jbe 1f
+ addb $7, %ah
+1:
+ cmpb $0x39, %al
+ jbe 1f
+ addb $7, %al
+1:
+ movb %ah, %cl
+
+ xorw %bx, %bx
+
+ movb $0x0e, %ah
+ int $0x10
+
+ movb $0x0e, %ah
+ movb %cl, %al
+ int $0x10
+
+ movw $0x0e20, %ax
+ int $0x10
+
+ popaw
+ ret
+#else
+#if 0
+ .word 5, 0x47, 0x52, 0x4c, 0x44, 0x52, 4, 0x24
+ .word 0x49, 0x33, 0x30, 0xe000, 0, 0x3000, 0, 0
+#else
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+#endif
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+#endif
+ . = _start1 + 0x256 /* cmdcons comes here */
+
+#if 0
+ jmp 1f
+#else
+ .byte 0x90, 0x90
+#endif
+
+ . = _start1 + 0x258
+
+ .byte 0x90, 0x90
+
+ . = _start1 + 0x25a
+
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+ .byte 0x90, 0x90
+
+ . = _start1 + 0x26a
+1:
+ //movw %cs, %ax
+ //movw %ax, %ds
+ //jmp single_boot_sector
+
+ /* a value < 0x80 here means we are not booted from no-emulation-mode
+ * bootable CD.
+ */
+ movb $0x7F, %dl
+ jmp _start1
+
+#endif /* (! defined(GRLDR_INSTALL)) */
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+cdrom_helper:
+
+ /* IP and old_DS is on the stack. */
+
+ /* DS=ES=40h */
+
+ /* Stack is high and safe. */
+
+ /* EAX is LBA. if EAX==0, LBA is unknown. */
+
+ /* check if the first sector is the same as the current one */
+
+ /* load the first sector onto the sector immediately follows */
+1:
+ popw %bx /* BX = old_DS = load_segment */
+ pushw %bx
+ movw %bx, %es
+ addw $0x0080, %bx /* buffer segment */
+ call load_cd_sector
+
+ /* compare the two sectors */
+ movw $0x200, %cx
+ movw %bx, %ds
+ xorw %si, %si
+ xorw %di, %di
+ cld
+ repz cmpsl
+ je load_the_rest /* 1st sector is ok, continue */
+not_grldr:
+ testw %bp, %bp
+ jz 2f
+ xorw %bp, %bp
+ xorl %eax, %eax
+2:
+ incl %eax
+ jnz 1b /* try next */
+
+cd_no_grldr:
+
+ popw %ds /* DS=load_segment */
+
+ # Here we use error message and routine in FAT32 boot sector
+ # which is also inside the 2048-byte CD sector.
+
+ movw $(msg_BootError_32 - _start1), %si
+ jmp boot_error_32
+
+load_cd_sector:
+ /* input: EAX LBA
+ * BX buffer segment(buffer offset=0)
+ * DS 0x40 (or another safe one)
+ */
+
+ movw $0x1A0, %si
+
+ /* disk address packet */
+ movl $0x00010010, (%si) /* load 1 sector each time. */
+ movw $0, 4(%si) /* buffer offset=0 */
+ movw %bx, 6(%si) /* buffer segment */
+ movl %eax, 8(%si) /* LBA lo 32 bits */
+ movl $0, 12(%si) /* LBA hi 32 bits */
+
+ pushal
+ movb $0x42, %ah
+ int $0x13
+ popal
+ ret
+
+load_the_rest:
+
+ /* load all sectors (except the first one) */
+
+ /* EAX = first sector(LBA) of GRLDR */
+
+ popw %bx /* BX = old_DS = load_segment */
+ pushw %bx
+ movw %bx, %es
+ /* 6144 = 0x1800 = 3 sectors > 4KB, this is for the additional 4KB-preset-menu at the end of grldr */
+ movw $((grldr_signature - _start1 + 4 + STAGE2_SIZE - 1 + 6144) / 2048), %cx /* sectors to load */
+1:
+ incl %eax /* next sector */
+ addw $0x0080, %bx /* buffer segment */
+
+ call load_cd_sector
+
+ loop 1b
+
+ /* loading is completed. BX=segment of the last sector. */
+
+ subw $0x0181, %bx /* decw %bx */
+ movw %bx, %ds
+
+ /* check the ending signature */
+ cmpl $0xCE1A02B0, ((grldr_signature - _start1 + 4 + STAGE2_SIZE - 1) % 2048) + 13
+ jne not_grldr
+#; je grldr_real_start /* yes. boot it! */
+
+#; /* it is not our grldr image, return and use MBR-helper. */
+#;
+#;4:
+#; //jmp grldr_real_start
+#; popw %ds
+#; ret
+
+grldr_real_start:
+
+ #; FAT_12_16 no longer be used. So comment out.
+ #;je 1f /* jc 1f */
+ #;//ZF=0 /* CF cleared, so we are coming from FAT_12_16 */
+ #;popw %dx /* discard the cluster number */
+ #;popw %dx /* this is our boot_drive/boot_partition */
+ #;1:
+
+ #; The partition number for no-emulation-mode bootable CDROM will be
+ #; set to 0xFF later(in common.c). So comment out.
+ #;cli
+ #;movw %cs, %ax
+ #;cmpw $0x1000, %ax
+ #;jne 1f
+ #;
+ #;/* CS=0x1000, may be booted from ext2 or no-emulation-mode CDROM */
+ #;
+ #;cmpw $0x1000, %di
+ #;jne 2f
+ #;cmpw $0x7c00, %bp
+ #;jne 2f
+ #;movw %es, %ax
+ #;cmpw $0x1000, %ax
+ #;jbe 2f
+ #;cmpw $0x7c00, %si
+ #;jbe 2f
+ #;movl %edx, %eax
+ #;shrl $16, %eax
+ #;jnz 2f
+ #;jecxz 1f // booted from ext2 partition
+ #;2:
+ #;// booted from no-emulation-mode bootable CDROM
+ #;movb $0xff, %dh // partition 0xff means whole drive(for CDROM)
+ #; #; if needed, 0xfe can be used as an indicator
+ #; #; here for the bootable CDROM and changed to
+ #; #; 0xff later.
+ #;1:
+ #;
+ #;//if not booted from CDROM, don't touch the boot partition number(dh)
+
+ cli
+ xorw %ax, %ax
+ movw %ax, %ss
+ movw $0x0400, %sp /* tmp use real-mode IDT as stack */
+ movw %cs, %bp /* save CS to BP */
+ call 1f
+1:
+ popw %bx /* BX=Instruction Pointer of 1b */
+ subw $(1b - _start1), %bx
+ movw %bx, %cx
+ shrw $4, %bx
+ addw %bp, %bx
+ pushw %bx /* new CS */
+ andw $0x000f, %cx
+ addw $(1f - _start1), %cx
+ pushw %cx /* new IP */
+ lret
+1:
+ pushw %cs
+ popw %ds
+
+ /* CS=DS=BX, CS:0000 = _start1 */
+
+ addw $((pre_stage2_start - _start1) >> 4), %bx
+
+ /* BX:0000 = pre_stage2_start */
+
+ cmpw $0x820, %bx
+ jb 2f
+
+ movw $((0x8200 - (pre_stage2_start - _start1) - 0x400) >> 4), %cx
+
+ /* Now CS(=DS) >= CX+0x40 */
+
+ movw %cx, %es
+ xorw %di, %di
+ xorw %si, %si
+
+ /////////////////////////////////////////////////////////////
+ //
+ // CS
+ // DS 0x820 BX
+ // _start1---------------pre_stage2_start
+ // CX+0x40---------------0x820
+ // CX
+ // ES
+ //
+ /////////////////////////////////////////////////////////////
+
+ movw $0x200, %cx /* move 2 sectors */
+ cld
+ repz movsw
+
+ pushw %es /* ES:0000 = _start */
+ pushw $(1f - _start)
+ lret /* CS=ES, CS:0000 = _start1 */
+1:
+
+ /* move BX:0000 to 0820:0000 upward since BX >= 0x820 */
+
+ cld
+
+ movw %bx, %ds
+ movw $0x820, %bx
+ movw %bx, %es
+
+ xorw %si, %si
+ xorw %di, %di
+
+ movw $6, %bx /* 64K pages: 0x20000 - 0x7ffff */
+1:
+ movw $0x8000, %cx
+ repz movsw
+ movw %ds, %ax
+ addw $0x1000, %ax
+ movw %ax, %ds
+ movw %es, %ax
+ addw $0x1000, %ax
+ movw %ax, %es
+ decw %bx
+ jnz 1b
+
+ jmp 3f
+2:
+
+ /* move BX:0000 to 0820:0000 downward since BX < 0x820 */
+
+ std
+
+ addw $0x7000, %bx
+ movw %bx, %ds
+ movw $0x7820, %bx
+ movw %bx, %es
+
+ movw $0xfffe, %si
+ movw %si, %di
+
+ movw $8, %bx /* 64K pages: 0x08200 - 0x881ff */
+1:
+ movw $0x8000, %cx
+ repz movsw
+ movw %ds, %ax
+ subw $0x1000, %ax
+ movw %ax, %ds
+ movw %es, %ax
+ subw $0x1000, %ax
+ movw %ax, %es
+ decw %bx
+ jnz 1b
+
+ cld
+
+3:
+
+ /* put the config file name */
+ xorw %ax, %ax
+ movw %ax, %es
+ movw %ax, %ds
+
+ xorl %ebp, %ebp
+
+ movb %dh, 0x820A /* this is the boot partition number */
+
+ #; clear saved_entryno so that force_cdrom_as_boot_device be cleared
+ #; later in common.c
+
+ movl %ebp, 0x820C /* EBP=0, clear saved_entryno */
+
+ movw $0x0010, %cx /* set max length of grub version string */
+ movw $0x8212, %di /* version string */
+ cld
+ /* AL is already 0. Locate the end of version string */
+ repnz scasb /* find the location of the default config file name */
+
+ jcxz 1f /* failed, will not use the default config file name */
+
+ movw $0x4e, %cx /* max length of config file name */
+
+ movw %cs, %si /* CS:0000 = _start1 */
+ shlw $4, %si /* 0000:SI = _start1 */
+
+ addw $(default_config_file - _start1), %si
+
+ //movw $(default_config_file + 0x8200 - pre_stage2_start), %si
+ cld
+ repz movsb /* move file name to the config-file field of stage2 */
+1:
+
+ movw $0x0003, %ax /* set display mode: 80*25 color text */
+ int $0x10
+
+ xorw %bx, %bx
+ movw $(launch_pre_stage2 - _start1), %si
+ call print_message /* CS:SI points to message string */
+
+ xorw %ax, %ax
+ movw %ax, %ss
+ movw $0x2000, %sp
+
+ sti
+
+ ljmp $0, $0x8200
+
+launch_pre_stage2:
+ .ascii "\r\n\r\nBooting GRLDR...\r\n"
+
+ .byte 0 /* mark the end of ascii zero string */
+
+default_config_file:
+//#ifndef PRESET_MENU_STRING
+ .ascii "/menu.lst"
+//#else
+// .ascii "[default menu is disabled]"
+//#endif
+
+ .byte 0 /* mark the end of ascii zero string */
+#endif /* ! defined(GRLDR_MBR) && (! defined(GRLDR_INSTALL)) */
+
+ . = _start1 + 0x400
+
+#define ALTERNATIVE_KERNEL
+
+
+/*
+ * The following is based on FreeDOS, modified heavily by Tinybit in Feb, 2004
+ *
+ * Merges LBA and CHS boot sectors to ONE FAT32 boot sector!
+ *
+ * Memory layout for GRLDR FAT32 single stage boot process:
+ *
+ * ...
+ * |-------| 1FE0:7E00
+ * |BOOTSEC| (GRUB does not use this relocation area)
+ * |RELOC. | (overwritten by kernel loaded)
+ * |-------| 1FE0:7C00
+ * ...
+ * |-------|
+ * |KERNEL | (overwrites bootsec reloc.)
+ * |LOADED | (holds 1 sector directory buffer before kernel load)
+ * |-------| 2000:0000
+ * ...
+ * |-------| 0000:7E00
+ * |BOOTSEC| GRUB always run inside this sector,
+ * |ORIGIN | no relocation.
+ * |-------| 0000:7C00
+ * ...
+ * |-------| 0060:0200
+ * | FAT | (only 1 sector buffered)
+ * |-------| 0060:0000
+ * ...
+ *
+ */
+
+/*
+; This is an LBA-enabled FreeDOS FAT32 boot sector (single sector!).
+; You can use and copy source code and binaries under the terms of the
+; GNU Public License (GPL), version 2 or newer. See www.gnu.org for more.
+
+; Based on earlier work by FreeDOS kernel hackers, modified heavily by
+; Eric Auer and Jon Gentle in 7 / 2003.
+;
+; Features: Uses LBA and calculates all variables from BPB/EBPB data,
+; thus making partition move / resize / image-restore easier. FreeDOS
+; can boot from FAT32 partitions which start > 8 GB boundary with this
+; boot sector. Disk geometry knowledge is not needed for booting.
+;
+; Windows uses 2-3 sectors for booting (sector stage, statistics sector,
+; filesystem stage). Only using 1 sector for FreeDOS makes multi-booting
+; of FreeDOS and Windows on the same filesystem easier.
+;
+; Requirements: LBA BIOS and 386 or better CPU. Use the older CHS-only
+; boot sector if you want FAT32 on really old PCs (problems: you cannot
+; boot from > 8 GB boundary, cannot move / resize / ... without applying
+; SYS again if you use the CHS-only FAT32 boot sector).
+;
+; FAT12 / FAT16 hints: Use the older CHS-only boot sector unless you
+; have to boot from > 8 GB. The LBA-and-CHS FAT12 / FAT16 boot sector
+; needs applying SYS again after move / resize / ... a variant of that
+; boot sector without CHS support but with better move / resize / ...
+; support would be good for use on LBA harddisks.
+
+
+; Memory layout for the FreeDOS FAT32 single stage boot process:
+
+; ...
+; |-------| 1FE0:7E00
+; |BOOTSEC|
+; |RELOC. |
+; |-------| 1FE0:7C00
+; ...
+; |-------| 2000:0200
+; | FAT | (only 1 sector buffered)
+; |-------| 2000:0000
+; ...
+; |-------| 0000:7E00
+; |BOOTSEC| overwritten by the kernel, so the
+; |ORIGIN | bootsector relocates itself up...
+; |-------| 0000:7C00
+; ...
+; |-------|
+; |KERNEL | maximum size 134k (overwrites bootsec origin)
+; |LOADED | (holds 1 sector directory buffer before kernel load)
+; |-------| 0060:0000
+; ...
+*/
+
+#define BOOTGRUB /* undef this if compiled for loading FreeDOS */
+//#undef BOOTGRUB
+
+#ifdef BOOTGRUB
+#define LOADSEG 0x2000
+#define FATSEG 0x0060
+#else
+#define LOADSEG 0x0060
+#define FATSEG 0x2000
+#endif
+
+Entry_32:
+ jmp 1f
+
+ . = Entry_32 + 0x02
+
+ /* The default mode is CHS. This is for maximum compatiblity with
+ * small-sized disks, e.g., floppies.
+ *
+ * Valid values are 0x90 for CHS mode, or 0x0e for LBA mode.
+ *
+ * If the BIOS int13 supports LBA, this byte can be safely set to 0x0e.
+ *
+ * Some USB BIOSes might have bugs when using CHS mode, so the format
+ * program should set this byte to 0x0e. It seems that (generally) all
+ * USB BIOSes have LBA support.
+ *
+ * If the format program does not know whether the BIOS has LBA
+ * support, it may operate this way:
+ *
+ * if (partition_start + total_sectors_in_partition) exceeds the CHS
+ * addressing ability(especially when it is greater than 1024*256*63),
+ * the caller should set this byte to 0x0e, otherwise, set to 0x90.
+ */
+
+ .byte 0x90 /* for CHS. Another possible value is 0x0e for LBA */
+
+
+ . = Entry_32 + 0x03
+
+#ifdef BOOTGRUB
+ .ascii "GRLDR " /* OEM name string (of OS which formatted the disk). */
+#endif
+
+ . = Entry_32 + 0x0b
+
+ .word 0x200 /* bytes per sector. Must be 512 */
+
+ . = Entry_32 + 0x0d
+
+ /* Sectors per cluster. Valid values are 1, 2, 4, 8, 16, 32, 64 and 128.
+ * But a cluster size larger than 32K should not occur.
+ */
+
+ .byte 1 /* sectors per cluster */
+
+ . = Entry_32 + 0x0e
+
+ /* Reserved sectors(number of sectors before the first FAT,
+ * including the boot sector), usually 1.
+ */
+
+ .word 1 /* reserved sectors */
+
+ . = Entry_32 + 0x10
+
+ /* Number of FATs(nearly always 2). */
+
+ .byte 2 /* number of FATs */
+
+ . = Entry_32 + 0x11
+
+ /* (Maximum number of root directory entries)Must be 0. */
+
+ .word 0 /* Max dir entries for FAT12/FAT16 */
+
+ . = Entry_32 + 0x13
+
+ /* (Total number of sectors for small disks only)Must be 0. */
+
+ .word 0 /* total sectors for FAT12/FAT16 */
+
+ . = Entry_32 + 0x15
+
+ /* Media descriptor byte, pretty meaningless now. */
+
+ .byte 0xf8 /* media descriptor */
+
+ . = Entry_32 + 0x16
+
+ /* (Sectors per FAT)Must be 0. */
+
+ .word 0 /* sectors per FAT for FAT12/FAT16 */
+
+ . = Entry_32 + 0x18
+
+ .word 18 /* sectors per track */
+
+ . = Entry_32 + 0x1a
+
+ .word 2 /* number of heads */
+
+ . = Entry_32 + 0x1c
+
+ /* Number of hidden sectors (those preceding the boot sector).
+ * Also referred to as the starting sector of the partition.
+ * For floppies, it should be 0.
+ */
+
+ .long 0 /* hidden sectors */
+
+ . = Entry_32 + 0x20
+
+ /* Total number of sectors in the filesystem. */
+
+ .long 0 /* total sectors for FAT32 */
+
+ . = Entry_32 + 0x24
+
+ /* FAT32 sectors per FAT. */
+
+ .long 0
+
+ . = Entry_32 + 0x28
+
+ /* If bit 7 is clear then all FATs are updated, otherwise bits 0-3
+ * give the current active FAT, all other bits are reserved.
+ * This word is not used by grldr boot code.
+ */
+
+ .word 0
+
+ . = Entry_32 + 0x2a
+
+ /* High byte is major revision number, low byte is minor revision
+ * number, currently both are 0.
+ * This word is not used by grldr boot code.
+ */
+
+ .word 0
+
+ . = Entry_32 + 0x2c
+
+ /* Root directory starting cluster. */
+
+ .long 0
+
+ . = Entry_32 + 0x30
+
+ /* File system information sector number.
+ * This word is not used by grldr boot code.
+ */
+
+ .word 0
+
+ . = Entry_32 + 0x32
+
+ /* If non-zero this gives the sector which holds a copy of the
+ * boot record, usually 6.
+ * This word is not used by grldr boot code.
+ */
+
+ .word 6
+
+ . = Entry_32 + 0x34
+
+ /* Reserved, 12 bytes, set to 0. */
+
+ .long 0
+ .long 0
+ .long 0
+
+ . = Entry_32 + 0x40
+
+ /* drive number of the boot device.
+ * This byte is ignored for read. The program will write DL onto
+ * this byte. The caller should set drive number in DL.
+ * We assume all BIOSes pass correct drive number in DL.
+ * That is to say, buggy BIOSes are not supported!!
+ */
+
+ .byte 0
+
+ . = Entry_32 + 0x41
+
+ /* partition number of this filesystem in the boot drive.
+ * This byte is ignored for read. The boot code will write partition
+ * number onto this byte. See Entry + 0x5d below.
+ */
+
+ .byte 0
+
+ . = Entry_32 + 0x42
+
+ /* Signature (must be 28h or 29h to be recognised by NT). */
+
+ .byte 0x29 /* extended boot signature for FAT12/FAT16 */
+
+ . = Entry_32 + 0x43
+
+ .long 0x0AC4AF63 /* volume serial number */
+
+ . = Entry_32 + 0x47
+
+ .ascii "NO NAME " /* volume label, 11 bytes. */
+
+ . = Entry_32 + 0x52
+
+ .ascii "FAT32 " /* filesystem ID, 8 bytes. */
+
+/*
+; bp is initialized to 7c00h
+; %define bsOemName bp+0x03 ; OEM label (8)
+%define bsBytesPerSec bp+0x0b ; bytes/sector (dw)
+%define bsSecPerClust bp+0x0d ; sectors/allocation unit (db)
+%define bsResSectors bp+0x0e ; # reserved sectors (dw)
+%define bsFATs bp+0x10 ; # of fats (db)
+; %define bsRootDirEnts bp+0x11 ; # of root dir entries (dw, 0 for FAT32)
+ ; (FAT32 has root dir in a cluster chain)
+; %define bsSectors bp+0x13 ; # sectors total in image (dw, 0 for FAT32)
+ ; (if 0 use nSectorHuge even if FAT16)
+; %define bsMedia bp+0x15 ; media descriptor: fd=2side9sec, etc... (db)
+; %define sectPerFat bp+0x16 ; # sectors in a fat (dw, 0 for FAT32)
+ ; (FAT32 always uses xsectPerFat)
+%define sectPerTrack bp+0x18 ; # sectors/track
+; %define nHeads bp+0x1a ; # heads (dw)
+%define nHidden bp+0x1c ; # hidden sectors (dd)
+; %define nSectorHuge bp+0x20 ; # sectors if > 65536 (dd)
+%define xsectPerFat bp+0x24 ; Sectors/Fat (dd)
+ ; +0x28 dw flags (for fat mirroring)
+ ; +0x2a dw filesystem version (usually 0)
+%define xrootClst bp+0x2c ; Starting cluster of root directory (dd)
+ ; +0x30 dw -1 or sector number of fs.-info sector
+ ; +0x32 dw -1 or sector number of boot sector backup
+ ; (+0x34 .. +0x3f reserved)
+%define drive bp+0x40 ; Drive number
+ bp+0x41 ; partition number for GRLDR
+
+%define fat_sector bp+0x44 ; last accessed FAT sector (dd)
+ ; (overwriting unused bytes)
+%define fat_start bp+0x48 ; first FAT sector (dd)
+ ; (overwriting unused bytes)
+%define data_start bp+0x4c ; first data sector (dd)
+ ; (overwriting unused bytes)
+
+*/
+ /* not used: [0x42] = byte 0x29 (ext boot param flag)
+ * [0x43] = dword serial
+ * [0x47] = label (padded with 00, 11 bytes)
+ * [0x52] = "FAT32",32,32,32 (not used by Windows)
+ * ([0x5a] is where FreeDOS parts start)
+ */
+
+ . = Entry_32 + 0x5a
+1:
+ cli
+ cld
+
+#ifdef BOOTGRUB
+
+ . = Entry_32 + 0x5c
+
+ /* the byte at offset 0x5d stores the real partition number for read.
+ * the format program or the caller should set it to a correct value.
+ * For floppies, it should be 0xff, which stands for whole drive.
+ */
+
+ movb $0xff, %dh /* boot partition number */
+
+ cmpb $0xff, %dh /* is floppy? */
+ jne 1f
+ movb $0, %dl /* yes, let drive number = 0 */
+1:
+#endif
+
+ xorw %ax, %ax
+ movw %ax, %ds
+ movw $0x7c00, %bp
+
+#ifdef BOOTGRUB
+ movw %ax, %es
+#else
+ movw $0x1fe0, %ax
+ movw %ax, %es
+ movw %bp, %si /* move from 0000:7c00 */
+ movw %bp, %di /* move to 1fe0:7c00 */
+ movw $0x0100, %cx /* one sector to move */
+ repz movsw
+ ljmp $0x1fe0, $(1f - Entry_32 + 0x7c00)
+1:
+ movw %ax, %ds
+#endif
+ movw %ax, %ss /* stack and BP-relative moves up, too */
+ leaw -0x20(%bp), %sp
+ sti
+ movw %dx, 0x40(%bp) /* BIOS passes drive number in DL */
+
+ movb $0x41, %ah
+ movw $0x55AA, %bx
+ int $0x13
+ jc 1f /* No EBIOS */
+ cmpw $0xAA55, %bx
+ jne 1f /* No EBIOS */
+ testb $1, %cl
+ jz 1f /* No EBIOS */
+ /* EBIOS supported */
+ movb $0x42, (ebios_32 - 1 - Entry_32 + 0x7c00)
+1:
+
+/* figure out where FAT and DATA area starts
+ * (modifies EAX EDX, sets fat_start and data_start variables)
+ */
+ xorl %eax, %eax
+ movl %eax, 0x44(%bp) /* init buffer status */
+
+ /* first, find fat_start */
+ movw 0x0e(%bp), %ax /* reserved sectors */
+ addl 0x1c(%bp), %eax /* hidden sectors */
+ movl %eax, 0x48(%bp) /* first FAT sector */
+ movl %eax, 0x4c(%bp) /* first data sector, initial value */
+
+ /* next, find data_start */
+ movl 0x10(%bp), %eax /* number of fats, no movzbl needed: the
+ 2 words after 0x10(%bp) are 0 for fat32 */
+ mull 0x24(%bp) /* sectors per fat (EDX=0) */
+ addl %eax, 0x4c(%bp) /* first DATA sector */
+
+/* Searches for the file in the root directory.
+ * Returns: EAX = first cluster of file
+ */
+
+ movl 0x2c(%bp), %eax /* root dir cluster */
+
+1:
+ pushl %eax /* save cluster */
+ call cluster_to_lba_32
+ /* EDX is sectors per cluster, EAX is sector number */
+ movw $(msg_BootError_32 - Entry_32 + 0x7c00), %si
+ jc boot_error_32 /* EOC encountered */
+
+2:
+ lesw (loadseg_off_32 - Entry_32)(%bp), %bx /* load to loadseg:0 */
+ call readDisk_32
+
+ xorw %di, %di
+
+ /* Search for kernel file name, and find start cluster */
+3:
+ movw $11, %cx
+ movw $(filename_32 - Entry_32 + 0x7c00), %si
+ repz cmpsb
+ jz 1f /* note that di now is at dirent+11 */
+
+ addw $0x20, %di
+ andw $-0x20, %di /* 0xffe0 */
+ cmp 0x0b(%bp), %di /* bytes per sector */
+ jnz 3b /* next directory entry */
+
+ decw %dx /* initially DX holds sectors per cluster */
+ jnz 2b /* loop over sectors in cluster */
+
+ popl %eax /* restore current cluster */
+ call next_cluster_32
+ jmp 1b /* read next cluster */
+
+#ifndef ALTERNATIVE_KERNEL
+loadseg_off_32:
+ .word 0
+ .word LOADSEG
+#endif
+
+1:
+ /* kernel directory entry is found */
+ pushw %es:(0x14-11)(%di) /* get cluster number HI */
+ pushw %es:(0x1a-11)(%di) /* get cluster number LO */
+ popl %eax /* convert to 32bit */
+
+ xorw %bx, %bx /* read kernel at ES:BX=LOADSEG:0 */
+
+/* read kernel */
+
+2:
+ pushl %eax
+ call cluster_to_lba_32
+ /* EDX is sectors per cluster, EAX is sector number */
+ jnc 1f
+
+ /* EOC encountered - done */
+#ifdef BOOTGRUB
+ movw 0x40(%bp), %dx /* boot_drive and boot_partition */
+#else
+ movb 0x40(%bp), %bl /* FreeDOS kernel uses BL, not DL, for drive */
+#endif
+ ljmp *(loadseg_off_32 - Entry_32)(%bp)
+
+1:
+ call readDisk_32
+ decw %dx /* initially DX holds sectors per cluster */
+ jnz 1b /* loop over sectors in cluster */
+
+ popl %eax
+ call next_cluster_32
+ jmp 2b
+
+/* given a cluster number, find the number of the next cluster in
+ * the FAT chain. Needs fat_start.
+ * input: EAX - cluster
+ * EDX = 0
+ * output: EAX - next cluster
+ * EDX = undefined
+ */
+
+next_cluster_32:
+ pushw %es
+ /* pushw %di */
+ pushw %bx /* hi word of EBX never used */
+
+#if 1
+ /* xorl %edx, %edx */
+ shll $2, %eax /* 32bit FAT */
+ movzwl 0x0b(%bp), %ebx /* bytes per sector */
+ divl %ebx /* residue is in EDX */
+ /* movw %dx, %di */
+#else
+ shll $2, %eax /* 32bit FAT */
+ ;xchgw %ax, %di /* movw %ax, %di */
+ movw %ax, %di
+ ;shlw $2, %di /* 32bit FAT */
+
+ pushw %cx
+ movw 0x0b(%bp), %bx /* bytes per sector */
+ bsfw %bx, %cx
+ ;decw %cx
+ ;decw %cx
+ decw %bx
+ andw %bx, %di /* mask to sector size */
+ shrl %cl, %eax
+ popw %cx
+#endif
+ addl 0x48(%bp), %eax /* add the first FAT sector number.
+ EAX is absolute sector number now */
+ movw $FATSEG, %bx
+ movw %bx, %es
+ xorw %bx, %bx
+
+ cmpl 0x44(%bp), %eax /* is it the last accessed and already buffered
+ FAT sector? */
+ jz 1f
+ movl %eax, 0x44(%bp) /* mark sector EAX as buffered */
+ call readDisk_32 /* read sector EAX to buffer */
+1:
+#if 1
+ //.byte 0x67, 0x26, 0x80, 0x62, 0x03, 0x0f
+ addr32 andb $0x0f, %es:3(%edx) /* mask out top 4 bits */
+
+ //.byte 0x67, 0x66, 0x26, 0x8b, 0x02
+ addr32 movl %es:(%edx), %eax /* read next cluster number */
+#else
+ andb $0x0f, %es:3(%di) /* mask out top 4 bits */
+ movl %es:(%di), %eax /* read next cluster number */
+#endif
+ popw %bx
+ /* popw %di */
+ popw %es
+ ret
+
+/* Convert cluster number to the absolute sector number
+ * ... or return carry if EndOfChain! Needs data_start.
+ * input: EAX - target cluster
+ * output: EAX - absolute sector
+ * EDX - [bsSectPerClust] (byte)
+ * carry clear
+ * (if carry set, EAX/EDX unchanged, end of chain)
+ */
+
+cluster_to_lba_32:
+ cmpl $0x0ffffff8, %eax /* check End Of Chain */
+ cmc
+ jb 1f /* carry is stored if EOC */
+
+ /* sector = (cluster-2) * clustersize + data_start */
+ decl %eax
+ decl %eax
+
+ movzbl 0x0d(%bp), %edx /* sectors per cluster */
+ pushw %dx /* only DX would change */
+ mull %edx /* EDX = 0 */
+ popw %dx
+ addl 0x4c(%bp), %eax /* data_start */
+ /* here, carry is cleared (unless parameters are wrong) */
+1:
+ ret
+
+/* Read a sector from disk, using LBA or CHS
+ * input: EAX - 32-bit DOS sector number
+ * ES:BX - destination buffer
+ * (will be filled with 1 sector of data)
+ * output: ES:BX points one byte after the last byte read.
+ * EAX - next sector
+ */
+
+readDisk_32:
+ pushal
+ xorl %edx, %edx /* EDX:EAX = LBA */
+ pushl %edx /* hi 32bit of sector number */
+ pushl %eax /* lo 32bit of sector number */
+ pushw %es /* buffer segment */
+ pushw %bx /* buffer offset */
+ pushw $1 /* 1 sector to read */
+ pushw $16 /* size of this parameter block */
+
+ xorl %ecx, %ecx
+ pushl 0x18(%bp) /* lo:sectors per track, hi:number of heads */
+ popw %cx /* ECX = sectors per track */
+ divl %ecx /* residue is in EDX */
+ /* quotient is in EAX */
+ incw %dx /* sector number in DL */
+ popw %cx /* ECX = number of heads */
+ pushw %dx /* push sector number into stack */
+ xorw %dx, %dx /* EDX:EAX = cylinder * TotalHeads + head */
+ divl %ecx /* residue is in EDX, head number */
+ /* quotient is in EAX, cylinder number */
+ xchgb %dl, %dh /* head number should be in DH */
+ /* DL = 0 */
+ popw %cx /* pop sector number from stack */
+ xchgb %al, %ch /* lo 8bit cylinder should be in CH */
+ /* AL = 0 */
+ shlb $6, %ah /* hi 2bit cylinder ... */
+ orb %ah, %cl /* ... should be in CL */
+
+ movw $0x201, %ax /* read 1 sector */
+ebios_32: /* ebios_32 - 1 points to 0x02 that can be changed to 0x42 */
+
+// cmpb $0x0e, 2(%bp) /* force LBA? */
+// jnz 1f /* no, continue */
+// movb $0x42, %ah /* yes, use extended disk read */
+//1:
+ movw %sp, %si /* DS:SI points to disk address packet */
+ movb 0x40(%bp), %dl /* hard disk drive number */
+ int $0x13
+ popaw /* remove parameter block from stack */
+ popal
+ jc disk_error_32 /* disk read error, jc 1f if caller handles */
+ incl %eax /* next sector */
+ addw 0x0b(%bp), %bx /* bytes per sector */
+ jnc 1f /* 64K bound check */
+ pushw %dx
+ movw %es, %dx
+ addb $0x10, %dh /* add 1000h to ES */
+ /* here, carry is cleared */
+ movw %dx, %es
+ popw %dx
+1:
+ /* carry stored on disk read error */
+ ret
+
+ . = . - (. - readDisk_32)/91
+
+msg_DiskReadError_32:
+
+ .ascii "disk error\0"
+
+msg_BootError_32:
+
+ .ascii "No "
+
+filename_32:
+
+#ifdef BOOTGRUB2
+ .ascii "G2LDR \0"
+#elif defined (BOOTGRUB)
+ .ascii "GRLDR \0"
+#else
+ .ascii "KERNEL SYS\0"
+#endif
+
+#ifdef ALTERNATIVE_KERNEL
+filename_end_32:
+
+ . = Entry_32 + 0x1e8
+
+loadseg_off_32:
+ .word 0
+ .word LOADSEG
+
+ . = Entry_32 + 0x1ec
+
+boot_image_ofs_32:
+
+ .word (filename_32 - Entry_32)+(filename_end_32 - filename_32 - 1)*2048
+#endif
+
+ . = Entry_32 + 0x1ee
+
+disk_error_32:
+
+ movw $(msg_DiskReadError_32 - Entry_32 + 0x7c00), %si
+
+boot_error_32:
+
+/* prints string DS:SI (modifies AX BX SI) */
+
+//print_32:
+1:
+ lodsb (%si), %al /* get token */
+ //xorw %bx, %bx /* video page 0 */
+ movb $0x0e, %ah /* print it */
+ int $0x10 /* via TTY mode */
+ cmpb $0, %al /* end of string? */
+ jne 1b /* until done */
+
+ /* The caller will change this to
+ * ljmp $0x9400, $(try_next_partition - _start1)
+ */
+
+1: jmp 1b
+
+ . = Entry_32 + 0x1fc
+
+ .word 0, 0xAA55 /* Win9x uses all 4 bytes as magic value here */
+
+ . = Entry_32 + 0x200
+
+ . = _start1 + 0x600
+
+ //.arch i8086, nojumps
+ .arch i186, nojumps
+/*
+ * The following is based on FreeDOS, modified heavily by Tinybit in Feb, 2004
+ *
+ * Merges FAT12 and FAT16 boot sectors to ONE FAT boot sector!
+ *
+ * Memory layout for GRLDR FAT single stage boot process:
+ *
+ * +--------+
+ * | |
+ * |GRLDR | also used as max 128k FAT buffer
+ * |LOADED | before GRLDR loading starts
+ * |--------| 2000:0000
+ * | |
+ * |--------| 0000:7E00
+ * |BOOTSECT|
+ * |ORIGIN |
+ * |--------| 0000:7C00
+ * | |
+ * |--------| 0000:3000
+ * |CLUSTER |
+ * |LIST |
+ * |--------| 0000:2000
+ * | |
+ * +--------+
+ */
+
+/*
+;
+; File:
+; boot.asm
+; Description:
+; DOS-C boot
+;
+; Copyright (c) 1997;
+; Svante Frey
+; All Rights Reserved
+;
+; This file is part of DOS-C.
+;
+; DOS-C is free software; you can redistribute it and/or
+; modify it under the terms of the GNU General Public License
+; as published by the Free Software Foundation; either version
+; 2, or (at your option) any later version.
+;
+; DOS-C 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 DOS-C; see the file COPYING. If not,
+; write to the Free Software Foundation, 675 Mass Ave,
+; Cambridge, MA 02139, USA.
+;
+;
+; +--------+ 1FE0:7E00
+; |BOOT SEC|
+; |RELOCATE|
+; |--------| 1FE0:7C00
+; | |
+; |--------| 1FE0:3000
+; | CLUSTER|
+; | LIST |
+; |--------| 1FE0:2000
+; | |
+; |--------| 0000:7E00
+; |BOOT SEC| overwritten by max 128k FAT buffer
+; |ORIGIN | and later by max 134k loaded kernel
+; |--------| 0000:7C00
+; | |
+; |--------|
+; |KERNEL | also used as max 128k FAT buffer
+; |LOADED | before kernel loading starts
+; |--------| 0060:0000
+; | |
+; +--------+
+*/
+
+#ifdef BOOTGRUB
+#define LOADSEG_12_16 0x2000
+#define FATBUF 0x2000 /* offset of temp buffer for FAT chain */
+#else
+#define LOADSEG_12_16 0x0060
+#define FATBUF 0x2000 /* offset of temp buffer for FAT chain */
+#endif
+
+Entry_12_16:
+ jmp 1f
+
+ . = Entry_12_16 + 0x02
+
+ /* The default mode is CHS. This is for maximum compatiblity with
+ * small-sized disks, e.g., floppies.
+ *
+ * Valid values are 0x90 for CHS mode, or 0x0e for LBA mode.
+ *
+ * If the BIOS int13 supports LBA, this byte can be safely set to 0x0e.
+ *
+ * Some USB BIOSes might have bugs when using CHS mode, so the format
+ * program should set this byte to 0x0e. It seems that (generally) all
+ * USB BIOSes have LBA support.
+ *
+ * If the format program does not know whether the BIOS has LBA
+ * support, it may operate this way:
+ *
+ * if (partition_start + total_sectors_in_partition) exceeds the CHS
+ * addressing ability(especially when it is greater than 1024*256*63),
+ * the caller should set this byte to 0x0e, otherwise, set to 0x90.
+ */
+
+ .byte 0x90 /* for CHS. Another possible value is 0x0e for LBA */
+
+
+ . = Entry_12_16 + 0x03
+
+#ifdef BOOTGRUB
+ .ascii "GRLDR "
+#endif
+
+ . = Entry_12_16 + 0x0b
+
+ .word 0x200 /* bytes per sector */
+
+ . = Entry_12_16 + 0x0d
+
+ .byte 1 /* sectors per cluster */
+
+ . = Entry_12_16 + 0x0e
+
+ .word 1 /* reserved sectors */
+
+ . = Entry_12_16 + 0x10
+
+ .byte 2 /* number of FATs */
+
+ . = Entry_12_16 + 0x11
+
+ .word 224 /* Max dir entries */
+
+ . = Entry_12_16 + 0x13
+
+ .word 2880 /* total sectors in the filesystem */
+
+ . = Entry_12_16 + 0x15
+
+ .byte 0xf0 /* media descriptor */
+
+ . = Entry_12_16 + 0x16
+
+ .word 9 /* sectors per FAT */
+
+ . = Entry_12_16 + 0x18
+
+ .word 18 /* sectors per track */
+
+ . = Entry_12_16 + 0x1a
+
+ .word 2 /* number of heads */
+
+ . = Entry_12_16 + 0x1c
+
+ .long 0 /* hidden sectors */
+
+ . = Entry_12_16 + 0x20
+
+ .long 0 /* total sectors for large partitions */
+
+ . = Entry_12_16 + 0x24
+
+ /* drive number of the boot device.
+ * This byte is ignored for read. The program will write DL onto
+ * this byte. The caller should set drive number in DL.
+ * We assume all BIOSes pass correct drive number in DL.
+ * That is to say, buggy BIOSes are not supported!!
+ */
+
+ .byte 0
+
+ . = Entry_12_16 + 0x25
+
+ /* partition number of this filesystem in the boot drive.
+ * This byte is ignored for read. The boot code will write partition
+ * number onto this byte. See Entry_12_16 + 0x41 below.
+ */
+
+ .byte 0
+
+ . = Entry_12_16 + 0x26
+
+ .byte 0x29 /* extended boot signature */
+
+ . = Entry_12_16 + 0x27
+
+ .long 0x0AC4AF63 /* volume serial number */
+
+ . = Entry_12_16 + 0x2b
+
+ .ascii "NO NAME " /* volume label */
+
+ . = Entry_12_16 + 0x36
+
+ .ascii "FAT12 " /* filesystem ID */
+
+/*
+; bp is initialized to 7c00h
+%define bsOemName bp+0x03 ; OEM label
+%define bsBytesPerSec bp+0x0b ; bytes/sector
+%define bsSecPerClust bp+0x0d ; sectors/allocation unit
+%define bsResSectors bp+0x0e ; # reserved sectors
+%define bsFATs bp+0x10 ; # of fats
+%define bsRootDirEnts bp+0x11 ; # of root dir entries
+%define bsSectors bp+0x13 ; # sectors total in image
+%define bsMedia bp+0x15 ; media descrip: fd=2side9sec, etc...
+%define sectPerFat bp+0x16 ; # sectors in a fat
+%define sectPerTrack bp+0x18 ; # sectors/track
+%define nHeads bp+0x1a ; # heads
+%define nHidden bp+0x1c ; # hidden sectors
+%define nSectorHuge bp+0x20 ; # sectors if > 65536
+%define drive bp+0x24 ; drive number
+ bp+0x25 ; partition number for GRLDR
+%define extBoot bp+0x26 ; extended boot signature
+%define volid bp+0x27
+%define vollabel bp+0x2b
+%define filesys bp+0x36
+
+%define RootDirSecs bp+0x26 ; # of sectors root dir uses
+ ; (overwriting unused bytes)
+%define fat_start bp+0x28 ; first FAT sector
+ ; (overwriting unused bytes)
+%define root_dir_start bp+0x2c ; first root directory sector
+ ; (overwriting unused bytes)
+%define data_start bp+0x30 ; first data sector
+ ; (overwriting unused bytes)
+%define data_clusters bp+0x34 ; # of clusters in data area
+ ; (overwriting unused bytes)
+ bp+0x36 ; bytes per FAT( > 0x1800 means FAT16)
+ ; (overwriting unused bytes)
+*/
+ /* not used: [0x26] = byte 0x29 (ext boot param flag)
+ * [0x27] = dword serial
+ * [0x2b] = label (padded with 00, 11 bytes)
+ * [0x36] = "FAT12" or "FAT16",32,32,32 (not used by Windows)
+ * ([0x3e] is where FreeDOS parts start)
+ */
+
+ . = Entry_12_16 + 0x3e
+1:
+ cli
+ cld
+
+#ifdef BOOTGRUB
+
+ . = Entry_12_16 + 0x40
+
+ /* the byte at offset 0x41 stores the real partition number for read.
+ * the format program or the caller should set it to a correct value.
+ * For floppies, it should be 0xff, which stands for whole drive.
+ */
+
+ movb $0xff, %dh /* boot partition number */
+
+ cmpb $0xff, %dh /* is floppy? */
+ jne 1f
+ movb $0, %dl /* yes, let drive number = 0 */
+1:
+#endif
+
+ xorw %ax, %ax
+ movw %ax, %ds
+ movw $0x7c00, %bp
+
+#ifdef BOOTGRUB
+ movw %ax, %es
+ movw %ax, %ss /* stack and BP-relative moves up, too */
+ leaw -0x20(%bp), %sp
+ sti
+ movw %dx, 0x24(%bp) /* BIOS passes drive number in DL */
+ /* AX=0 */
+// xchgw %ax, %dx /* let DX = 0 */
+// xorw %cx, %cx /* CX = 0 */
+#else
+ movw %bp, %si /* move from 0000:7c00 */
+ movw %bp, %di /* move to 1fe0:7c00 */
+ movb %dl, 0x24(%si) /* BIOS passes drive number in DL */
+// xchgw %ax, %dx /* let DX = 0 */
+ movw $0x1fe0, %ax
+ movw %ax, %es
+ movw $0x0100, %cx /* one sector to move */
+ repz movsw
+ /* CX = 0 */
+ ljmp $0x1fe0, $(1f - Entry_12_16 + 0x7c00)
+1:
+ movw %ax, %ds
+ movw %ax, %ss /* stack and BP-relative moves up, too */
+ leaw -0x20(%bp), %sp
+ sti
+ /* AX=0x1fe0 */
+#endif
+
+ movb $0x41, %ah
+ movw $0x55AA, %bx
+ int $0x13
+ jc 1f /* No EBIOS */
+ cmpw $0xAA55, %bx
+ jne 1f /* No EBIOS */
+ testb $1, %cl
+ jz 1f /* No EBIOS */
+ /* EBIOS supported */
+ movb $0x42, (ebios_12_16 - 1 - Entry_12_16 + 0x7c00)
+1:
+// xorw %cx, %cx
+ xorw %ax, %ax
+
+ /* GET DRIVE PARMS: Calculate start of some disk areas */
+
+ movw 0x1c(%bp), %si /* number of hidden sectors(lo) */
+ movw 0x1e(%bp), %di /* number of hidden sectors(hi) */
+ addw 0x0e(%bp), %si /* number of reserved sectors */
+ adcw %ax, %di /* DI:SI = first FAT sector */
+ /* AX = 0 */
+
+ movw %si, 0x28(%bp) /* FAT start sector(lo) */
+ movw %di, 0x2a(%bp) /* FAT start sector(hi) */
+
+ //xchgw %ax, %dx /* let AX = 0 */
+ movb 0x10(%bp), %al /* number of FATs */
+ /* cbw */
+ mulw 0x16(%bp) /* sectors per FAT */
+ /* DX:AX = total number of FAT sectors */
+ /* DX = 0 since no too many FAT sectors */
+ addw %ax, %si
+ adcw %dx, %di /* DI:SI = root directory start sector */
+ movw %si, 0x2c(%bp) /* root directory starting sector(lo) */
+ movw %di, 0x2e(%bp) /* root directory starting sector(hi) */
+
+ /* Calculate how many sectors the root directory occupies */
+
+ movw 0x0b(%bp), %bx /* bytes per sector */
+ movb $5, %cl /* divide BX by 32 */
+ shrw %cl, %bx /* BX = directory entries per sector */
+
+ movw 0x11(%bp), %ax /* max number of root dir entries */
+ /* xorw %dx, %dx */ /* assuming DX = 0 */
+ divw %bx /* AX = sectors per root directory */
+ /* DX = 0 since normally no residue */
+
+ movw %ax, 0x26(%bp) /* number of sectors the root dir occupies */
+
+ addw %ax, %si /* DI:SI = first data sector */
+ adcw %dx, %di /* assuming DX = 0 */
+
+ movw %si, 0x30(%bp) /* data starting sector(lo) */
+ movw %di, 0x32(%bp) /* data starting sector(hi) */
+#ifdef USE_TOTAL_CLUSTERS
+ movw 0x13(%bp), %cx /* total sectors(small) */
+ jcxz 1f
+ movw %cx, 0x20(%bp) /* total sectors(large)(lo) */
+ movw %dx, 0x22(%bp) /* total sectors(large)(hi), assuming DX = 0 */
+1:
+ movw 0x20(%bp), %ax /* total sectors(large) */
+ movw 0x22(%bp), %bx
+ addw 0x1c(%bp), %ax /* number of hidden sectors */
+ adcw 0x1e(%bp), %bx
+ subw %si, %ax /* data starting sector */
+ sbbw %di, %bx /* BX:AX = total sectors in the data area */
+ movb 0x0d(%bp), %dl /* sectors per cluster(DH=0) */
+ xchgw %bx, %dx /* DX:AX = total sectors in the data area */
+ /* BX = sectors per cluster */
+ divw %bx /* AX = total clusters in the data area */
+ movw %ax, 0x34(%bp) /* total clusters in the data area */
+#else
+ movw $0xffff, 0x36(%bp)
+ movw 0x16(%bp), %ax /* sectors per FAT */
+ mulw 0x0b(%bp) /* bytes per sector */
+ jc 1f
+ movw %ax, 0x36(%bp)
+1:
+#endif
+ /* Searches for the file in the root directory
+ *
+ * Returns:
+ * AX = first cluster of file
+ */
+
+ /* First, read the whole root directory into the temporary buffer */
+
+ movw 0x2c(%bp), %ax /* root directory starting sector(lo) */
+ movw 0x2e(%bp), %dx /* root directory starting sector(hi) */
+ movw 0x26(%bp), %di /* number of sectors the root dir occupies */
+ lesw (loadseg_off_12_16 - Entry_12_16)(%bp), %bx
+ /* ES:BX = loadseg:0 */
+ call readDisk_12_16
+
+ lesw (loadseg_off_12_16 - Entry_12_16)(%bp), %di
+ /* ES:DI = loadseg:0 */
+
+
+ /* Search for kernel file name, and find start cluster */
+
+1:
+ movw $11, %cx
+ movw $(filename_12_16 - Entry_12_16 + 0x7c00), %si
+ pushw %di
+ repz cmpsb
+ popw %di
+ movw %es:0x1a(%di), %ax /* get cluster number from dir entry */
+ jz 1f
+
+ addw $0x20, %di /* go to next directory entry */
+ cmpb %ch, %es:(%di) /* if the first byte of the name is 0, */
+ /* there is no more files in the directory */
+ /* assuming CH = 0 */
+ jnz 1b
+ movw $(msg_BootError_12_16 - Entry_12_16 + 0x7c00), %si
+ jmp boot_error_12_16 /* fail if not found */
+
+#ifndef ALTERNATIVE_KERNEL
+loadseg_off_12_16: .word 0
+loadseg_seg_12_16: .word LOADSEG_12_16
+#endif
+
+1:
+ pushw %ax /* store first cluster number */
+ /* CX = 0 */
+
+
+ /* Reads the FAT chain and stores it in a temporary buffer in the first
+ * 64KB. The FAT chain is stored an array of 16-bit cluster numbers,
+ * ending with 0.
+ *
+ * The file must fit in conventional memory, so it can't be larger than
+ * 640KB. The sector size must be at least 512 bytes, so the FAT chain
+ * can't be larger than around 3KB.
+ *
+ * Call with: AX = first cluster in chain
+ */
+
+ /* Load the complete FAT into memory. The FAT can't be larger
+ * than 128 kb, so it should fit in the temporary buffer.
+ */
+
+ lesw (loadseg_off_12_16 - Entry_12_16)(%bp), %bx
+ /* ES:BX = loadseg:0 */
+ movw 0x16(%bp), %di /* sectors per FAT */
+ movw 0x28(%bp), %ax /* FAT start sector(lo) */
+ movw 0x2a(%bp), %dx /* FAT start sector(hi) */
+ call readDisk_12_16
+ popw %ax /* restore first cluster number */
+
+ /* Set ES:DI to the temporary storage for the FAT chain */
+ pushw %ds
+ popw %es
+ movw (loadseg_seg_12_16 - Entry_12_16)(%bp), %ds
+ movw $FATBUF, %di
+
+2:
+ stosw /* store cluster number */
+ movw %ax, %si /* SI = cluster number */
+ addw %si, %si /* multiply cluster number by two */
+ movw (loadseg_seg_12_16 - Entry_12_16)(%bp), %dx
+ /* segment for FAT16 */
+ jnc 1f
+ addb $0x10, %dh /* overflow. Add 0x1000 to segment value */
+1:
+
+#ifdef USE_TOTAL_CLUSTERS
+ cmpw $0x0ff7, 0x34(%bp) /* total clusters in the data area */
+#else
+ cmpw $0x1801, 0x36(%bp) /* bytes per FAT */
+#endif
+ jnb 3f
+
+ /* This is a FAT12 disk */
+
+ addw %ax, %si /* multiply cluster number by 3 ... */
+ shrw $1, %si /* ... and divide by 2 */
+ lodsw
+
+ /* If the cluster number was even, the cluster value is now in
+ * bits 0-11 of AX. If the cluster number was odd, the cluster
+ * value is in bits 4-15, and must be shifted right 4 bits. If
+ * the number was odd, CF was set in the last shift instruction.
+ */
+
+ jnc 1f
+ movb $4, %cl
+ shrw %cl, %ax
+1:
+ andb $0x0f, %ah /* mask off the highest 4 bits */
+ cmpw $0x0ff7, %ax /* check for EOF */
+ jmp 4f
+
+3:
+ /* This is a FAT16 disk. The maximal size of a 16bit FAT
+ * is 128KB, so it may not fit within a single 64KB segment
+ */
+
+ movw %dx, %ds /* DS:SI points to next cluster */
+ lodsw /* AX = next cluster */
+
+ cmpw $0xfff7, %ax /* check for EOF */
+4:
+ jbe 2b /* continue if not EOF */
+
+ /* Mark end of FAT chain with 0, so we have a single
+ * EOF marker for both FAT12 and FAT16 systems.
+ */
+
+ xorw %ax, %ax
+ stosw
+
+ pushw %cs
+ popw %ds
+
+ /* Loads the file into memory, one cluster at a time */
+
+ lesw (loadseg_off_12_16 - Entry_12_16)(%bp), %bx
+ /* ES:BX = loadseg:0 */
+ movw $FATBUF, %si /* set DS:SI to the FAT chain */
+
+2:
+ lodsw /* AX = next cluster to read */
+ orw %ax, %ax
+ jnz 1f
+
+ /* EOC encountered - done */
+#ifdef BOOTGRUB
+ movw 0x24(%bp), %dx /* boot_drive and boot_partition */
+#else
+ movb 0x24(%bp), %bl /* FreeDOS kernel uses BL, not DL, for drive */
+#endif
+ ljmp *(loadseg_off_12_16 - Entry_12_16)(%bp) /* boot it! */
+
+1:
+ decw %ax /* cluster numbers start with 2 */
+ decw %ax
+
+ movw 0x0d(%bp), %di /* sectors per cluster */
+ andw $0xff, %di /* DI = sectors per cluster */
+ mulw %di
+ addw 0x30(%bp), %ax /* data starting sector(lo) */
+ adcw 0x32(%bp), %dx /* data starting sector(hi) */
+ /* DX:AX = first sector to read */
+ call readDisk_12_16
+ jmp 2b /* read next cluster */
+
+/* Reads a number of sectors into memory.
+ *
+ * Call with: DX:AX = 32-bit DOS sector number
+ * DI = number of sectors to read
+ * ES:BX = destination buffer
+ *
+ * Returns: CF set on error
+ * ES:BX points one byte after the last byte read.
+ * DX:AX = next sector number after read
+ */
+
+readDisk_12_16:
+2:
+ pushaw
+ xorw %cx, %cx
+ pushw %cx
+ pushw %cx
+ pushw %dx
+ pushw %ax
+ pushw %es /* buffer segment */
+ pushw %bx /* buffer offset */
+ incw %cx
+ pushw %cx /* 1 sector to read */
+ movb $16, %cl
+ pushw %cx /* size of this parameter block */
+
+ xchgw %ax, %cx /* save AX to CX */
+
+ /*
+ * translate sector number to BIOS parameters
+ *
+ * LBA = sector-1 offset in track
+ * + head * sectPerTrack offset in cylinder
+ * + cyl * sectPerTrack * nHeads offset in platter
+ *
+ */
+ pushw %bx
+ movw 0x18(%bp), %ax /* sectors per track */
+ movw %ax, %bx
+ mulb 0x1a(%bp) /* nHeads, but maybe a word value 0x100 */
+ jnz 1f
+ movb %bl, %ah /* nHeads=0x100, so AX=sectPerTrack*0x100 */
+1:
+ xchgw %ax, %cx /* restore AX from CX, and save AX to CX */
+ /* DX:AX = LBA, CX = nHeads * sectPerTrack <= 256*63 */
+ divw %cx /* AX = cyl, DX = sector-1 + head * sectPerTrack */
+ xchgw %ax, %dx /* DX = cyl, AX = sector-1 + head * sectPerTrack */
+ divb %bl /* sectors per track */
+ /* DX = cyl, AL = head, AH = sector-1 */
+#if 1
+ xchgb %al, %ah /* DX = cyl, AH = head, AL = sector-1 */
+ incw %ax /* DX = cyl, AH = head, AL = sector */
+ xchgw %ax, %dx /* AX = cyl, DH = head, DL = sector */
+ xchgw %ax, %cx /* CX = cyl, DH = head, DL = sector */
+ xchgb %cl, %ch /* set cyl number low 8 bits in CH */
+ rorb $1, %cl /* move cyl high bits into bits 7-6 */
+ rorb $1, %cl /* (assumes top = 0) */
+ orb %dl, %cl /* merge sector into cylinder */
+#else
+ movw %dx, %cx /* CX = cyl, AL = head, AH = sector-1 */
+
+ /*
+ * the following manipulations are necessary in order to properly place
+ * parameters into registers.
+ * CH = cylinder number low 8 bits
+ * CL<7-6> = cylinder high two bits
+ * CL<5-0> = sector
+ */
+ movb %al, %dh /* save head into DH for BIOS */
+ xchgb %cl, %ch /* set cyl number low 8 bits in CH */
+ rorb $1, %cl /* move cyl high bits into bits 7-6 */
+ rorb $1, %cl /* (assumes top = 0) */
+ incb %ah /* AH = sector number */
+ orb %ah, %cl /* merge sector into cylinder */
+#endif
+ popw %bx
+
+ movw $0x0201, %ax /* read 1 sector */
+ebios_12_16: /* ebios_12_16 - 1 points to 0x02 that can be changed to 0x42 */
+
+// cmpb $0x0e, 2(%bp) /* force LBA? */
+// jnz 1f /* no, continue */
+// movb $0x42, %ah /* yes, use extended disk read */
+//1:
+ movw %sp, %si /* DS:SI points to disk address packet */
+ movb 0x24(%bp), %dl /* drive number */
+ int $0x13
+// stc #; only for testing the buggy Virtual PC
+ popaw /* remove parameter block from stack */
+ popaw
+ jc disk_error_12_16 /* disk read error, jc 1f if caller handles */
+ incw %ax /* next sector */
+ jnz 1f
+ incw %dx
+1:
+ addw 0x0b(%bp), %bx /* bytes per sector */
+ jnc 1f /* 64K bound check */
+ pushw %dx
+ movw %es, %dx
+ addb $0x10, %dh /* add 1000h to ES */
+ /* here, carry is cleared */
+ movw %dx, %es
+ popw %dx
+1:
+ decw %di
+ jnz 2b
+
+ /* carry stored on disk read error */
+ ret
+
+ . = . - (. - readDisk_12_16)/99
+
+msg_DiskReadError_12_16:
+
+ .ascii "disk error\0"
+
+msg_BootError_12_16:
+
+ .ascii "No "
+
+filename_12_16:
+
+#ifdef BOOTGRUB2
+ .ascii "G2LDR \0"
+#elif defined (BOOTGRUB)
+ .ascii "GRLDR \0"
+#else
+ .ascii "KERNEL SYS\0"
+#endif
+
+#ifdef ALTERNATIVE_KERNEL
+filename_end_12_16:
+
+ . = Entry_12_16 + 0x1e8
+
+loadseg_off_12_16: .word 0
+loadseg_seg_12_16: .word LOADSEG_12_16
+
+ . = Entry_12_16 + 0x1ec
+
+boot_image_ofs_12_16:
+
+ .word (filename_12_16 - Entry_12_16)+(filename_end_12_16 - filename_12_16 - 1)*2048
+#endif
+
+ . = Entry_12_16 + 0x1ee
+
+disk_error_12_16:
+
+ movw $(msg_DiskReadError_12_16 - Entry_12_16 + 0x7c00), %si
+
+boot_error_12_16:
+
+/* prints string DS:SI (modifies AX BX SI) */
+
+//print_12_16:
+1:
+ lodsb (%si), %al /* get token */
+ //xorw %bx, %bx /* video page 0 */
+ movb $0x0e, %ah /* print it */
+ int $0x10 /* via TTY mode */
+ cmpb $0, %al /* end of string? */
+ jne 1b /* until done */
+
+ /* The caller will change this to
+ * ljmp $0x9400, $(try_next_partition - _start1)
+ */
+
+1: jmp 1b
+
+ . = Entry_12_16 + 0x1fc
+
+ .word 0, 0xAA55 /* Win9x uses all 4 bytes as magic value here */
+
+ . = Entry_12_16 + 0x200
+
+ . = _start1 + 0x800
+
+
+
+
+ .arch i486, nojumps
+
+/*
+ #; Ext2 boot sector for GRLDR
+ */
+
+
+#define DEBUG call debug_print
+#undef DEBUG
+
+ //. = _start1 + 0x800
+
+Entry_ext2:
+
+ jmp 1f
+
+ . = Entry_ext2 + 0x02
+
+ /* The default mode is CHS. This is for maximum compatiblity with
+ * small-sized disks, e.g., floppies.
+ *
+ * Valid values are 0x02 for CHS mode, or 0x42 for LBA mode.
+ *
+ * If the BIOS int13 supports LBA, this byte can be safely set to 0x42.
+ *
+ * Some USB BIOSes might have bugs when using CHS mode, so the format
+ * program should set this byte to 0x42. It seems that (generally) all
+ * USB BIOSes have LBA support.
+ *
+ * If the format program does not know whether the BIOS has LBA
+ * support, it may operate this way:
+ *
+ * if (partition_start + total_sectors_in_partition) exceeds the CHS
+ * addressing ability(especially when it is greater than 1024*256*63),
+ * the caller should set this byte to 0x42, otherwise, set to 0x02.
+ */
+
+ .byte 0x02 /* for CHS. Another possible value is 0x42 for LBA */
+
+ . = Entry_ext2 + 0x03
+
+#if 0
+
+ .ascii "ext2 grldr"
+
+#else
+
+msg_DiskReadError_ext2:
+
+ .ascii "I/O error\0"
+
+#endif
+
+ . = Entry_ext2 + 0x0d
+
+ /* sectors per block. Valid values are 2, 4, 8, 16, 32. */
+
+ .byte 2
+
+ . = Entry_ext2 + 0x0e
+
+ /* bytes per block.
+ * Valid values are 0x400, 0x800, 0x1000, 0x2000, 0x4000.
+ */
+
+ .word 1024 /* bytes per block, at most 16K */
+
+ . = Entry_ext2 + 0x10
+
+ /* pointers in pointers-per-block blocks, that is, number of blocks
+ * covered by a double-indirect block.
+ * Valid values are 0x10000, 0x40000, 0x100000, 0x400000, 0x1000000.
+ */
+
+ .long 0x10000 /* number of blocks covered by double-indirect block */
+ /* low word=0 */
+
+ . = Entry_ext2 + 0x14
+
+ /* pointers per block, that is, number of blocks covered by an indirect
+ * block. Valid values are 0x100, 0x200, 0x400, 0x800, 0x1000.
+ */
+
+ .long 0x100 /* high word=0, low byte=0 */
+
+ . = Entry_ext2 + 0x18
+
+ /* this is default for 1.44M floppy, the caller should set it to
+ * a correct value */
+
+ .word 18 /* sectors per track */
+
+ . = Entry_ext2 + 0x1a
+
+ /* this is default for 1.44M floppy, the caller should set it to
+ * a correct value */
+
+ .word 2 /* number of heads */
+
+ . = Entry_ext2 + 0x1c
+
+ /* this is default for 1.44M floppy, the caller should set it to
+ * a correct value */
+
+ .long 0 /* hidden sectors */
+
+ . = Entry_ext2 + 0x20
+
+ /* total sectors in the filesystem(or in the partition).
+ * This value is informative. The code does not use it.
+ */
+
+ /* this is default for 1.44M floppy, the caller should set it to
+ * a correct value */
+
+ .long 2880
+
+ . = Entry_ext2 + 0x24
+
+ /* This byte is ignored for read. The program will write DL onto
+ * this byte. The caller should set drive number in DL.
+ * We assume all BIOSes pass correct drive number in DL.
+ * That is to say, buggy BIOSes are not supported!!
+ */
+
+ .byte 0 /* drive number */
+
+ . = Entry_ext2 + 0x25
+
+ /* this is default for floppies, the caller should set it to
+ * a correct value for hard-drive partitions */
+
+ .byte 0xff /* partition number, 0xff for whole drive */
+
+ . = Entry_ext2 + 0x26
+
+ .word 0x80 /* inode size */
+
+ . = Entry_ext2 + 0x28
+
+ /* this is default for 1.44M floppy, the caller should set it to
+ * a correct value */
+
+ .long 2048 /* s_inodes_per_group */
+
+ . = Entry_ext2 + 0x2c
+
+ /* block number for group descriptors = s_first_data_block + 1.
+ * Valid values are 2 for 1024-byte blocks, and 1 for otherwise.
+ */
+
+ /* this is default for 1.44M floppy, the caller should set it to
+ * a correct value */
+
+ .long 2 /* block number for group descriptors */
+
+ . = Entry_ext2 + 0x30
+1:
+ cld /* 0xFC */
+
+ xorw %ax, %ax /* 0x31, 0xC0; CF=0, ZF=1 */
+
+ /* this byte `nop' will be changed to `cwd' by bootlace for floppy */
+ nop /* 0x90=nop, 0x99=cwd */
+ /* cwd will set DL=0 forcibly for floppy A: */
+
+ movw %ax, %ss /* constant SS=0 */
+ movw $0x7c00, %sp
+
+ movw %sp, %bp /* constant BP=0x7c00 */
+ movw %ax, %ds /* constant DS=0 */
+
+ pushw %ax /* 0x0000 at 0000:7bfe */
+ movw $0x1000, %bx
+ pushw %bx /* 0x1000 at 0000:7bfc */
+ pushw %ax /* 0x0000 at 0000:7bfa */
+ /* SP=0x7bfa */
+
+ /* the 6 bytes in the stack are used by read_block():
+ * 0000 ---- -2(%bp)
+ * 1000 ---- -4(%bp)
+ * 0000 ---- -6(%bp)
+ * Don't touch them!
+ */
+
+ movb %dl, 0x24(%bp) /* BIOS passes drive number in DL */
+
+ movb $0x41, %ah
+ movw $0x55AA, %bx
+ int $0x13
+#if 0
+ jnc 1f
+ /* No EBIOS */
+ movb $0x02, (ebios_ext2 - 1 - Entry_ext2 + 0x7c00)
+#else
+ jc 1f #; No EBIOS
+
+ //testb $1, %cl
+ //jz 1f #; No EBIOS
+#if 0
+ /* gcc-4.0.1 does not generate 2-byte code. */
+ rcrb $1, %cl #; also can be rorb $1, %cl
+#else
+ .byte 0xD0, 0xD9 #; ror cl: D0 C9
+#endif
+ jnc 1f #; No EBIOS
+
+ movb $0x42, (ebios_ext2 - 1 - Entry_ext2 + 0x7c00)
+#endif
+1:
+ xorl %eax, %eax /* CF=0, ZF=1 */
+
+#if 0
+ /* the INC touches ZF flag, so use MOV instead */
+
+ incw %ax
+ incw %ax /* EAX=2=inode number for root dir */
+#else
+
+ /* MOV keeps all flags untouched, so it is better than INC */
+
+ movb $2, %al /* EAX=2=inode number for root dir */
+#endif
+
+ /* CF=0, ZF=1 because MOV and PUSH do not touch Flags */
+
+ /* read root dir to 0000:1000, and grldr to 1000:0000 */
+
+4:
+ /* EAX holds the inode number: for root dir or grldr */
+
+ /* These 3 PUSHes is intended to place 1000:0000 onto the stack for
+ * grldr. For root dir, the stack is not used since CF is cleared.
+ * Although there is no corresponding POPs, this is safe enough
+ * because the program comes here only twice: the first is for
+ * the root dir, and the second is for grldr.
+ *
+ * For root dir, CF=0 and ZF=1. For grldr, CF=1.
+ */
+
+ pushw %di /* 0x1000, see "jz 4b" below. */
+ pushw %ss /* 0x0000 */
+ pushfw
+
+ /* SP=0x7bf4 for root dir, or 0x7bee for grldr */
+
+ decl %eax /* EAX=(inode - 1) */
+
+ /* inode numbers are far less than 0x7fffffff, so it is safe to
+ * initialise EDX with CDQ */
+
+ cdq /* let EDX=0 */
+
+ divl 0x28(%bp) /* s_inodes_per_group */
+ /* EAX=group number */
+ pushl %edx /* EDX=inode number in the group */
+
+ /* group numbers are far less than 0x7fffffff, so it is safe to
+ * initialise EDX with CDQ */
+
+ cdq /* let EDX=0 */
+ shll $5, %eax /* EAX=relative displacement of the group descriptor */
+ divl 0x0e(%bp) /* bytes per block */
+ /* EAX=relative block number for the group descriptor */
+ /* DX=displacement in the block */
+ /* EDX high=0 */
+
+ pushw %dx /* we don't care about EDX high word, because it is 0 */
+
+ addl 0x2c(%bp), %eax /* EAX=absolute block number for the group descriptor */
+ /* CF=0, ZF=0 */
+
+ call read_block /* 0000:1000 points to the block data containing the group descriptor */
+ /* ES changed and > 0, BX=0x1000 */
+ /* ECX=EDX=0 */
+ /* CF=0, ZF=0 */
+
+ popw %si /* DS:[BX+SI] points to the group descriptor */
+ /* DS:[BX+SI+8] points to the starting block number of the group inode table */
+
+ popl %eax /* inode number in the group */
+// shll $7, %eax /* inode struct size = 0x80 */
+// /* EAX=relative displacement of the inode struct */
+// /* EDX=0 */
+ movw 0x26(%bp), %dx /* EDX=inode size */
+ mull %edx /* EDX:EAX=relative displacement of the inode struct */
+
+ divl 0x0e(%bp) /* bytes per block */
+ /* EAX=relative block number for the inode struct */
+ pushw %dx /* DX=displacement of the inode struct in the block */
+ /* EDX high=0 */
+
+ addl 8(%bx, %si), %eax /* EAX=absolute block number for the inode struct */
+ /* CF=0, ZF=0 */
+
+ call read_block /* 0000:1000 points to the block data containing the inode struct */
+ /* ES changed and > 0, BX=0x1000 */
+ /* ECX=EDX=0 */
+ /* CF=0, ZF=0 */
+
+ popw %si /* DS:[BX+SI] points to the inode struct */
+
+ addw %bx, %si /* DS:SI points to the inode struct */
+
+ /* Move the inode struct to a known safe area(0000:0fa8 - 0000:0fff),
+ * that is, 0x58 bytes immediately before 0000:1000. We care about only
+ * the beginning 0x58 bytes of the 0x80-byte inode struct, the last
+ * 0x28 bytes are ignored. The area from 0xfa8+0x28 to 0xfa8+0x57
+ * stores 12 direct block pointers.
+ *
+ *
+ * At address Initial value Stores what?
+ * ========== ============= ======================================
+ * 0xfa8+0x04 (const) the size of the file in bytes
+ *
+ * 0xfa8+0x08 total blocks blocks left to read
+ *
+ * 0xfa8+0x0c 0 serial number of the block to read
+ *
+ */
+
+ pushw %ss
+ popw %es /* ES=0 */
+
+ leaw -0x58(%bx), %di /* BX=0x1000, so DI=0x0fa8 */
+ //movw $0x0fa8, %di
+ movb $0x2c, %cl /* 0x2c words = 0x58 bytes */
+
+ repz movsw /* now ECX=0, BX=0x1000=DI */
+
+ movl %ecx, (0x0c - 0x58)(%di) /* block serial number of the file */
+ /* ECX=0 means first block */
+ /* DI=0x1000 */
+
+ movl (0x04 - 0x58)(%di), %eax /* i_size, the file size */
+ decl %eax
+
+ divl 0x0e(%bp) /* bytes per block */
+ /* EDX=various */
+ incl %eax
+ movl %eax, (0x08 - 0x58)(%di) /* total blocks for file data */
+
+ /*
+ * 0000:1000 trebly indirect block
+ * 0000:8000 indirect block
+ * 0000:c000 double indirect block
+ * 1000:0000 the file data
+ */
+
+ /* now DS:SI points to indirect block number */
+
+ lodsl /* indirect block number */
+ testl %eax, %eax
+ jz 1f
+
+ //pushw %ss
+ //popw %es /* ES=0 */
+ movb $0x80, %bh /* ES:BX=0000:8000 */
+#if 0
+ stc
+ call read_block
+#else
+ call read_block_c
+#endif
+ /* ES changed and > 0, BX=0x8000 */
+ /* ECX=EDX=0 */
+ /* ZF=0, CF=0 */
+
+ /* now DS:SI points to double indirect block number */
+
+ lodsl /* double indirect block number */
+ testl %eax, %eax
+ jz 1f
+
+#if 0
+ pushw %ss
+ popw %es /* ES=0 */
+ movb $0xc0, %bh /* ES:BX=0000:c000 */
+ stc
+ call read_block
+#else
+ movb $0xc0, %bh /* ES:BX=0000:c000 */
+ call read_block_c
+#endif
+ /* ES changed and > 0, BX=0xc000 */
+ /* ECX=EDX=0 */
+ /* ZF=0, CF=0 */
+
+ /* now DS:SI points to trebly indirect block number */
+
+ lodsl /* trebly indirect block number */
+ testl %eax, %eax /* CF=0, TEST always clears CF */
+ jz 1f
+ /* ZF=0 */
+ //pushw %ss
+ //popw %es /* ES=0 */
+ //movb $0x10, %bh /* ES:BX=0000:1000 */
+ //stc
+ call read_block /* 0000:1000 points to the block data */
+ /* ES changed and > 0, BX=0x1000 */
+ /* ECX=EDX=0 */
+ /* ZF=0, CF=0 */
+
+ /* the block at 0000:1000, which contains the indirect block numbers,
+ * is just overwritten by the trebly indirect block */
+
+1:
+ /* get absolute block number by block serial number */
+
+ movl (0x0c - 0x58)(%di), %ebx /* block serial number of the file */
+ subl $12, %ebx
+ jc 3f /* direct block: block serial number < 12 */
+
+ pushw %bx
+ subl 0x14(%bp), %ebx
+ popw %ax
+ jnc 2f
+
+ /* indirect block: 12 <= block serial number < 12 + 0x14(%bp) */
+
+ //addw 0x14(%bp), %bx
+ addb $(0x70 / 4), %ah
+ //xchgw %ax, %bx
+ jmp 8f
+
+2:
+ pushl %ebx
+ subl 0x10(%bp), %ebx
+ jc 7f /* EBX on the stack is < 0x10(%bp). double indirect block:
+ * 12 + 0x14(%bp) <= block serial number < 12 + 0x14(%bp) + 0x10(%bp)
+ */
+
+ /* trebly indirect block: block serial number >= 12 + 0x14(%bp) + 0x10(%bp) */
+
+ popl %eax /* discard the stack */
+ xchgl %eax, %ebx /* move EBX to EAX */
+ /* EDX=0 */
+ divl 0x10(%bp)
+ /* EAX=indirect block number, < 0x14(%bp) */
+ /* EDX=block number, < 0x10(%bp) */
+
+ pushl %edx /* EDX < 0x10(%bp) */
+ testl %edx, %edx
+ jnz 7f
+
+ /* EDX=0, so we need to load the double indirect block */
+
+ shlw $2, %ax
+ xchgw %ax, %bx
+
+ /* get the double indirect block number from the trebly indirect
+ * block data */
+
+ movl (%bx, %di), %eax
+
+//6:
+ movw $0xc000, %bx /* ES:BX=0000:c000 */
+
+ //pushw %ss
+ //popw %es /* ES=0 */
+ //stc
+ call read_block_c /* 0000:c000 points to the block data */
+ /* ES changed and > 0, BX=0xc000 */
+ /* ECX=EDX=0 */
+ /* CF=0, ZF=0 */
+7:
+ popl %eax /* EAX < 0x10(%bp) */
+ cdq /* let EDX=0 (notice the above jc 7f and jnz 7f) */
+ divl 0x14(%bp)
+ /* EAX=indirect block number, < 0x14(%bp) */
+ /* EDX=block number, < 0x14(%bp) */
+
+ pushw %dx /* EDX < 0x14(%bp) */
+ testw %dx, %dx
+ jnz 7f
+
+ /* if DX=0, we need to load the indirect block */
+
+ //addb $(0xb0 / 4), %ah
+ shlw $2, %ax
+ xchgw %ax, %bx
+
+ /* get the indirect block number from the double indirect block data */
+
+ movl 0xb000(%bx, %di), %eax
+ //movl (%bx, %di), %eax
+//5:
+ movw $0x8000, %bx /* ES:BX=0000:8000 */
+
+ //pushw %ss
+ //popw %es /* ES=0 */
+ //stc
+ call read_block_c /* 0000:8000 points to the block data */
+ /* ES changed and > 0, BX=0x8000 */
+ /* ECX=EDX=0 */
+ /* CF=0, ZF=0 */
+7:
+ popw %ax /* AX < 0x14(%bp) */
+8:
+ xchgw %ax, %bx
+3:
+ shlw $2, %bx
+ movl (%bx, %di), %eax
+
+ /* got it! EAX=absolute block number */
+
+ /* read block data to 1000:0000. For root dir, read each block to
+ * 1000:0000(overwrite the previous read). For grldr, read blocks
+ * one by one to the area starting at 1000:0000.
+ */
+
+ popfw
+ popw %bx
+ popw %es
+ pushfw
+
+ /* CF=0 and ZF=1 for reading root dir, CF=1 for reading grldr */
+
+ call read_block /* 1000:0000 points to the block data */
+ /* ES changed and > 0x1000, BX=0 */
+ /* ECX=EDX=0 */
+ /* CF=0, ZF=0 */
+
+ popfw
+ pushw %es
+ pushw %bx
+ pushfw
+
+ jc 3f /* CF=1, we are reading grldr */
+
+ /* We have just read a block of the root dir to 1000:0000.
+ * So we check all dir entries in the block to see if anyone
+ * matches grldr.
+ */
+
+ xorw %si, %si
+ pushw %ss
+ popw %es /* ES=0 */
+
+2:
+ pushw %ds /* DS=0 */
+ movw %di, %ds /* DS=0x1000 */
+ movw $(filename_ext2 - Entry_ext2 + 0x7c00), %di
+
+ pushw %si
+ lodsl /* This is possible inode number for grldr */
+ pushl %eax /* This is possible inode number for grldr */
+ lodsw
+ xchgw %ax, %dx /* rec_len */
+ lodsw /* AL=name_len, should be 5 for grldr */
+ /* AH=file_type(1 for regular file) */
+#if 0
+ cmpw $0x0105, %ax
+ jnz 5f
+ movb %al, %cl /* CH is already 0 */
+ repz cmpsb
+#else
+ decb %ah
+ //jnz 5f
+ xchgw %ax, %cx /* CX=name_len */
+ repz cmpsb
+ jnz 5f
+ xchgw %ax, %cx /* movb $0, %al */
+ scasb
+#endif
+5:
+ popl %eax /* This is possible inode number for grldr */
+ popw %si
+
+ /* DS=0x1000, EAX=inode number */
+
+ movw %ds, %di /* DI=0x1000 */
+ popw %ds /* DS=0 */
+
+ stc /* indicates the new inode is for grldr */
+
+ jz 4b /* grldr is found with EAX=inode number */
+
+ addw %dx, %si
+ cmpw 0x0e(%bp), %si /* bytes per block */
+ jb 2b
+
+ /* file not found in this block, continue */
+
+ /* We are lucky that CF=0, which indicates we are dealing with
+ * the root dir.
+ */
+
+3:
+
+ /* CF=1 for grldr, CF=0 for root dir. */
+
+ incl (0x0c - 0x58)(%di)
+ decl (0x08 - 0x58)(%di)
+ jnz 1b
+
+#if 0
+ /* The above 2 instructions INC and DEC do not touch CF, so we
+ * can omit this POP-PUSH pair.
+ */
+
+ popfw
+ pushfw
+#endif
+
+ movw $(msg_No_grldr_ext2 - Entry_ext2 + 0x7c00), %si
+
+ jnc boot_error_ext2 /* grldr not found in the root dir */
+
+ /* All grldr blocks have been loaded to memory starting at 1000:0000,
+ * Before the boot, we pass boot_drive and boot_partition to grldr.
+ */
+
+ /* ES>0x1000, BX=0, ECX=EDX=0, DI=0x1000, SS=0, SI>0x7c00, DS=0
+ * BP=0x7c00, SP<=0x7c00
+ */
+
+ movw 0x24(%bp), %dx
+
+ /* boot it now! */
+
+ pushw %di /* 0x1000 */
+ pushw %ss /* 0x0000 */
+ lret
+
+read_block_c:
+
+ pushw %ss
+ popw %es /* ES=0 */
+ stc
+
+/* read_block - read a block
+ * input: CF - indicator for overlap or consecution
+ * EAX = block number
+ * ES:BX - buffer
+ *
+ * output: if CF is cleared on input, ES:BX is initialized to 0000:1000
+ * ES:BX - buffer filled with data
+ * ES, EAX - Changed
+ * ECX = 0
+ * EDX = 0
+ * ZF = 0
+ * CF = 0
+ */
+
+read_block:
+
+ jc 1f
+
+ .byte 0xC4, 0x5E, 0xFC /* lesw -4(%bp), %bx */
+ /* ES:BX=0000:1000 */
+ jnz 1f
+
+ //at this time, the gcc cannot generate 3 byte code
+ .byte 0xC4, 0x5E, 0xFA /* lesw -6(%bp), %bx */
+ /* ES:BX=1000:0000 */
+ //. = . - (. - read_block) / 6
+1:
+ movzbl 0x0d(%bp), %ecx /* CX=sectors per block */
+ /* ECX high=0 */
+ . = . - (. - 1b) / 6
+ mull %ecx /* EAX=relative sector number */
+ /* EDX=0 */
+ . = . - (. - 1b) / 9
+ addl 0x1c(%bp), %eax /* EAX=absolute sector number */
+
+#if 1
+ /* pass through, saving 4 bytes(call and ret) */
+#else
+ call readDisk_ext2
+ ret
+#endif
+
+/* Read sectors from disk, using LBA or CHS
+ * input: EAX = 32-bit LBA sector number
+ * CX = number of sectors to read
+ * ECX high word = 0
+ * ES:BX = destination buffer
+ *
+ * output: No return on error
+ * BX not changed
+ * ES = ES + 0x20 * CX
+ * EAX = EAX + CX
+ * ZF = 0
+ * CF = 0
+ */
+
+readDisk_ext2:
+2:
+ pushal
+ //xorl %edx, %edx /* EDX:EAX = LBA */
+ pushl %edx /* hi 32bit of sector number */
+ pushl %eax /* lo 32bit of sector number */
+ pushw %es /* buffer segment */
+ pushw %bx /* buffer offset */
+ pushw $1 /* 1 sector to read */
+ pushw $16 /* size of this parameter block */
+
+ //xorl %ecx, %ecx
+ pushl 0x18(%bp) /* lo:sectors per track, hi:number of heads */
+ popw %cx /* ECX = sectors per track */
+ divl %ecx /* residue is in EDX */
+ /* quotient is in EAX */
+ /* EDX high=0, DH=0 */
+ incw %dx /* DL=sector number */
+ popw %cx /* ECX = number of heads */
+ pushw %dx /* push sector number into stack */
+ xorw %dx, %dx /* EDX:EAX = cylinder * TotalHeads + head */
+ divl %ecx /* residue is in EDX, head number */
+ /* quotient is in EAX, cylinder number */
+ /* EDX high=0, EAX high=0 */
+
+
+ xchgb %dl, %dh /* head number should be in DH */
+ /* DL = 0 */
+ popw %cx /* pop sector number from stack */
+ xchgb %al, %ch /* lo 8bit cylinder should be in CH */
+ /* AL = 0 */
+ shlb $6, %ah /* hi 2bit cylinder ... */
+ orb %ah, %cl /* ... should be in CL */
+
+ incw %ax /* AL=1, read 1 sector */
+
+ /* Instead of 0x0e, the LBA indicator at 2(%bp) is
+ *
+ * 0x42 for LBA
+ *
+ * and
+ *
+ * 0x02 for CHS
+ */
+#if 0
+ movb $0x42, %ah
+ /* ebios_ext2 - 1 points to 0x42 that can be changed to 0x02 */
+#else
+ movb $0x02, %ah
+ /* ebios_ext2 - 1 points to 0x02 that can be changed to 0x42 */
+#endif
+ebios_ext2:
+
+ //andb 2(%bp), %ah
+
+ movw %sp, %si /* DS:SI points to disk address packet */
+ movb 0x24(%bp), %dl /* drive number */
+ int $0x13
+ jc disk_error_ext2
+ movw %es, %ax
+ addw $0x20, %ax /* here, carry is cleared */
+ movw %ax, %es
+ popaw /* remove parameter block from stack */
+ popal
+ incl %eax /* next sector, here ZF=0 */
+ loop 2b
+ ret
+
+ //. = . - (. - readDisk_ext2)/74
+
+//msg_DiskReadError_ext2:
+//
+// .ascii "disk error\0"
+
+msg_No_grldr_ext2:
+
+ .ascii "No "
+
+filename_ext2:
+#ifdef BOOTGRUB2
+ .ascii "g2ldr\0"
+#else
+ .ascii "grldr\0"
+#endif
+ . = Entry_ext2 + 0x1ee
+
+filename_end_ext2:
+
+ .word (filename_ext2 - Entry_ext2)+(filename_end_ext2 - filename_ext2 - 1)*2048
+
+ . = Entry_ext2 + 0x1f0
+
+disk_error_ext2:
+
+ movw $(msg_DiskReadError_ext2 - Entry_ext2 + 0x7c00), %si
+
+boot_error_ext2:
+
+/* prints string DS:SI (modifies AX BX SI) */
+
+//print_ext2:
+1:
+ lodsb (%si), %al /* get token */
+ //xorw %bx, %bx /* video page 0 */
+ movb $0x0e, %ah /* print it */
+ int $0x10 /* via TTY mode */
+ cmpb $0, %al /* end of string? */
+ jne 1b /* until done */
+#if 1
+
+ /* The caller will change this to
+ * ljmp $0x9400, $(try_next_partition - _start1)
+ */
+
+1: jmp 1b
+
+#else
+ /* boot failed, try to hand over the control to supervisor */
+ ldsw (1f + 3 - Entry_ext2)(%bp), %si
+ lodsl
+ cmpl $0x9400b8fa, %eax
+1: jnz 1b /* no supervisor, hang up. */
+ ljmp $0x9400, $(try_next_partition - _start1)
+
+ //. = . - (. - disk_error_ext2) / 30
+#endif
+
+ . = Entry_ext2 + 0x1fe
+
+ .word 0xAA55
+
+ . = _start1 + 0xA00
+
+#define INSIDE_GRLDR
+
+#include "ntfsbs.S"
+
+ . = _start1 + 0x1200
+
+ .arch i586, jumps
+
+#ifdef DEBUG
+
+ . = Entry_ext2 + 0x201
+
+debug_print:
+
+ pushfl
+ pushal
+ movl %eax, %ebp
+ call 2f
+#if 0
+ popal
+ pushal
+ movl %ebx, %ebp
+ call 2f
+ popal
+ pushal
+ movl %ecx, %ebp
+ call 2f
+ popal
+ pushal
+ movl %edx, %ebp
+ call 2f
+ popal
+ pushal
+ movl %esi, %ebp
+ call 2f
+ popal
+ pushal
+ movl %edi, %ebp
+ call 2f
+ popal
+ popfl
+ pushfl
+ pushal
+ pushfl
+ popl %ebp /* flags */
+ call 2f
+ movw %ds, %bp
+ shll $16, %ebp
+ movw %es, %bp
+ call 2f
+ movw $0x0e0d, %ax /* print CR */
+ int $0x10 /* via TTY mode */
+ movw $0x0e0a, %ax /* print LF */
+ int $0x10 /* via TTY mode */
+#endif
+ popal
+ popfl
+ ret
+2:
+ movw $7, %cx
+1:
+ xorw %bx, %bx /* video page 0 */
+ movl %ebp, %eax
+ shrl %cl, %eax
+ shrl %cl, %eax
+ shrl %cl, %eax
+ shrl %cl, %eax
+ andb $0x0f, %al
+ addb $0x30, %al
+ movb $0x0e, %ah /* print char in AL */
+ int $0x10 /* via TTY mode */
+
+ decw %cx
+ testw %cx, %cx
+ jns 1b
+
+ movw $0x0e20, %ax /* print space */
+ int $0x10 /* via TTY mode */
+ ret
+#endif
+
+#if 1
+ /* restore GRLDR_CS */
+
+ /* this code is executed at 0000:MONITOR, which must be a 16-byte
+ * aligned address. The address 0000:MONITOR should be designed in
+ * a way that could avoid memory confliction with volume boot records
+ * (currently FAT12/16/32/NTFS/EXT2/3 are built in).
+ */
+
+ /* CS=code */
+
+ .align 16
+
+restore_GRLDR_CS:
+2:
+ call 1f
+1:
+ popw %bx # instruction pointer of 1b
+ movw %cs, %ax
+ shrw $4, %bx
+ addw %ax, %bx # BX=segment value of this code
+ pushw %bx
+ pushw $(1f - 2b)
+ lret
+1:
+ /* modify gdt base */
+ xorl %eax, %eax
+ movw %bx, %ax
+ shll $4, %eax
+ addl $(gdt -2b), %eax
+ movl %eax, %cs:(gdt - 2b + 2)
+
+ movw $GRLDR_CS, %bx
+ movw %bx, %es
+ movw %ds, %bx # save old DS to BX
+
+ cli
+ lgdt %cs:(gdt - 2b)
+ movl %cr0, %eax
+ orb $1, %al
+ movl %eax, %cr0
+
+ movw $8, %si
+ movw %si, %ds
+
+ xorl %esi, %esi
+ xorl %edi, %edi
+ movl $(0x9000 / 4), %ecx
+
+ cld
+ repz movsl
+
+ movw $16, %si
+ movw %si, %ds
+
+ andb $0xfe, %al
+ movl %eax, %cr0
+
+ movw %bx, %ds # restore DS from BX
+
+ ljmp $GRLDR_CS, $(try_next_partition - _start1)
+
+#endif
+
+# Descriptor tables
+#
+# NOTE: The intel manual says gdt should be sixteen bytes aligned for
+# efficiency reasons. However, there are machines which are known not
+# to boot with misaligned GDTs, so alter this at your peril! If you alter
+# GDT_ENTRY_BOOT_CS (in asm/segment.h) remember to leave at least two
+# empty GDT entries (one for NULL and one reserved).
+#
+# NOTE: On some CPUs, the GDT must be 8 byte aligned. This is
+# true for the Voyager Quad CPU card which will not boot without
+# This directive. 16 byte aligment is recommended by intel.
+#
+ .align 16
+gdt:
+ /* this is the default null entry in GDT */
+ .word gdt_end - gdt - 1 # gdt limit
+ .long (GRLDR_CS * 16 + gdt - _start1) # linear address of gdt
+ .word 0 # pad 2 bytes
+
+ /* real mode data segment base=0x200000 */
+ .word 0xFFFF, 0
+ .byte 0x20, 0x92, 0, 0
+
+ /* real mode data segment base=0 */
+ .word 0xFFFF, 0
+ .byte 0, 0x92, 0, 0
+
+gdt_end:
+
+helper_start:
+
+ /* helper function begins here
+ * before the call:
+ * CF=1 : indicates an invalid or corrupt entry
+ * CF=0 : indicates a valid entry
+ *
+ * on return:
+ * CF=1 : means "below", try next entry
+ * CF=0,ZF=1 : means "equal", helper did nothing, so we need
+ * a further try to boot via NT bootsector
+ * CF=0,ZF=0 : means "above", helper succeeded, boot it now
+ */
+
+ sti
+
+ /* DS=SS=0x9400 */
+ pushw %cs
+ popw %ds
+
+ pushw $FS_BOOT
+ popw %es
+
+ /* ES=FS_BOOT */
+
+ /* Format of partition information blocks.
+ *
+ * Offset Length in bytes Field
+ * 00h 1 Set to 80h if this partition is active.
+ * 01h 1 Partition's starting head.
+ * 02h 2 Partition's starting sector and track.
+ * 04h(SI) 1 Partition's ID number.
+ * 05h 1 Partition's ending head.
+ * 06h 2 Partition's ending sector and track.
+ * 08h 4 Starting LBA.
+ * 0Ch 4 Partition's length in sectors.
+ */
+
+ pushw %ds /* DS=0x9400 */
+ pushw %es /* ES=FS_BOOT */
+ pushal
+ pushfw
+
+ //pushw %si
+ //stc
+ //jc invalid_or_null /* invalid or null entry */
+#if 0
+ /* backup 63 sectors at FS_BOOT:0 to 63 sectors at FS_BOOT:8000
+ * this piece of code is no longer useful.
+ */
+ pushw %es
+ popw %ds
+ xorw %si, %si
+ movw $0x8000, %di
+ movw $0x3f00, %cx
+ cld
+ repz movsw
+#endif
+
+#if (defined(GRLDR_MBR)) || (defined(GRLDR_INSTALL))
+ testb $0x80, %cs:0x02 /* boot previous MBR first? */
+ jnz 2f /* no, continue to find GRLDR */
+
+ /* yes, call the routine for booting the previous MBR.
+ * it will not return on success.
+ * on failure, it will return here
+ */
+
+ /* before we call the routine, we will check if the user want to
+ * skip this step and continue to find the GRLDR
+ */
+#if 0
+ movw $(press_space_bar_string - _start1), %si
+ cmpw $0x3920, %cs:0x04
+ je 1f
+ movw $(press_hot_key_string - _start1), %si
+1:
+ /* if timeout==0, don't display the message */
+
+ cmpb $0, %cs:0x03
+ je 1f
+ call print_message /* CS:SI points to message string */
+ movw $(press_any_key_string - _start1), %si
+ call print_message /* CS:SI points to message string */
+#else
+ cmpb $0, %cs:0x03
+ je 1f
+ movw $(press_hot_key_pre - _start1), %si
+ call print_message
+ movw $(press_hot_key_name - _start1), %si
+ call print_message
+ movw $(press_hot_key_sub - _start1), %si
+ call print_message
+#endif
+1:
+ call sleep_5_seconds
+ jc 1f /* desired hot-key pressed */
+ call boot_prev_mbr //Error_modify
+1:
+ orb $0x80, %cs:0x02
+2:
+#endif
+ popfw
+ popal
+ popw %es
+ popw %ds
+
+ pushw %ds /* DS=0x9400 */
+ pushw %es /* ES=FS_BOOT */
+ pushal
+ pushfw
+
+ //cmpb $0x0e, 0x00 /* EBIOS previously checked OK? */
+ //jbe 1f /* yes, skip the check */
+ movb $0x02, 0x00 /* initialise this byte to 0x02 */
+ movb $0x41, %ah /* EBIOS check existence */
+ movw $0x55aa, %bx
+ int $0x13
+ jc 1f /* No EBIOS */
+ cmpw $0xaa55, %bx
+ jnz 1f /* No EBIOS */
+ testb $1, %cl
+ jz 1f /* No EBIOS */
+ movb $0x42, 0x00 /* LBA supported, save 0x42 to 9400:0000 */
+1:
+ popfw
+ popal
+ popw %es
+ popw %ds
+
+ pushw %ds /* DS=0x9400 */
+ pushw %es /* ES=FS_BOOT */
+ pushal
+ pushfw
+
+ pushaw
+ cmpw $0x1c2, %si
+ jne 1f
+ /* initialize partition number and partition entries end */
+ movw $0xffff, 0x1bc /* hd partition number */
+ movw $0x01fe, 0x1ba /* partition entries end */
+1:
+ pushw %dx
+ testb %dl, %dl
+ jns 1f /* floppy, use normal CHS mode */
+ cmpw $0x1f2, %si /* is it a primary partition? */
+ ja 2f /* no, it is an extended partition */
+ movl 4(%si), %eax
+ movl %eax, 8(%si) /* parent part_start saved here */
+ xorl %eax, %eax
+ movl %eax, 4(%si) /* current part_start(0) saved here */
+2:
+ //movl -4(%si), %eax
+ //cmpl $0xfffffe00, %eax /* check the starting CHS */
+ //jb 1f /* use normal CHS mode */
+
+ /* get CHS total number of sectors */
+ pushw %es
+ pushw %ds
+ movb $8, %ah /* read drive parameters changes DX,ES,DI */
+ //movb $0x80, %dl /* BIOS drive number is in DL */
+ int $0x13
+ popw %ds
+ popw %es
+ jc 3f
+ testb $63, %cl
+ jnz 2f
+3:
+ /* failed to get drive parameters, use maximum value */
+#if 0
+ popw %dx
+ pushw %dx
+ cmpb $0x80, %dl
+ jne 3f
+ pushw %ds
+ xorw %ax, %ax
+ movw %ax, %ds
+ cmpb $0, 0x475
+ popw %ds
+ je 3f
+
+3:
+#endif
+ movw $0xffff, %cx
+ movw %cx, %dx
+2:
+ //xorl %eax, %eax
+ movzbl %dh, %eax
+ incw %ax
+ movzbl %cl, %edx
+ andb $63, %dl
+ mulw %dx /* DX=0, AX=product */
+ shrb $6, %cl
+ xchgb %cl, %dh
+ xchgb %ch, %dl
+ incw %dx /* DX=total cylinders */
+ mull %edx /* EDX=0, EAX=product */
+
+ /* check the partition's starting LBA */
+ movl 4(%si), %ebx
+ addl 8(%si), %ebx /* EBX=start_LBA */
+
+ testl %ebx, %ebx
+ je 1f
+
+ ///* we always use LBA mode */
+ ////cmpl %eax, %ebx
+ ////jb 1f /* use normal CHS mode */
+ cmpb $0x42, 0x00 /* EBIOS present? */
+ jne 1f /* no, skip the LBA mode int13 call */
+
+ /* load partition boot track to FS_BOOT using LBA mode */
+ popw %ax /* AX=orig DX which holds drive number DL */
+ pushw %ax
+ pushl %edx /* EDX=0, higher 4 bytes of starting LBA */
+ pushl %ebx /* lower 4 bytes of starting LBA */
+ pushw %es /* ES=FS_BOOT */
+ pushw %dx /* DX=0, ES:0 is the buffer */
+ //pushl $0x003f0010 /* transfer 63 sectors */
+ pushw $0x3f /* transfer 63 sectors */
+ pushw $0x10 /* size of disk address packet */
+ xchgw %ax, %dx /* restore drive number DL from AL */
+ movb $0x42, %ah /* extended read */
+ movw %sp, %si /* DS:SI points to disk address packet */
+ int $0x13 /* ignore the read failure */
+ popaw /* adjust the stack */
+ jc 1f
+ popw %dx
+ popaw
+
+ //popw %ax /* discard flags in the stack */
+ popfw
+ clc
+
+ pushfw /* push new flags with CF=0 */
+ pushaw
+ pushw %dx
+1:
+ popw %dx
+ popaw
+
+ popfw
+ popal
+ popw %es
+ popw %ds
+
+ pushw %ds /* DS=0x9400 */
+ pushw %es /* ES=FS_BOOT */
+ pushal
+ pushfw
+
+ pushw %si
+
+ pushfw
+ pushw %es
+//---------------------------------------------------------
+ /* print "Try (hd0,n): " or "Try (fd0): "*/
+ pushw %ds
+ popw %es /* ES=DS=CS=0x9400 */
+
+ cld /* for stosb */
+ xorw %ax, %ax
+ testb %dl, %dl
+ jns 1f /* floppy */
+ /* hard drive */
+#if 0
+ movw %si, %ax
+ subw $0x1c2, %ax
+ shrw $4, %ax
+ cmpw $0x1fe, %si /* is in MBR? */
+ jb 1f /* yes */
+ /* no, it is an entry in an extended partition */
+ movb $0xFC, (add_sub_si + 2 - _start1) /* addw $-4, %si */
+ incw 0x1bc /* logical partition number */
+ movb 0x1bc, %al
+#else
+ incw 0x1bc /* logical partition number */
+ movw 0x1bc, %ax
+ cmpb $4, %al
+ jb 1f
+ movb $0xFC, (add_sub_si + 2 - _start1) /* addw $-4, %si */
+#endif
+1:
+ /* AL=partition number, AH=0 */
+ pushw %ax
+
+ movw $(partition_message - _start1 + 7), %di /* drive type */
+ movb %dl, %al
+ shrb $7, %al /* drive type: floppy=0, harddrive=1 */
+ shlb $1, %al
+ addw $0x6466, %ax /* "fd" or "hd" */
+ stosw
+ movb %dl, %al
+ andb $0x7f, %al /* drive number */
+ aam /* convert binary to decimal, AH=high, AL=low */
+ testb %ah, %ah
+ jz 1f
+ addb $0x30, %ah
+ movb %ah, (%di)
+ incw %di
+1:
+ addb $0x30, %al
+ stosb
+
+ popw %ax
+
+ testb %dl, %dl
+ jns 2f /* floppy */
+ /* this is a hard drive, the partition number is in AL */
+ movb $0x2c, (%di) /* "," */
+ incw %di
+ aam /* convert binary to decimal, AH=high, AL=low */
+ testb %ah, %ah
+ jz 1f
+ addb $0x30, %ah
+ movb %ah, (%di)
+ incw %di
+1:
+ addb $0x30, %al
+ stosb
+2:
+ movl $0x00203a29, (%di) /* "): \0" */
+
+ movw $(partition_message - _start1), %si
+ call print_message /* CS:SI points to message string */
+//---------------------------------------------------------
+ popw %es
+ popfw
+ //stc
+ jc invalid_or_null /* invalid or null entry */
+
+ xorw %si, %si
+ pushw %es
+ popw %ds
+
+ /* DS=ES=FS_BOOT */
+
+ /* First, check for ext2 filesystem */
+
+ cmpw $0xEF53, 0x438 /* Magic signature */
+ jnz 1f
+ xorl %eax, %eax
+ cmpl %eax, 0x400 /* s_inodes_count */
+ jz 1f
+ cmpl %eax, 0x404 /* s_blocks_count */
+ jz 1f
+// cmpw %ax, 0x458 /* s_inode_size, usually 0x80 */
+// jz 1f
+ cmpl %eax, 0x420 /* s_blocks_per_group */
+ jz 1f
+ cmpl %eax, 0x428 /* s_inodes_per_group */
+ jz 1f
+ movl 0x414, %eax /* s_first_data_block */
+ movw %ax, %bx /* BX=1 for 1K block, 0 otherwise */
+ shrl $1, %eax /* must be 0 */
+ jnz 1f
+ movl 0x418, %ecx /* s_log_block_size */
+ cmpl $4, %ecx /* max size of block is 16K */
+ ja 1f
+ negw %cx /* CF=0 for 1K block, CF=1 otherwise */
+ adcw %ax, %bx /* EAX=0 */
+ decw %bx
+ jnz 1f
+
+ /* BX = 0 */
+ /* EAX= 0 */
+
+ movw $0x80, %ax /* EXT2_GOOD_OLD_INODE_SIZE */
+ movw %ax, %cs:0x826 /* inode size */
+ movl 0x44C, %ecx /* ECX=s_rev_level */
+ jecxz 3f /* EXT2_GOOD_OLD_REV */
+ movw 0x458, %ax /* AX=s_inode_size */
+ testw %ax, %ax
+ jz 1f /* invalid inode size */
+ pushw %ax
+ pushw %dx
+ movb 0x418, %cl /* s_log_block_size */
+ addb $10, %cl
+ xorw %dx, %dx /* DX=0 */
+ incw %dx /* DX=1 */
+ shlw %cl, %dx /* DX=block size in bytes */
+ xchgw %ax, %cx /* CX=s_inode_size */
+ xchgw %ax, %dx /* AX=block size in bytes */
+ xorw %dx, %dx /* DX:AX=block size in bytes */
+ divw %cx /* quo=AX, rem=DX */
+ testw %dx, %dx
+ popw %dx
+ popw %ax
+ jnz 1f /* invalid inode size */
+ movw %ax, %cs:0x826 /* inode size */
+3:
+ /* BX = 0 */
+
+ /* super block is sane */
+
+ //pushw %cs
+ //popw %ds
+ ///* DS=SS=0x9400 */
+ ///* ES=FS_BOOT */
+ cld
+ movw $0x800, %si
+ xorw %di, %di
+ movw $0x0200, %cx /* yes, we need 2 sectors if enable debug */
+
+ repz cs movsw /* CS segment override prefix(=0x2E) */
+
+ /* modify the boot partition number */
+
+ /* the boot partition number is at offset 0x25 for ext2 */
+
+ testb %dl, %dl
+ jns 3f /* no modification for floppy */
+ movw $0x25, %di
+ movw %cs:0x1bc, %ax /* partition number */
+ stosb
+3:
+ /* fix for ext2 partition: hidden_sectors, offset 0x1c */
+ popw %si /* DI points to old entry in MBR */
+ pushw %si
+ xorl %eax, %eax /* let hidden_sectors=0 for floppy */
+ testb %dl, %dl
+ jns 3f /* floppy */
+ movl %cs:4(%si), %eax
+ addl %cs:8(%si), %eax
+3:
+ /* BX = 0 */
+
+ movl %eax, %es:0x1c(%bx) /* adjust hidden_sectors for EXT2 */
+
+ /* fix for ext2 partition: EBIOS indicator, offset 0x02 */
+
+ movb %cs:0x00(%bx), %al
+ movb %al, %es:0x02(%bx)
+
+ /* fix for ext2 partition: sectors per block, offset 0x0d */
+ /* fix for ext2 partition: bytes per block, offset 0x0e */
+ /* fix for ext2 partition: dwords per block(dpb), offset 0x14 */
+ /* fix for ext2 partition: square of dpb, offset 0x10 */
+
+ movb %es:0x418, %cl /* s_log_block_size */
+ //incw %cx
+ movl $2, %eax
+ shlw %cl, %ax
+ movb %al, %es:0x0d(%bx)
+ shlw $9, %ax /* block size is word wide */
+ movw %ax, %es:0x0e(%bx)
+ shrw $2, %ax
+ movl %eax, %es:0x14(%bx)
+ addb $8, %cl
+ shll %cl, %eax
+ movl %eax, %es:0x10(%bx)
+
+
+ /* fix for ext2 partition: sectors per track, offset 0x18 */
+ /* fix for ext2 partition: number of heads, offset 0x1a */
+#if 1
+ pushw %ds
+ pushw %es
+ pushw %bx
+ pushw %dx
+ movb $8, %ah /* read drive parameters changes DX,ES,DI,BX */
+ movb $0x80, %dl /* BIOS drive number is in DL */
+ int $0x13
+ movw %dx, %ax
+ popw %dx
+ popw %bx
+ popw %es
+ popw %ds
+ jc 3f
+ andb $63, %cl
+ jz 3f
+ movb %cl, %es:0x18(%bx)
+ shrw $8, %ax
+ incw %ax
+ movw %ax, %es:0x1a(%bx)
+3:
+#else
+ testb %dl, %dl
+ jns 3f /* floppy */
+ popw %di /* DI points to old entry in MBR */
+ pushw %di
+ movw %cs:1(%di), %ax
+ andb $63, %ah
+ movb %ah, %es:0x18
+ xorb %ah, %ah
+ incw %ax
+ movw %ax, %es:0x1a
+3:
+#endif
+
+ /* fix for ext2 partition: s_inodes_per_group, offset 0x28 */
+ movl %es:0x428, %eax /* s_inodes_per_group */
+ movl %eax, %es:0x28(%bx)
+
+ /* fix for ext2 partition: block number for group descriptors, offset 0x2c */
+ /* At which block the group descriptors begin? */
+ movl %es:0x414, %eax /* s_first_data_block */
+ incw %ax
+ movl %eax, %es:0x2c(%bx)
+
+ /* fix for ext2 partition: on error go back to supervisor, offset 0x01fc */
+ movw $0x01fc, %si
+ movw %si, %di
+ lodsw
+ cmpw $0xFEEB, %ax /* EB FE is jmp back to itself(infinite loop) */
+ jnz 3f
+ decw %ax /* AL=0xEA, ljmp */
+ stosb
+ //movw $(try_next_partition - _start1), %ax
+ movw $MONITOR, %ax
+ stosw
+ //movw %cs, %ax /* AX=0x9400 */
+ xorw %ax, %ax
+ stosw /* the last byte 0x00 is in the next sector! */
+// addw $0x0f, %di
+// movw $(restore_GRLDR_CS - _start1), %si
+// movw $((gdt_end - restore_GRLDR_CS) / 4), %cx
+// .byte 0x2e /* %cs: prefix */
+// repz movsl
+3:
+
+ movw $(EXT2_message - _start1), %si
+ call print_message /* CS:SI points to message string */
+
+ clc
+ jmp move_entries_and_return
+
+1:
+ #; It is not EXT2. Check for FAT12/16/32/NTFS.
+
+ /* DS=ES=FS_BOOT */
+
+ cmpw $0x200, 0x0b(%si) /* bytes per sector */
+ jne 1f /* not a normal BPB */
+ movb 0x0d(%si), %al /* sectors per cluster */
+ testb %al, %al
+ jz 1f /* invalid if = 0 */
+ movb %al, %cl
+ movw $128, %ax
+ divb %cl /* quo=AL, rem=AH */
+ testb %ah, %ah
+ jnz 1f /* invalid if not 2^n */
+ movw 0x18(%si), %ax /* sectors per track */
+ testw %ax, %ax
+ jz 1f /* invalid if = 0 */
+ cmpw $63, %ax
+ ja 1f /* invalid if > 63 */
+ movw 0x1a(%si), %ax /* number of heads */
+ decw %ax /* Max head number, should be a byte */
+ testb %ah, %ah /* should be 0 */
+ jnz 1f /* invalid if number of heads > 256 */
+ cmpb $0xf0, 0x15(%si) /* media descriptor */
+ jb 1f
+
+ cmpb $0x42, %cs:0x00 /* EBIOS present? */
+ jne 3f
+ //movb $0x41, %ah /* EBIOS check existence */
+ //movw $0x55aa, %bx
+ //int $0x13
+ //jc 3f /* No EBIOS */
+ //cmpw $0xaa55, %bx
+ //jnz 3f /* No EBIOS */
+ //testb $1, %cl
+ //jz 3f /* No EBIOS */
+ movb $0x0e, 0x02(%si) /* force LBA */
+3:
+ cld
+ movw $0x0600, %bx /* FAT12/FAT16 */
+ movw $0x003c, %cx /* FAT12/FAT16 */
+
+ movb 0x10(%si), %al /* number of FATs(NTFS:0, FAT:1,2) */
+ cmpb $2, %al
+ ja 1f /* abnormal FAT */
+ movw 0x11(%si), %ax /* max root entries */
+ testw %ax, %ax
+ jnz 2f /* FAT12/FAT16 */
+
+ /* FAT32 or NTFS */
+ movw 0x13(%si), %ax /* total sectors(small) */
+ testw %ax, %ax
+ jnz 1f /* invalid FAT32 BPB */
+ movw 0x16(%si), %ax /* sectors per FAT(small) */
+ testw %ax, %ax
+ jnz 1f /* invalid FAT32 BPB */
+ movb 0x10(%si), %al /* number of FATs(NTFS:0, FAT:1,2) */
+ testb %al, %al
+ jz 8f
+
+ /* FAT32 */
+ movl 0x20(%si), %eax /* FAT32 total sectors */
+ testl %eax, %eax
+ jz 1f
+ movl 0x24(%si), %eax /* FAT32 sectors per FAT */
+ testl %eax, %eax
+ jz 1f
+ movw $0x0400, %bx /* FAT32 */
+ movw $0x0058, %cx /* FAT32 */
+ movw $(FAT32_message - _start1), %si
+ jmp 7f
+8:
+ /* NTFS */
+ movl 0x20(%si), %eax /* FAT32 total sectors */
+ testl %eax, %eax
+ jnz 1f
+ //movw 0x11(%si), %ax /* max root entries */
+ //testw %ax, %ax
+ //jnz 1f
+ movw 0x0e(%si), %ax /* reserved sectors */
+ testw %ax, %ax
+ jnz 1f
+
+ /* BUG fix for extended NTFS partition */
+ popw %si /* SI points to old entry in MBR */
+ pushw %si
+ xorl %eax, %eax /* let hidden_sectors=0 for floppy */
+ testb %dl, %dl
+ jns 3f /* floppy */
+ movl %cs:4(%si), %eax
+ addl %cs:8(%si), %eax
+3:
+ movl %eax, 0x1c /* adjust hidden_sectors for NTFS */
+
+ movb %dl, 0x24 /* adjust drive number for NTFS */
+
+#if 1
+ // Load NTFS using internal boot sector at 0xA00
+
+ movw $(NTFS5_message - _start1), %si
+ call print_message /* CS:SI points to message string */
+
+ movw $0xA00, %bx
+ movw $0x52, %cx
+
+ pushw %cs
+ popw %ds
+
+ /* DS=SS=0x9400 */
+ /* ES=FS_BOOT */
+
+ movw %bx, %si
+ xorw %di, %di
+ lodsw
+ stosw
+ addw %cx, %si
+ addw %cx, %di
+ movw $0x800, %cx
+ subw %di, %cx
+
+ repz movsb
+
+ /* modify the boot partition number */
+ movb %es:1, %al
+ addb $5, %al /* AL is less than 0x80 */
+ cbw /* AH=0 */
+ xchgw %ax, %di /* move AX to DI */
+ movb $0xff, %al /* partition=whole drive for floppy */
+ testb %dl, %dl
+ jns 3f /* no modification for floppy */
+ movb 0x1bc, %al /* partition number */
+3:
+ stosb
+
+ /* fix for NTFS partition: on error go back to supervisor, offset 0x01fa */
+
+ movw $0x01fa, %di
+ movw %es:(%di), %ax
+ cmpw $0xFEEB, %ax /* EB FE is jmp back to itself(infinite loop) */
+ jnz 3f
+ decw %ax /* AL=0xEA, ljmp */
+ stosb
+ //movw $(try_next_partition - _start1), %ax
+ movw $MONITOR, %ax
+ stosw
+
+ //movw %cs, %ax /* AX=0x9400 */
+ xorw %ax, %ax
+ stosw /* DI=0x01ff */
+3:
+ clc
+ jmp move_entries_and_return
+
+#else
+
+ /* modify the boot partition number */
+ movb $0xB6, %al /* 0xB6="MOV DH,imm8" */
+ movb %cs:0x1bc, %ah
+ testb %dl, %dl
+ js 3f
+ movb $0xff, %ah /* partition number for floppy is whole drive */
+3:
+ /* before the call:
+ * AH= partition number
+ * AL= 0xB6 ; 0xB6 is opcode of "MOV DH,imm8"
+ * DL= drive number
+ *
+ * on return: CF=0 if there is NTFS boot record;
+ * CF=1 otherwise.
+ * CF of flags_orig on the stack will set if CF=1
+ */
+
+ call modify_NTFS_boot_record
+ //jnc move_entries_and_return
+ //movw $(NTFS5_message - _start1), %si
+ ////jmp 4f
+ //call print_message /* CS:SI points to message string */
+ //stc
+ jmp move_entries_and_return
+
+#endif
+
+2:
+ /* FAT12/FAT16 */
+ movb 0x10(%si), %al /* number of FATs(NTFS:0, FAT:1,2) */
+ testb %al, %al
+ jz 1f
+ movw 0x16(%si), %ax /* sectors per FAT(small) */
+ testw %ax, %ax
+ jz 1f
+ movw $(FAT16_message - _start1), %si
+ cmpw $12, %ax
+ ja 7f
+ movw $(FAT12_message - _start1), %si
+7:
+ /* BUG fix for extended FAT12/16/32 partition */
+ popw %di /* DI points to old entry in MBR */
+ pushw %di
+ xorl %eax, %eax /* let hidden_sectors=0 for floppy */
+ testb %dl, %dl
+ jns 3f /* floppy */
+ movl %cs:4(%di), %eax
+ addl %cs:8(%di), %eax
+3:
+ movl %eax, 0x1c /* adjust hidden_sectors for FAT */
+
+ call print_message /* CS:SI points to message string */
+ pushw %cs
+ popw %ds
+ /* DS=SS=0x9400 */
+ /* ES=FS_BOOT */
+ movw %bx, %si
+ xorw %di, %di
+ lodsw
+ stosw
+ addw %cx, %si
+ addw %cx, %di
+ movw $0x0200, %cx
+ subw %di, %cx
+ repz movsb
+ /* modify the boot partition number */
+ movb %es:1, %al
+ addb $5, %al /* AL is less than 0x80 */
+ cbw /* AH=0 */
+ xchgw %ax, %di /* move AX to DI */
+ movb $0xff, %al /* partition=whole drive for floppy */
+ testb %dl, %dl
+ jns 3f /* no modification for floppy */
+ movb 0x1bc, %al /* partition number */
+3:
+ stosb
+
+ /* fix for FAT12/16/32 partition: on error go back to supervisor, offset 0x01fa */
+ //pushw %es
+ //popw %ds
+ movw $0x01fa, %di
+ //movw %di, %si
+ //lodsw
+ movw %es:(%di), %ax
+ cmpw $0xFEEB, %ax /* EB FE is jmp back to itself(infinite loop) */
+ jnz 3f
+ decw %ax /* AL=0xEA, ljmp */
+ stosb
+ //movw $(try_next_partition - _start1), %ax
+ movw $MONITOR, %ax
+ stosw
+ //movw %cs, %ax /* AX=0x9400 */
+ xorw %ax, %ax
+ stosw /* DI=0x01ff */
+3:
+
+ clc
+ jmp move_entries_and_return
+1:
+ #; It is not FAT12/16/32/NTFS. Check for extended partition.
+
+ /* DS=ES=FS_BOOT */
+
+ pushw %cs
+ popw %es
+
+ /* ES=SS=0x9400 */
+ /* DS=FS_BOOT */
+
+ popw %si
+ pushw %si
+ cmpb $0x05, %es:(%si) /* extended */
+ je 1f
+ cmpb $0x0f, %es:(%si) /* Win95 extended (LBA) */
+ je 1f
+ cmpb $0x15, %es:(%si) /* hidden extended */
+ je 1f
+ cmpb $0x1f, %es:(%si) /* hidden win95 extended (LBA) */
+ je 1f
+ cmpb $0x85, %es:(%si) /* Linux extended */
+ je 1f
+ movw $(non_MS_message - _start1), %si
+4:
+ call print_message /* CS:SI points to message string */
+ stc
+ jmp move_entries_and_return
+1:
+ /* extended partition entry */
+ cmpw $0x1fe, %si
+ jb 1f
+ decw %es:0x1bc /* count the partitions in extended zone */
+1:
+ movw $(extended_message - _start1), %si
+ call print_message /* CS:SI points to message string */
+ movw $0x1be, %si
+ movw $4, %cx
+5:
+ //xorl %eax, %eax
+ //cmpl %eax, (%si)
+ //jnz 2f
+ movl (%si), %eax
+ cmpw 2(%si), %ax /* Is EAX high word equal to AX? */
+ jnz 2f
+ cmpb %al, %ah /* Is AL=AH? */
+ jnz 2f
+
+ /* now all 4 bytes in EAX are equal to each other. */
+ cmpl %eax, 4(%si)
+ jnz 2f
+ cmpl %eax, 8(%si)
+ jnz 2f
+ cmpl %eax, 12(%si)
+ jz 3f /* entry with 16 dups of a byte means empty entry */
+2:
+ movb (%si), %al
+ shlb $1, %al
+ jnz 1f
+ //jnz 3f /* invalid entry is treated as empty entry */
+ movb 2(%si), %al
+ and $63, %al /* starting sector number */
+ jz 1f
+ //jz 3f /* invalid entry is treated as empty entry */
+ movb 6(%si), %al
+ and $63, %al /* ending sector number */
+ jz 1f
+ //jz 3f /* invalid entry is treated as empty entry */
+ movl 8(%si), %eax /* starting LBA */
+ testl %eax, %eax
+ jz 1f
+ //jz 3f /* invalid entry is treated as empty entry */
+ movl 12(%si), %eax /* total number of sectors in partition */
+ testl %eax, %eax
+ jz 1f
+3:
+ addw $16, %si
+ loop 5b
+ cmpw $0xaa55, (%si)
+ jnz 1f
+
+ movw $0x1be, %si
+ movw $4, %cx
+ popw %bx /* the old SI points to extended partition ID in MBR */
+ pushw %bx
+5:
+#if 1
+ //xorl %eax, %eax
+ //cmpl %eax, (%si)
+ //jnz 2f
+ movl (%si), %eax
+ cmpw 2(%si), %ax /* Is EAX high word equal to AX? */
+ jnz 2f
+ cmpb %al, %ah /* Is AL=AH? */
+ jnz 2f
+
+ /* now all 4 bytes in EAX are equal to each other. */
+ cmpl %eax, 4(%si)
+ jnz 2f
+ cmpl %eax, 8(%si)
+ jnz 2f
+ cmpl %eax, 12(%si)
+ jz 3f /* entry with 16 dups of a byte means empty entry */
+2:
+ /* now it is an acceptable entry */
+ movw %es:0x1ba, %di /* partition entries end */
+ /* ensure our stack not to be overwritten by the partition entries */
+ cmpw $0x83f0, %di
+ ja 3f /* try next */
+ /* ensure our code not to be overwritten by the partition entries */
+ cmpw $0x3fe, %di
+ jne 6f
+ /* more entries stores at 0x9be00-0x9c3ff */
+ movw $0x7e00, %di
+ movw %di, %es:0x1ba
+6:
+ addw $16, %es:0x1ba /* increment partition entries end */
+
+ lodsl
+ stosl
+ lodsl
+ stosl
+
+ xchgw %ax, %dx /* save AL(the partition ID)to DL */
+
+ lodsl
+ xchgl %eax, %edx /* restore AL from DL(the partition ID)
+ * and save EAX to EDX */
+ cmpb $0x05, %al
+ je 6f
+ cmpb $0x0f, %al
+ je 6f
+ cmpb $0x15, %al
+ je 6f
+ cmpb $0x1f, %al
+ je 6f
+ cmpb $0x85, %al
+ je 6f
+ /* normal partition, copied to 0x941fe-0x943fb */
+ addl %es:4(%bx), %edx /* current partition start */
+6:
+ /* extended partition, copied to 0x941fe-0x943fb */
+ xchgl %eax, %edx /* restore or update EAX from EDX */
+ stosl
+ lodsl /* adjust SI only */
+ movl %es:8(%bx), %eax /* parent partition start ... */
+ stosl /* ... stored here */
+ jmp 2f
+3:
+ addw $16, %si
+#endif
+ //. = 5b + 0x7c
+2:
+ loop 5b
+
+ /* extended partition is not a normal one, so set carry to try next */
+ stc
+ jmp move_entries_and_return
+
+invalid_or_null:
+1:
+ movw $(invalid_message - _start1), %si
+ call print_message /* CS:SI points to message string */
+ stc
+
+move_entries_and_return:
+ popw %si
+ pushfw
+ pushw %cs
+ popw %ds
+ pushw %cs
+ popw %es
+ pushw %si
+ cmpw $0x202, %si
+ jne 1f
+ /* move entries backward 1 entry */
+ movw $0x1fe, %di
+ movw $0x20e, %si
+ movw $0xf8, %cx /* 0x1f0 bytes = 0xf8 words */
+ cld /* move upward */
+ repz movsw
+ movw $0x3ee, %di
+ movw $0x7e00, %si
+ movw $0x8, %cx /* 0x10 bytes = 0x8 words */
+ cld /* move upward */
+ repz movsw
+ movw $0x7e00, %di
+ movw $0x7e10, %si
+ movw $0x2f8, %cx /* 0x5f0 bytes = 0x2f8 words */
+ cld /* move upward */
+ repz movsw
+ cmpw $0x7e10, 0x1ba
+ jne 2f
+ movw $0x40e, 0x1ba
+2:
+ subw $0x10, 0x1ba
+
+1:
+ popw %si
+ movw $0x1ff, (add_sub_si + 5 - _start1)
+ cmpw $0x1fe, 0x1ba
+ jne 1f
+ decw (add_sub_si + 5 - _start1)
+ cmpw $0x31b2, %si /* floppy? */
+ je 1f /* yes */
+ cmpw $0x1f2, %si
+ ja 2f /* logical partition */
+ jb 1f /* primary partition 0, 1, 2 */
+ /* primary partition 3 */
+ cmpw $0x0003, 0x1bc /* are there any logical partitions? */
+ ja 1f /* yes */
+2:
+inc_hard_drive:
+
+ /* all partitions on the drive have been checked, try next drive.
+ *
+ * the current stack is:
+ *
+ * SP + 38 : DS
+ * SP + 36 : ES
+ * SP + 32 : EAX
+ * SP + 28 : ECX
+ * SP + 24 : EDX
+ * SP + 20 : EBX
+ * SP + 16 : ESP_temp
+ * SP + 12 : EBP
+ * SP + 8 : ESI
+ * SP + 4 : EDI
+ * SP + 2 : flags_orig
+ * SP : flags
+ *
+ */
+
+ /* get total hard drives */
+ xorw %ax, %ax
+ movw %ax, %ds
+ movb 0x475, %dh
+ pushw %cs
+ popw %ds
+// cmpb $16, %dh
+// jnb 2f
+// movb $16, %dh
+//2:
+ orb $0x80, %dh /* CF=0, DH=Max harddrive number + 1 */
+ //xchgw %ax, %cx /* CL=Max harddrive number + 1, CH=0 */
+ movw %sp, %bp
+ movb 24(%bp), %dl /* BIOS drive number is in DL */
+2:
+ jnc 3f
+ call print_message /* CS:SI points to message string */
+ movw $(drive_number_string - _start1), %si
+ movb %dl, %al
+ andb $0x7f, %al
+ aam /* AH=high decimal, AL=low decimal */
+ addw $0x3030, %ax
+ xchgb %al, %ah
+ movw %ax, 9(%si)
+ call print_message /* CS:SI points to message string */
+3:
+ incw %dx
+ cmpb %dh, %dl
+ jnb 2f /* all drives checked, try floppy finally */
+
+ pushw %bx
+ pushw %dx
+ pushw %es
+ movb $8, %ah /* read drive parameters changes DX, ES, DI */
+ int $0x13
+ popw %es
+ jc 3f /* try next hard drive */
+ //xchgw %ax, %cx /* this moves CL to AL */
+ andb $63, %cl /* CL=sectors per track, CF cleared */
+ stc
+ jz 3f /* try next hard drive */
+ popw %dx /* get DL */
+ popw %bx
+ movb %dl, %ch /* DL saved at BP high byte in the stack */
+ pushw %cx /* push new BX onto stack */
+ pushw %dx
+ //movb $0x02, %ah
+ //movw %ax, %si /* save AX to SI: read 1 track */
+ movw $0x201, %ax /* read 1 sector */
+ movw $0x7e00, %bx /* read MBR to 9400:7e00 */
+ movw $1, %cx
+ //popw %dx
+ //pushw %dx
+ xorb %dh, %dh
+ stc
+ int $0x13
+ sti
+3:
+ popw %dx
+ popw %bx /* BL=sectors per track, BH=DL */
+
+ //movw %si, %bx /* BL=sectors per track */
+
+ movw $(Error_while_reading_string - _start1), %si
+ jc 2b /* read failure, try next hard drive */
+
+ /* on seccessful return, should be: ah=0 for OK, al=1 for 1 sector */
+ //decw %ax /* some BIOSes return incorrect AL */
+ testb %ah, %ah
+ stc
+ jnz 2b
+
+ /* The new partition table might be empty or invalid.
+ * Move the new partition table onto the old one while checking
+ */
+
+ //movb %dl, %bh /* DL saved at BP high byte in the stack */
+
+ movw $0x7fbe, %si
+ movw $0x01be, %di
+
+3:
+ cmpw $0x1fe, %di
+ jnb 3f
+
+ xorl %ecx, %ecx
+
+ lodsl
+ stosl
+ orl %eax, %ecx
+ lodsl
+ stosl
+ orl %eax, %ecx
+ lodsl
+ stosl
+ orl %eax, %ecx
+ lodsl
+ stosl
+ orl %eax, %ecx
+ jecxz 3b /* null entry, check next */
+
+ //lodsw
+ //stosw
+ movb -16(%si), %al
+ shlb $1, %al
+ stc
+ xchgw %ax, %si /* save SI to AX */
+ movw $(partition_boot_indicator_string - _start1), %si
+ jnz 2b
+ xchgw %ax, %si /* restore SI from AX */
+ //lodsw
+ //stosw
+ movb -14(%si), %al
+ andb $63, %al
+ stc
+ xchgw %ax, %si /* save SI to AX */
+ movw $(partition_sectors_per_track_string - _start1), %si
+ jz 2b
+ xchgw %ax, %si /* restore SI from AX */
+ //lodsw
+ //stosw
+ //lodsw
+ //stosw
+ movb -10(%si), %al
+ andb $63, %al
+ stc
+ xchgw %ax, %si /* save SI to AX */
+ movw $(partition_sectors_per_track_string - _start1), %si
+ jz 2b
+ xchgw %ax, %si /* restore SI from AX */
+ //lodsl
+ //stosl
+ movl -8(%si), %eax
+ testl %eax, %eax
+ stc
+ xchgw %ax, %si /* save SI to AX */
+ movw $(partition_start_sector_string - _start1), %si
+ jz 2b
+ xchgw %ax, %si /* restore SI from AX */
+
+ //lodsl
+ //stosl
+ movl -4(%si), %eax
+ testl %eax, %eax
+ stc
+ xchgw %ax, %si /* save SI to AX */
+ movw $(partition_end_sector_string - _start1), %si
+ jz 2b
+ xchgw %ax, %si /* restore SI from AX */
+
+ jmp 3b
+3:
+ cmpw $0xAA55, (%si)
+ stc
+ xchgw %ax, %si /* save SI to AX */
+ movw $(no_boot_signature_string - _start1), %si
+ jnz 2b
+ xchgw %ax, %si /* restore SI from AX */
+ //lodsw
+ //stosw /* store boot signature */
+
+ /* Now the partition table is OK */
+
+ movw %bx, 12(%bp) /* adjust BP in the stack */
+
+ movw $0x1b2, 8(%bp) /* adjust SI in the stack */
+
+ /* temp change the code: call self_modify_once
+ *
+ * "call self_modify_once" at add_sub_si is:
+ *
+ * .byte 0xE8
+ * .word (self_modify_once - add_sub_si - 3)
+ *
+ */
+ movb $0xE8, (add_sub_si - _start1)
+ movw $(self_modify_once - add_sub_si - 3), (add_sub_si + 1 - _start1)
+
+ /* initialize partition number and partition entries end */
+ movw $0xffff, 0x1bc /* hd partition number */
+ movw $0x01fe, 0x1ba /* partition entries end */
+
+ jmp 1f
+2:
+ /* get here if all drives have been checked */
+#if 0
+ movw $0x202, 8(%bp) /* adjust SI in the stack */
+
+ /* restore the original code: addw $-4, %si */
+ movw $0xC683, (add_sub_si - _start1) /* 0x83, 0xC6 */
+ movb $0xFC, (add_sub_si + 2 - _start1) /* 0xFC */
+#endif
+ //--------------------------------------------------------------------
+ /* change the code: jmp Error_modify
+ *
+ * "jmp Error_modify" at Error_or_prev_MBR:
+ *
+ * .byte 0xE9
+ * .word (Error_modify - Error_or_prev_MBR - 3)
+ *
+ */
+ movb $0xE9, (Error_or_prev_MBR - _start1)
+ movw $(Error_modify - Error_or_prev_MBR - 3), (Error_or_prev_MBR + 1 - _start1)
+ //--------------------------------------------------------------------
+
+ //--------------------------------------------------------------------
+ /* floppy search disabled ? */
+#if 0
+ testb $1, 0x02 /* test bit0 of the third byte */
+ jz 1f /* zero means floppy search enabled */
+ /* 0x1fd or below means disable floppy search */
+ decw (add_sub_si + 5 - _start1)
+#else
+ movb 0x02, %al
+ andb $0x01, %al
+ subb %al, (add_sub_si + 5 - _start1)
+#endif
+ //--------------------------------------------------------------------
+
+1:
+#if 0
+ popfw
+ lahf /* Load Flags into AH Register. */
+ /* AH = SF:ZF:xx:AF:xx:PF:xx:CF */
+ /* CF will be moved to ZF */
+ movb %ah, %al
+ andb $1, %al /* CF=0 */
+ shlb $6, %al /* move CF to ZF */
+ popfw
+ lahf /* Load Flags into AH Register. */
+ /* AH = SF:ZF:xx:AF:xx:PF:xx:CF */
+ andb $0xbf, %ah /* 0xbf= binary 1011 1111. It clears ZF */
+ orb %al, %ah
+#else
+ popw %ax /* AX=Flags */
+ popfw /* Flags_orig */
+ lahf /* Load Flags_orig into AH Register. */
+ /* AH = SF:ZF:xx:AF:xx:PF:xx:CF */
+ shlb $2, %ah
+ rorw $2, %ax /* move CF of Flags to ZF of Flags_orig */
+#endif
+
+ sahf /* update flags */
+ /* current CF is the CF of Flags_orig */
+ /* current ZF is the CF of Flags */
+ jc 1f /* CF=1 means failed in loading bootsector */
+ popal /* get drive number DL */
+ pushal
+ pushfw
+ cmpb $0xff, %cs:0x06
+ jz 2f
+ movb %cs:0x1bc, %dh
+ testb %dl, %dl
+ js 3f
+ movb $0xff, %dh /* partition # for floppy is "whole drive" */
+3:
+ cmpw %cs:0x06, %dx
+ jz 2f
+ popfw
+ stc
+ pushfw
+2:
+ popfw
+1:
+ popal
+ popw %es
+ popw %ds
+ ret
+
+self_modify_once:
+ /* when we get here, SI should be 0x1b2, and BP high holds DL */
+ addw $12, %si /* 0x83, 0xC6, 0x0C */
+ movw %bp, %ax
+ movb %ah, %dl
+
+ /* note: DS=0x9400 */
+
+ /* restore the original code: addw $12, %si */
+ movw $0xC683, (add_sub_si - _start1) /* 0x83, 0xC6 */
+ movb $0x0C, (add_sub_si + 2 - _start1) /* 0x0C */
+ ret
+
+Error_modify:
+ cmpb $0xff, %cs:0x06 /* preferred drive? */
+ jz 1f /* not active. Turn to the final step. */
+
+ /* preferred drive is already handled, so de-activate it now. */
+ movb $0xff, %cs:0x06
+
+ /* we will do the second pass, from drive 0x80. */
+ movb $0x7f, %dl /* this will become 0x80 after inc. */
+
+ /* pass "error" to PUSHF, simulating a load failure, in order
+ * to try the first entry after return from the helper function.
+ */
+
+ stc
+
+ pushw $(helper_call + 3 - _start1) /* return address */
+ pushw %cs /* 0x9400, it is for DS. */
+ pushw $FS_BOOT /* 0x0d00, it is for ES. */
+ pushal
+ //pushl %eax
+ //pushl %ecx
+ //pushl %edx
+ //pushl %ebx
+ //pushl %esp
+ //pushl %ebp
+ //pushl %esi
+ //pushl %edi
+ pushfw /* CF=1 */
+ pushfw
+
+ pushw %cs
+ popw %es /* ES=0x9400 */
+
+ /* redo from start: DL will be 0x80 after inc. */
+ jmp inc_hard_drive
+1:
+boot_prev_mbr:
+
+ /* prepare to boot the previous MBR */
+
+ /* at this moment DS=0x9400, ES=$FS_BOOT or ES=0x9400 */
+ xorw %ax, %ax
+ //pushw %ax /* AX=0, for the segment of 0000:7c00 */
+ movw %ax, %es /* ES=0x0000 */
+ movw %ax, %ds /* DS=0x0000 */
+ pushw %ds
+ pushw %es
+ movw $0x0202, %ax /* read 2 sectors ... */
+ movw $0x7A00, %bx /* ... to 0000:7A00 */
+ //pushw %bx /* BX=0x7c00, for the offset of 0000:7c00 */
+ movw $0x0001, %cx /* from the first sector ... */
+ movw $0x0080, %dx /* ... of the first hard drive */
+ stc
+ int $0x13
+ sti
+ popw %es
+ popw %ds
+ jc 1f
+ testb %ah, %ah
+ jnz 1f
+ cmpw $0xAA55, 0x7dfe
+ jne 1f
+ cmpw $0xAA55, 0x7bfe
+ jne 1f
+
+ /* has a valid partition table ? */
+ movw $0x7dbe, %si
+3:
+ cmpw $0x7dfe, %si
+ jnb 3f /* partition table is OK */
+ movw $4, %cx
+
+ movw %si, %di
+2:
+ lodsl
+ negl %eax
+ jc 2f
+ loop 2b
+ /* empty entry, check next */
+ jmp 3b
+2:
+ /* non-empty entry */
+ movw %di, %si
+
+ lodsw
+ shlb $1, %al
+ jnz 2f
+ lodsw
+ andb $63, %al
+ jz 2f
+ lodsw
+ lodsw
+ andb $63, %al
+ jz 2f
+ lodsl
+ negl %eax
+ jnc 2f
+ lodsl
+ negl %eax
+ jc 3b
+2:
+ stc /* invalid partition table */
+3:
+ pushfw
+
+ /* disable the boot of non-MBR bootsector ? */
+ testb $2, %cs:0x02 /* test bit1 of the third byte */
+ jz 2f /* zero means non-MBR enabled */
+ popfw
+ jc 1f /* invalid partition table, print "Error" */
+
+ /* the partition table is valid */
+ pushfw
+
+2:
+ /* the check passed, and the boot is permitted */
+ popfw
+
+ jc 2f /* invalid partition table */
+
+ /* use partition table in MBR instead */
+
+ /* copy 72 bytes at 0000:7bb8 to 0000:7db8 */
+
+ movw $0x7bb8, %si
+ movw $0x7db8, %di
+ movw $36, %cx
+ cld
+ repz movsw
+
+2:
+ testb $0x80, %cs:0x02 /* test bit 7 of the third byte */
+ jz 2f /* zero means boot prev-MBR first */
+
+ movw $(Cannot_find_GRLDR_string - _start1), %si
+ call print_message /* CS:SI points to message string */
+//#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+ movw $(press_space_bar_string - _start1), %si
+ cmpw $0x3920, %cs:0x04
+ je 3f
+ movw $0x3920, %cs:0x04
+ #;movw $(press_hot_key_string - _start1), %si
+3:
+ call print_message /* CS:SI points to message string */
+ movw $(prev_MBR_string - _start1), %si
+ call print_message /* CS:SI points to message string */
+//#else
+// movw $(press_hot_key_pre - _start1), %si
+// call print_message
+// movw $(press_hot_key_name - _start1), %si
+// call print_message
+// movw $(press_hot_key_sub - _start1), %si
+// call print_message
+//#endif
+3:
+ call sleep_5_seconds
+ /* if hot-key is pressed, wait forever until another key is pressed. */
+ movb $0xff, %cs:0x03
+ jc 3b /* desired hot-key is pressed */
+2:
+ /* boot the previous MBR */
+
+ /* clear the DUCE indicator */
+ movl $0, 0x5FC /* DS=ES=0 */
+
+ //movb $0x80, %dl
+ ljmp $0, $0x7c00
+1:
+ /* no previous MBR, print "Error" */
+ ///* Note the 0000:7C00 is on the stack */
+ //popw %ax /* AX=0x0000 */
+ //popw %ax /* AX=0x7C00 */
+
+ testb $0x80, %cs:0x02 /* are we called prior to the GRLDR search? */
+ jnz 1f /* no, it is a failure at last */
+ /* yes, so return to the caller */
+ movw $(continue_string - _start1), %si
+ call print_message /* CS:SI points to message string */
+ call sleep_5_seconds
+ ret
+1:
+ movw $(message_string_helper - _start1), %si
+ call print_message /* CS:SI points to message string */
+1: jmp 1b /* hang */
+
+sleep_5_seconds:
+ /* sleep 5 seconds */
+
+ /* sleep forever if %cs:0x03 is 0xff */
+
+ /* calculate the timeout ticks */
+
+ pushw %ds
+ pushl %esi
+ pushl %edx
+
+ movl $0xffffffff, %edx
+ movzbl %cs:0x03, %eax
+ cmpb $0xff, %al
+ je 1f
+ movl $18, %edx /* 18.2 ticks per second. We simply use 18. */
+ mulw %dx /* EDX=0, EAX=ticks */
+ xchgw %ax, %dx /* EAX=0, EDX=ticks */
+1:
+ xorw %ax, %ax
+ movw %ax, %ds
+ movl 0x46c, %eax /* initial tick */
+ movl %eax, %ecx /* ECX=initial tick */
+ testl %edx, %edx
+ js 1f
+ addl %edx, %eax /* EAX=timeout tick */
+ pushl %eax
+
+ movzbl %cs:0x03, %eax
+ orl %eax, %eax
+ jz 3f
+
+ movw $(hot_key_timeout_pre - _start1), %si
+ pushl %eax
+ call print_message
+ popl %eax
+
+ movw $(hot_key_timeout_num - _start1), %si
+ call print_decimal
+3:
+ movl %ecx, %esi
+ addl $18, %esi
+
+ popl %eax
+ jmp 3f
+1:
+ movl %edx, %eax /* EAX=0xffffffff */
+ movl %edx, %esi
+3:
+ movl 0x46c, %ebx /* EBX=current tick */
+ cmpl %ecx, %ebx
+ jnb 2f
+
+ /* current tick is less than initial tick, this means the ticks have
+ * overflowed to the next day, and EBX is rather small. */
+ xorl %ecx, %ecx
+ movl %edx, %eax
+ movl $18, %esi
+2:
+ /* check if there is any key press. */
+ pushl %eax
+ movb $1, %ah
+ int $0x16
+ pushw %ax
+ pushfw
+
+ movb $0x11, %ah
+ int $0x16
+ jnz 1f
+ popfw
+ jnz 2f
+
+ /* no, there is no key press. */
+
+ popw %ax
+ popl %eax
+
+ cmpl %esi, %ebx
+ jb 4f
+ pushl %esi
+ pushl %eax
+ pushl %edx
+
+
+ subl %esi, %eax
+ xorl %edx, %edx
+ movl $18, %esi
+ divl %esi
+
+ movw $(hot_key_timeout_num - _start1), %si
+ pushl %ebx
+ call print_decimal
+ popl %ebx
+
+ popl %edx
+ popl %eax
+ popl %esi
+ addl $18, %esi
+4:
+ cmpl %eax, %ebx /* timeout? */
+ jbe 3b /* no, continue to wait */
+
+ /* timeout reached, CF=0, no key pressed. */
+ popl %edx
+ popl %esi
+ popw %ds
+ ret
+1:
+ popfw
+2:
+ /* yes, there is a key press. */
+#if 0
+ /* clear the keyboard buffer */
+ movb $1, %ah
+ int $0x16
+ jz 1f /* no keys, end */
+ movb $0, %ah
+ int $0x16 /* discard the key */
+ jmp 1b
+1:
+#endif
+
+ /* check if it is the desired key. */
+
+ xorw %cs:0x04, %ax /* CF=0 */
+ popw %ax
+ je 1f
+ xorw %cs:0x04, %ax /* CF=0 */
+ jne 2f /* not desired, return CF=0 */
+
+ /* remove the desired key from the keyboard buffer. */
+
+ movb $0, %ah
+ int $0x16 /* discard the key */
+ jmp 3f
+1:
+ /* remove the desired key from the keyboard buffer. */
+
+ movb $0x10, %ah
+ int $0x16 /* discard the key */
+3:
+ stc /* CF=1, the desired key pressed */
+2:
+ popl %eax
+ popl %edx
+ popl %esi
+ popw %ds
+ ret
+
+out_decimal:
+ /*
+ * input: EAX = number, CS:SI = buffer
+ */
+
+ pushl %edx
+ pushl %ecx
+ pushw %bx
+
+ movl $10, %ecx
+ movw %si, %bx
+
+1:
+ xorl %edx, %edx
+ divl %ecx
+ addb $'0', %dl
+ movb %dl, %cs:(%si)
+ incw %si
+ orl %eax, %eax
+ jnz 1b
+
+ pushw %si
+
+1:
+ decw %si
+ cmpw %bx, %si
+ jbe 1f
+ movb %cs:(%si), %al
+ xchgb %al, %cs:(%bx)
+ movb %al, %cs:(%si)
+ incw %bx
+ jmp 1b
+1:
+
+ popw %si
+
+ popw %bx
+ popl %ecx
+ popl %edx
+ ret
+
+print_decimal:
+ pushw %si
+ call out_decimal
+
+1:
+ cmpb $'\b', %cs:(%si)
+ jz 2f
+ movb $' ', %cs:(%si)
+ incw %si
+ jmp 1b
+2:
+ popw %si
+ call print_message
+ ret
+
+#if 0
+modify_NTFS_boot_record:
+
+ /* before the call:
+ * AH= partition number
+ * AL= 0xB6 ; 0xB6 is opcode of "MOV DH,imm8"
+ * DL= drive number
+ *
+ * on return: CF=0 if there is NTFS boot record;
+ * CF=1 otherwise.
+ * CF of flags_orig on the stack will set if CF=1
+ */
+
+ /*
+ *
+ * the current stack is:
+ *
+ * SP + 40 : DS
+ * SP + 38 : ES
+ * SP + 34 : EAX
+ * SP + 30 : ECX
+ * SP + 26 : EDX
+ * SP + 22 : EBX
+ * SP + 18 : ESP_temp
+ * SP + 14 : EBP
+ * SP + 10 : ESI
+ * SP + 6 : EDI
+ * SP + 4 : flags_orig
+ * SP + 2 : SI ; SI points to old entry in MBR
+ * SP : return_IP
+ *
+ */
+
+ /* DS=ES=FS_BOOT */
+
+ /* change NTLDR to GRLDR */
+
+ /* check GR or NT or anything else */
+
+ pushw %ax
+
+ movw $0x200, %si
+ lodsw
+ cmpw $5, %ax
+ jne 1f /* failure */
+ lodsw
+ testb %ah, %ah /* high byte of unicode ASCII should be 0 */
+ jne 1f /* failure */
+
+ /* 'N' should be a capital letter */
+
+ cmpb $0x41, %al /* Less than 'A' */
+ jb 1f /* failure */
+ cmpb $0x5A, %al /* Greater than 'Z'*/
+ ja 1f /* failure */
+
+ xchgw %ax, %cx /* save AX to CX. CL='N' */
+
+ lodsw
+ testb %ah, %ah /* high byte of unicode ASCII should be 0 */
+ jne 1f /* failure */
+
+ /* 'T' should be a capital letter */
+
+ cmpb $0x41, %al /* Less than 'A' */
+ jb 1f /* failure */
+ cmpb $0x5A, %al /* Greater than 'Z'*/
+ ja 1f /* failure */
+
+ movb %al, %ch /* save AL to CH. CH='T' */
+
+ lodsw
+ cmpw $0x4C, %ax /* 'L' */
+ jne 1f /* failure */
+ lodsw
+ cmpw $0x44, %ax /* 'D' */
+ jne 1f /* failure */
+ lodsw
+ cmpw $0x52, %ax /* 'R' */
+ jne 1f /* failure */
+ lodsw
+ cmpw $0x04, %ax /* length of "$I30" */
+ jne 1f /* failure */
+ lodsw
+ cmpw $0x24, %ax /* '$' */
+ jne 1f /* failure */
+ lodsw
+ cmpw $0x49, %ax /* 'I' */
+ jne 1f /* failure */
+ lodsw
+ cmpw $0x33, %ax /* '3' */
+ jne 1f /* failure */
+ lodsw
+ cmpw $0x30, %ax /* '0' */
+ jne 1f /* failure */
+
+
+ /* assume it is NT bootsector. first, find "NTLDR". CX holds "NT" */
+ movw $0x0100, %di
+ movb %cl, %al /* AL="N" */
+ movb $1, %ah /* AH=Carry for SAHF below */
+ movl $0x52444c00, %ebx /* "LDR" */
+ movb %ch, %bl /* 'T' */
+ movw $0x00fa, %cx
+
+ /* now AL holds 'N' and BL holds 'T' */
+
+ //cld /* already upward */
+3:
+ repnz scasb /* find "N" */
+ jcxz 4f /* gets the end, exit */
+ cmpl %ebx, (%di) /* is it "NTLDR"? */
+ jnz 3b /* no, continue to find */
+
+ /* "NTLDR" is found, so we believe it is NT boot sector. */
+
+ movw $0x5247, -1(%di) /* change "NT" to "GR" */
+
+ /* CF=0 for now */
+
+ lahf /* Load Flags into AH */
+ /* AH = SF:ZF:xx:AF:xx:PF:xx:CF */
+ /* AH = binary xxxxxxx0 */
+ jmp 3b
+4:
+ sahf /* Store AH into flags SF ZF xx AF xx PF xx CF */
+
+ /* CF=0 means "NTLDR" is found, CF=1 means "NTLDR" is not found. */
+
+ jc 1f /* failure */
+
+ movl $0x00520047, 0x202 /* change to "G R L D R" */
+
+ /* check NT 4.0 */
+
+ movw $0x406, %si
+ movl (%si), %ebx /* NT 4.0 */
+ cmpl $0x03E8B800, %ebx /* MOV AX, 03E8 */
+ jnz 3f
+
+ movl 0x84, %ebx
+ cmpl $0x680007E8, %ebx /* call 008e; push (0D00) */
+ jnz 3f
+
+// movw 0x154, %bx /* CR LF at end of "A disk read error occurred." */
+// cmpw $0x0A0D, %bx /* CR LF */
+// jnz 3f
+// movw 0x180, %bx /* CR LF at end of "A kernel file is missing from the disk." */
+// cmpw $0x0A0D, %bx /* CR LF */
+// jnz 3f
+// movw 0x1A8, %bx /* CR LF at end of "A kernel file is too discontiguous." */
+// cmpw $0x0A0D, %bx /* CR LF */
+// jnz 3f
+// movw 0x1F8, %bx /* CR LF at end of "NTLDR is compressed." */
+// cmpw $0x0A0D, %bx /* CR LF */
+// jnz 3f
+
+ movl 0xE8, %ebx
+ cmpl $0x13CD80B2, %ebx /* "B2 80"="mov DL, 80", "CD 13"="int 13" */
+ jnz 3f
+
+ popw %ax
+ movw %ax, 4(%si)
+
+ movl $0x68909090, %ebx /* nop;nop;nop;push (0D00) */
+ movl %ebx, 0x84
+
+// /* change CRLF in NTFS error messages to spaces */
+// movw $0x2020, %bx /* change CRLF to 2 spaces */
+// movw %bx, 0x154
+// movw %bx, 0x180
+// movw %bx, 0x1A8
+// movw %bx, 0x1F8
+
+ movb %dl, 0xE9 /* modify drive number */
+
+ /* modify NTFS boot record */
+ movb $0xea, %al /* ljmp, hand over the control to supervisor */
+ movb %al, 0x122
+ //movw $(try_next_partition - _start1), %ax /* offset for ljmp */
+ movw $MONITOR, %ax /* offset for ljmp */
+ movw %ax, 0x123
+ //movw %cs, %ax /* AX=0x9400, segment for ljmp */
+ xorw %ax, %ax
+ movw %ax, 0x125
+
+ movw $(NTFS4_message - _start1), %si
+ call print_message /* CS:SI points to message string */
+ clc
+ ret
+3:
+ /* check NT 5.0 */
+
+ movw $0x44b, %si
+ movl (%si), %ebx /* NT 5.0 */
+ cmpl $0x03E8B800, %ebx /* MOV AX, 03E8 */
+ jz 2f
+
+ movw $0x479, %si
+ movl (%si), %ebx /* NT 5.1 SP2 */
+ cmpl $0x03E8B800, %ebx /* MOV AX, 03E8 */
+ jnz 1f
+2:
+ movl 0x71, %ebx
+ cmpl $0x680053E8, %ebx /* call 00C7; push (0D00) */
+ jnz 1f
+
+ //movw 0x183, %bx /* CR LF at begin of "A disk read error occurred." */
+ movb 0x1F8, %bl
+ movb $1, %bh
+ movw (%bx), %bx
+ cmpw $0x0A0D, %bx /* CR LF */
+ jnz 1f
+ //movw 0x1A0, %bx /* CR LF at begin of "NTLDR is missing." */
+ movb 0x1F9, %bl
+ movb $1, %bh
+ movw (%bx), %bx
+ cmpw $0x0A0D, %bx /* CR LF */
+ jnz 1f
+ //movw 0x1B3, %bx /* CR LF at begin of "NTLDR is compressed." */
+ movb 0x1FA, %bl
+ movb $1, %bh
+ movw (%bx), %bx
+ cmpw $0x0A0D, %bx /* CR LF */
+ jnz 1f
+
+ popw %ax
+ movw %ax, 4(%si)
+
+ movl $0x68909090, %ebx /* nop;nop;nop;push (0D00) */
+ movl %ebx, 0x71
+
+ /* change CRLF in NTFS error messages to spaces */
+ movw $0x2020, %ax
+ movb 0x1F8, %bl
+ movb $1, %bh
+ movw %ax, (%bx) // 0x183
+ movb 0x1F9, %bl
+ movb $1, %bh
+ movw %ax, (%bx) // 0x1A0
+ movb 0x1FA, %bl
+ movb $1, %bh
+ movw %ax, (%bx) // 0x1B3
+
+ /* modify NTFS boot record */
+ movb $0xEA, %al /* ljmp, hand over the control to supervisor */
+ movb %al, 0x167
+ //movw $(try_next_partition - _start1), %ax /* offset for ljmp */
+ movw $MONITOR, %ax /* offset for ljmp */
+ movw %ax, 0x168
+ //movw %cs, %ax /* AX=0x9400, segment for ljmp */
+ xorw %ax, %ax
+ movw %ax, 0x16A
+
+ cmpw $0x44b, %si
+ jne 2f
+ movw $(NTFS5_message - _start1), %si
+ jmp 3f
+2:
+ movw $(NTFS5p_message - _start1), %si
+3:
+ call print_message /* CS:SI points to message string */
+ clc
+ ret
+1:
+ /* NTFS boot record not found. */
+
+ movw $(NTFS_no_boot_record_message - _start1), %si
+ call print_message /* CS:SI points to message string */
+
+ popw %ax
+ popl %eax /* return_IP and SI */
+ popfw
+ stc
+ pushfw
+ pushl %eax /* return_IP and SI */
+ ret
+#endif
+
+//#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+move_helper:
+
+ /* called only once and only when the boot loader loaded this code */
+ pushw %si
+ pushw %bx
+ pushl %eax
+
+ movw $0x0003, %ax /* set display mode: 80*25 color text */
+ int $0x10
+
+ movw $0x200, %si
+ movw %si, %di
+ movw $0xf00, %cx
+ cld
+ repz movsw
+
+ popl %eax
+ popw %bx
+ popw %si
+ ret
+//#endif
+
+#if (defined(GRLDR_MBR)) || (defined(GRLDR_INSTALL))
+filesystem_boot:
+ /* The partition boot record successfully modified, just boot it */
+
+ /*
+ * The boot might fail, but we want to take back the control.
+ * So we save the registers now.
+ */
+ pushw %ds
+ pushw %es
+ pushal
+
+ /* DS=CS=GRLDR_CS, ES=FS_BOOT */
+
+ /* save GRLDR_CS */
+
+ movw %es, %bx # save old ES to BX
+
+ cli
+ lgdt gdt - _start1
+ movl %cr0, %eax
+ orb $1, %al
+ movl %eax, %cr0
+
+ movw $8, %si
+ movw %si, %es
+
+ xorl %esi, %esi
+ xorl %edi, %edi
+ movl $(0x9000 / 4), %ecx
+
+ cld
+ repz movsl
+
+ movw $16, %si
+ movw %si, %es
+
+ andb $0xfe, %al
+ movl %eax, %cr0
+
+ movw %bx, %es # restore ES from BX
+
+ /* move FS_BOOT:0000 to 0:7c00 */
+#if 0
+ /* for single sector boot record */
+ movw $0x0200, %cx /* move 2 sectors, the old FS_BOOT:0000 will
+ * keep untouched. */
+#else
+ /* for 4-sector NTFS boot record */
+ movw $0x0400, %cx /* move 4 sectors, the old FS_BOOT:0000 will
+ * keep untouched. */
+#endif
+ xorw %si, %si
+ pushw %si /* SI=0, for the segment of 0000:7c00 */
+ movw $0x7c00, %di
+ pushw %di /* DI=0x7c00, for the offset of 0000:7c00 */
+ pushw %es /* ES=FS_BOOT */
+ popw %ds /* DS=FS_BOOT */
+ pushw %si /* SI=0 */
+ popw %es /* ES=0 */
+ cld
+ repz movsw
+
+ movw $MONITOR, %di
+ movw $(restore_GRLDR_CS - _start1), %si
+ movw $((gdt_end - restore_GRLDR_CS) / 4), %cx
+ cld
+ repz cs movsl /* CS segment override prefix(=0x2E) */
+
+ pushw %es /* ES=0 */
+ popw %ds /* DS=0 */
+ sti
+ lret //ljmp $0, $0x7c00
+#endif
+
+press_space_bar_string:
+ .ascii "\r\nPress space bar\0"
+
+press_hot_key_pre:
+ .ascii "\r\nPress \0"
+
+press_hot_key_sub:
+ .ascii " to start GRUB, any other key to boot previous MBR ...\0"
+
+hot_key_timeout_pre:
+ .ascii "\r\nTimeout : \0"
+
+hot_key_timeout_num:
+ .ascii " \b\b\b\0"
+
+continue_string:
+ .ascii "\r\nInvalid previous MBR. Press any key to start GRUB ...\0"
+
+Cannot_find_GRLDR_string:
+ .ascii "\r\nCannot find GRLDR.\0"
+
+prev_MBR_string:
+ .ascii " to hold the screen, any other key to boot previous MBR ...\0"
+
+Error_while_reading_string:
+ .ascii "\r\nError while reading MBR of \0"
+
+drive_number_string:
+ .ascii "drive (hd0 ) \0"
+
+partition_boot_indicator_string:
+ .ascii "\r\nInvalid boot indicator in partition table of \0"
+
+partition_sectors_per_track_string:
+ .ascii "\r\nInvalid sectors_per_track in partition table of \0"
+
+partition_start_sector_string:
+ .ascii "\r\nInvalid start_sector in partition table of \0"
+
+partition_end_sector_string:
+ .ascii "\r\nInvalid end_sector in partition table of \0"
+
+no_boot_signature_string:
+ .ascii "\r\nNo boot signature in partition table of \0"
+
+message_string_helper:
+ .ascii "\r\nError: Cannot find GRLDR in all devices. Press Ctrl+Alt+Del to restart.\0"
+
+partition_message:
+ .ascii "\r\nTry (hd0,0 ) : \0"
+
+EXT2_message:
+ .ascii "EXT2: \0"
+NTFS4_message:
+ .ascii "NTFS4: \0"
+NTFS5_message:
+ .ascii "NTFS5: \0"
+NTFS5p_message:
+ .ascii "NTFS5p: \0"
+FAT32_message:
+ .ascii "FAT32: \0"
+FAT16_message:
+ .ascii "FAT16: \0"
+FAT12_message:
+ .ascii "FAT12: \0"
+non_MS_message:
+ .ascii "non-MS: skip \0"
+extended_message:
+ .ascii "Extended: \0"
+invalid_message:
+ .ascii "invalid or null \0"
+#if 0
+NTFS_no_boot_record_message:
+ .ascii "This partition is NTFS but with unknown boot record. Please\r\ninstall Microsoft NTFS boot sectors to this partition correctly, or create an\r\nFAT12/16/32 partition and place the same copy of GRLDR and MENU.LST there.\0"
+#endif
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+ . = _start1 + 0x1ffa
+#else
+ . = . + (0x3ec - ((. - _start1) % 0x200)) % 0x200
+
+press_hot_key_name:
+
+ /* hot key name, the address is (grldr_signature - 16) */
+
+ .ascii "hot-key\0"
+
+ . = press_hot_key_name + 14
+
+ //. = . + (0x3fa - ((. - _start1) % 0x200)) % 0x200
+#endif
+
+ /* version word of grldr.mbr, the address is (grldr_signature - 2) */
+
+ .word 2
+
+grldr_signature:
+ .byte 0x47, 0x52, 0x55, 0xaa /* signature for helper */
+
+ .align 0x200
+
+#if (! defined(GRLDR_MBR)) && (! defined(GRLDR_INSTALL))
+
+ /* pre_stage2 start at 0x2000 for grldr */
+
+ . = _start1 + 0x2000
+
+#endif
+
+#if defined(GRLDR_MBR)
+ /* if the size is less than 8192, let it be 8192 */
+ . = . + (0x2000 - (. - _start1)) * (0x4000 / (. - _start1 + 0x2001))
+#endif
+
+pre_stage2_start:
+
+
diff --git a/debian/grub-extras/ntldr-img/grubinst.c b/debian/grub-extras/ntldr-img/grubinst.c
new file mode 100644
index 0000000..2f7561a
--- /dev/null
+++ b/debian/grub-extras/ntldr-img/grubinst.c
@@ -0,0 +1,1043 @@
+/*
+ * GRUB Utilities -- Utilities for GRUB Legacy, GRUB2 and GRUB for DOS
+ * Copyright (C) 2007 Bean (bean123@126.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+
+#ifndef WIN32
+
+#define O_BINARY 0
+
+#endif
+
+#include "grub_mbr.h"
+#include "utils.h"
+#include "version.h"
+
+// Application flags, used by this program
+
+#define AFG_VERBOSE 1
+#define AFG_PAUSE 2
+#define AFG_READ_ONLY 4
+#define AFG_NO_BACKUP_MBR 8
+#define AFG_FORCE_BACKUP_MBR 16
+#define AFG_RESTORE_PREVMBR 32
+#define AFG_LIST_PART 64
+#define AFG_IS_FLOPPY 128
+#define AFG_LBA_MODE 256
+#define AFG_CHS_MODE 512
+#define AFG_OUTPUT 1024
+#define AFG_EDIT 2048
+
+// Grldr flags, this flag is used by grldr.mbr
+
+#define GFG_DISABLE_FLOPPY 1
+#define GFG_DISABLE_OSBR 2
+#define GFG_DUCE 4
+#define GFG_PREVMBR_LAST 128
+
+#define APP_NAME "grubinst: "
+
+#define print_pause if (afg & AFG_PAUSE) {fputs("Press <ENTER> to continue ...\n",stderr); fflush(stderr); fgetc(stdin);}
+
+#define print_apperr(a) { fprintf(stderr,APP_NAME "%s\n",a); print_pause; }
+#define print_syserr(a) { perror(APP_NAME a); print_pause; }
+
+static void help(void)
+{
+ fputs("Usage:\n"
+ "\tgrubinst [OPTIONS] DEVICE_OR_FILE\n\n"
+ "OPTIONS:\n\n"
+ "\t--help,-h\t\tShow usage information\n\n"
+ "\t--pause\t\t\tPause before exiting\n\n"
+ "\t--version\t\tShow version information\n\n"
+ "\t--verbose,-v\t\tVerbose output\n\n"
+ "\t--list-part,-l\t\tList all logical partitions in DEVICE_OR_FILE\n\n"
+ "\t--save=FN,-s=FN\t\tSave the orginal MBR/BS to FN\n\n"
+ "\t--restore=FN,-r=FN\tRestore MBR/BS from previously saved FN\n\n"
+ "\t--restore-prevmbr,-r\tRestore previous MBR saved in the second sector\n"
+ "\t\t\t\tof DEVICE_OR_FILE\n\n"
+ "\t--read-only,-t\t\tdo everything except the actual write to the\n"
+ "\t\t\t\tspecified DEVICE_OR_FILE. (test mode)\n\n"
+ "\t--no-backup-mbr\t\tdo not copy the old MBR to the second sector of\n"
+ "\t\t\t\tDEVICE_OR_FILE.\n\n"
+ "\t--force-backup-mbr\tforce the copy of old MBR to the second sector\n"
+ "\t\t\t\tof DEVICE_OR_FILE.(default)\n\n"
+ "\t--mbr-enable-floppy\tenable the search for GRLDR on floppy.(default)\n\n"
+ "\t--mbr-disable-floppy\tdisable the search for GRLDR on floppy.\n\n"
+ "\t--mbr-enable-osbr\tenable the boot of PREVIOUS MBR with invalid\n"
+ "\t\t\t\tpartition table (usually an OS boot sector).\n"
+ "\t\t\t\t(default)\n\n"
+ "\t--mbr-disable-osbr\tdisable the boot of PREVIOUS MBR with invalid\n"
+ "\t\t\t\tpartition table (usually an OS boot sector).\n\n"
+ "\t--duce\t\t\tdisable the feature of unconditional entrance\n"
+ "\t\t\t\tto the command-line.\n\n"
+ "\t--boot-prevmbr-first\ttry to boot PREVIOUS MBR before the search for\n"
+ "\t\t\t\tGRLDR.\n\n"
+ "\t--boot-prevmbr-last\ttry to boot PREVIOUS MBR after the search for\n"
+ "\t\t\t\tGRLDR.(default)\n\n"
+ "\t--preferred-drive=D\tpreferred boot drive number, 0 <= D < 255.\n\n"
+ "\t--preferred-partition=P\tpreferred partition number, 0 <= P < 255.\n\n"
+ "\t--time-out=T,-t=T\twait T seconds before booting PREVIOUS MBR. if\n"
+ "\t\t\t\tT is 0xff, wait forever. The default is 5.\n\n"
+ "\t\t\t\tbefore booting PREVIOUS MBR. K is a word\n"
+ "\t\t\t\tvalue, just as the value in AX register\n"
+ "\t\t\t\treturned from int16/AH=1. The high byte is the\n"
+ "\t\t\t\tscan code and the low byte is ASCII code. The\n"
+ "\t\t\t\tdefault is 0x3920 for space bar.\n\n"
+ "\t--key-name=S\t\tSpecify the name of the hot key.\n\n"
+ "\t--floppy,-f\t\tif DEVICE_OR_FILE is floppy, use this option.\n\n"
+ "\t--floppy=N\t\tif DEVICE_OR_FILE is a partition on a hard\n"
+ "\t\t\t\tdrive, use this option. N is used to specify\n"
+ "\t\t\t\tthe partition number: 0,1,2 and 3 for the\n"
+ "\t\t\t\tprimary partitions, and 4,5,6,... for the\n"
+ "\t\t\t\tlogical partitions.\n\n"
+ "\t--sectors-per-track=S\tspecifies sectors per track for --floppy.\n"
+ "\t\t\t\t1 <= S <= 63, default is 63.\n\n"
+ "\t--heads=H\t\tspecifies number of heads for --floppy.\n"
+ "\t\t\t\t1 <= H <= 256, default is 255.\n\n"
+ "\t--start-sector=B\tspecifies hidden sectors for --floppy=N.\n\n"
+ "\t--total-sectors=C\tspecifies total sectors for --floppy.\n"
+ "\t\t\t\tdefault is 0.\n\n"
+ "\t--lba\t\t\tuse lba mode for --floppy. If the floppy BIOS\n"
+ "\t\t\t\thas LBA support, you can specify --lba here.\n"
+ "\t\t\t\tIt is assumed that all floppy BIOSes have CHS\n"
+ "\t\t\t\tsupport. So you would rather specify --chs.\n"
+ "\t\t\t\tIf neither --chs nor --lba is specified, then\n"
+ "\t\t\t\tthe LBA indicator(i.e., the third byte of the\n"
+ "\t\t\t\tboot sector) will not be touched.\n\n"
+ "\t--chs\t\t\tuse chs mode for --floppy. You should specify\n"
+ "\t\t\t\t--chs if the floppy BIOS does not support LBA.\n"
+ "\t\t\t\tWe assume all floppy BIOSes have CHS support.\n"
+ "\t\t\t\tSo it is likely you want to specify --chs.\n"
+ "\t\t\t\tIf neither --chs nor --lba is specified, then\n"
+ "\t\t\t\tthe LBA indicator(i.e., the third byte of the\n"
+ "\t\t\t\tboot sector) will not be touched.\n\n"
+ "\t--install-partition=I\tInstall the boot record onto the boot area of\n"
+ "\t-p=I\t\t\tpartition number I of the specified hard drive\n"
+ "\t\t\t\tor harddrive image DEVICE_OR_FILE.\n\n"
+ "\t--boot-file=F,-b=F\tChange the name of boot file.\n\n"
+ "\t--load-seg=S\t\tChange load segment for boot file.\n\n"
+ "\t--grub2,-2\t\tLoad grub2 kernel g2ldr instead of grldr.\n\n"
+ "\t--output,-o\t\tSave embeded grldr.mbr to DEVICE_OR_FILE.\n\n"
+ "\t--edit,-e\t\tEdit external grldr/grldr.mbr.\n",
+ stderr);
+}
+
+int afg,gfg,def_drive,def_part,time_out,hot_key,part_num;
+int def_spt,def_hds,def_ssc,def_tsc;
+char *save_fn,*restore_fn,boot_file_83[12];
+const char *key_name;
+const char *boot_file;
+unsigned short load_seg;
+
+static char fn_buf[24];
+
+static char* get_disk_name(int n)
+{
+#if defined(WIN32)
+ sprintf(fn_buf,"\\\\.\\PhysicalDrive%d",n);
+#elif defined(LINUX)
+ sprintf(fn_buf,"/dev/hd%c",'a'+n);
+#elif defined(FREEBSD)
+ sprintf(fn_buf,"/dev/ad%d",n);
+#else
+ print_apperr("Disk device is not supported in your system");
+ return NULL;
+#endif
+ return fn_buf;
+}
+
+static char* get_flop_name(int n)
+{
+#if defined(WIN32)
+ if (n>1)
+ {
+ print_apperr("Only two floppy drives are supported");
+ return NULL;
+ }
+ sprintf(fn_buf,"\\\\.\\%c:",'A'+n);
+#elif defined(LINUX) || defined(FREEBSD)
+ sprintf(fn_buf,"/dev/fd%d",n);
+#else
+ print_apperr("Floppy device is not supported in your system");
+ return NULL;
+#endif
+ return fn_buf;
+}
+
+static char* parse_fname(char* fn)
+{
+ if ((afg & AFG_OUTPUT) && (fn[0]=='('))
+ {
+ print_apperr("Can\'t use device name while using --output option");
+ return NULL;
+ }
+ if ((! strncmp(fn,"(hd",3)) || (! strncmp(fn,"(fd",3)))
+ {
+ int n;
+ char *p;
+
+ n=strtol(&fn[3],&p,0);
+ if ((n<0) || (n>=MAX_DISKS))
+ {
+ print_apperr("Invalid device number");
+ return NULL;
+ }
+ if (*p==',')
+ {
+ part_num=strtol(p+1,&p,0);
+ if ((part_num<0) || (part_num>=MAX_PARTS))
+ {
+ print_apperr("Invalid partition number");
+ return NULL;
+ }
+ }
+ if ((*p!=')') || (*(p+1)!=0))
+ {
+ print_apperr("Invalid device name");
+ return NULL;
+ }
+ if (fn[1]=='h')
+ fn=get_disk_name(n);
+ else
+ {
+ fn=get_flop_name(n);
+ afg|=AFG_IS_FLOPPY;
+ }
+ }
+ return fn;
+}
+
+static char* str_upcase(char* str)
+{
+ int i;
+
+ for (i=0;str[i];i++)
+ if ((str[i]>='a') && (str[i]<='z'))
+ str[i]-='a'-'A';
+
+ return str;
+}
+
+static char* str_lowcase(char* str)
+{
+ int i;
+
+ for (i=0;str[i];i++)
+ if ((str[i]>='A') && (str[i]<='Z'))
+ str[i]+='a'-'A';
+
+ return str;
+}
+
+static int SetBootFile(char* fn)
+{
+ char* pc;
+
+ if (*fn==0)
+ return 1;
+ if (strlen(fn)>7)
+ return 1;
+ pc=strchr(fn,'.');
+ if (pc)
+ if ((pc==fn) || (pc-fn>8) || (strlen(pc+1)>3))
+ return 1;
+ str_upcase(fn);
+ memset(boot_file_83,' ',sizeof(boot_file_83)-1);
+ if (pc)
+ {
+ memcpy(boot_file_83,fn,pc-fn);
+ memcpy(&boot_file_83[8],pc+1,strlen(pc+1));
+ }
+ else
+ memcpy(boot_file_83,fn,strlen(fn));
+ str_lowcase(fn);
+ boot_file=fn;
+ return 0;
+}
+
+static void list(int hd)
+{
+ xde_t xe;
+
+ xe.cur=xe.nxt=0xFF;
+ fprintf(stderr," # id base leng\n");
+ while (! xd_enum(hd,&xe))
+ fprintf(stderr,"%2d %02" PRIX64 " %8" PRIX64 " %8" PRIX64 "\n",
+ xe.cur,
+ (uint64_t) xe.dfs,
+ (uint64_t) xe.bse,
+ (uint64_t) xe.len);
+}
+
+static int is_grldr_mbr(unsigned char* buf)
+{
+ int i,n;
+
+ i=0x1B7;
+ n=sizeof("Missing MBR-helper.")-1;
+
+ while ((i>n) && (buf[i]==0))
+ i--;
+ return (! memcmp(&buf[i-n+1],"Missing MBR-helper.", sizeof("Missing MBR-helper.")));
+}
+
+static int install(char* fn)
+{
+ int hd = -1,nn,fs,slen;
+ unsigned char prev_mbr[sizeof(grub_mbr)];
+ unsigned long ssec;
+
+ if (fn==NULL)
+ return 1;
+
+ if (afg & AFG_EDIT)
+ {
+ unsigned short r1,r2;
+
+ if (afg & AFG_VERBOSE)
+ fprintf(stderr,"Edit mode\n");
+ hd=open(fn,O_RDWR | O_BINARY,0644);
+ if (hd==-1)
+ {
+ print_syserr("open");
+ return errno;
+ }
+ r1=get16(&grub_mbr[0x1FFA],0);
+ nn=read(hd,grub_mbr,sizeof(grub_mbr));
+ if (nn==-1)
+ {
+ print_syserr("read");
+ close(hd);
+ return errno;
+ }
+ if (nn<(int)sizeof(grub_mbr))
+ {
+ print_apperr("The input file is too short");
+ close(hd);
+ return 1;
+ }
+ if (get32(&grub_mbr[0x1FFC],0)!=0xAA555247)
+ {
+ print_apperr("Invalid input file");
+ close(hd);
+ return 1;
+ }
+ r2=get16(&grub_mbr[0x1FFA],0);
+ if (r1!=r2)
+ {
+ char buf[80];
+
+ sprintf(buf,"Version number mismatched (old=%d new=%d)",r2,r1);
+ print_apperr(buf);
+ close(hd);
+ return 1;
+ }
+ go_sect(hd,0);
+ afg |= AFG_OUTPUT;
+ }
+
+ if (boot_file)
+ {
+ unsigned short ofs;
+
+ // Patching the FAT32 boot sector
+ ofs=get16(&grub_mbr,0x400+0x1EC) & 0x7FF;
+ strcpy((char *) &grub_mbr[0x400+ofs],boot_file_83);
+ if (load_seg)
+ set16(&grub_mbr,0x400+0x1EA,load_seg);
+
+ // Patching the FAT12/FAT16 boot sector
+ ofs=get16(&grub_mbr,0x600+0x1EC) & 0x7FF;
+ strcpy((char *) &grub_mbr[0x600+ofs],boot_file_83);
+ if (load_seg)
+ set16(&grub_mbr,0x600+0x1EA,load_seg);
+
+ // Patching the EXT2 boot sector
+ ofs=get16(grub_mbr,0x800+0x1EE) & 0x7FF;
+ strcpy((char *) &grub_mbr[0x800+ofs],boot_file);
+
+ // Patching the NTFS sector
+ ofs=get16(grub_mbr,0xA00+0x1EC) & 0x7FF;
+ strcpy((char *) &grub_mbr[0xA00+ofs],boot_file);
+ if (load_seg)
+ set16(grub_mbr,0xA00+0x1EA,load_seg);
+
+ if (afg & AFG_VERBOSE)
+ {
+ fprintf(stderr,"Boot file changed to %s\n",boot_file);
+ if (load_seg)
+ fprintf(stderr,"Load segment changed to %04X\n",load_seg);
+ }
+ }
+
+ if (afg & AFG_OUTPUT)
+ {
+ int mode;
+
+ mode=(! (afg & AFG_READ_ONLY))?(O_TRUNC | O_CREAT):0;
+ if (! (afg & AFG_EDIT))
+ {
+ if (afg & AFG_VERBOSE)
+ fprintf(stderr,"Extract mode\n");
+ hd=open(fn,O_RDWR | O_BINARY | mode,0644);
+ if (hd==-1)
+ {
+ print_syserr("open");
+ return errno;
+ }
+ }
+ if (! (afg & AFG_READ_ONLY))
+ if (write(hd,grub_mbr,sizeof(grub_mbr))!=sizeof(grub_mbr))
+ {
+ print_apperr("Write to output file fails");
+ close(hd);
+ return 1;
+ }
+ goto quit;
+ }
+
+ memset(&grub_mbr[512],0,512);
+ grub_mbr[2] = gfg;
+ grub_mbr[3]=time_out;
+ set16(&grub_mbr,4,hot_key);
+ grub_mbr[6] = def_drive;
+ grub_mbr[7] = def_part;
+ if ((key_name==NULL) && (hot_key==0x3920))
+ key_name="SPACE";
+ if (key_name)
+ strcpy((char *) &grub_mbr[0x1fec],key_name);
+
+ hd=open(fn,O_RDWR | O_BINARY,S_IREAD | S_IWRITE);
+ if (hd==-1)
+ {
+ print_syserr("open");
+ return errno;
+ }
+ if (afg & AFG_LIST_PART)
+ {
+ list(hd);
+ close(hd);
+ return 0;
+ }
+ if (part_num!=-1)
+ {
+ if (def_ssc!=-1)
+ ssec=def_ssc;
+ else
+ {
+ xde_t xe;
+
+ xe.cur=0xFF;
+ xe.nxt=part_num;
+ if (xd_enum(hd,&xe))
+ {
+ print_apperr("Partition not found");
+ close(hd);
+ return 1;
+ }
+ ssec=xe.bse;
+ if (afg & AFG_VERBOSE)
+ fprintf(stderr,"Part Fs: %02X (%s)\nPart Leng: %" PRIu64 "\n",xe.dfs,dfs2str(xe.dfs),
+ (uint64_t) xe.len);
+ }
+ }
+ else
+ ssec=0;
+ if (afg & AFG_VERBOSE)
+ fprintf(stderr,"Start sector: %" PRIu64 "\n", (uint64_t) ssec);
+ if ((ssec) && (go_sect(hd,ssec)))
+ {
+ print_apperr("Can\'t seek to the start sector");
+ close(hd);
+ return 1;
+ }
+ nn=read(hd,prev_mbr,sizeof(prev_mbr));
+ if (nn==-1)
+ {
+ print_syserr("read");
+ close(hd);
+ return errno;
+ }
+ if (nn<(int)sizeof(prev_mbr))
+ {
+ print_apperr("The input file is too short");
+ close(hd);
+ return 1;
+ }
+ fs=get_fstype(prev_mbr);
+ if (afg & AFG_VERBOSE)
+ {
+ fprintf(stderr,"Image type: %s\n",fst2str(fs));
+ if (fs==FST_MBR)
+ fprintf(stderr,"Num of heads: %d\nSectors per track: %d\n",mbr_nhd,mbr_spt);
+ }
+ if (fs==FST_OTHER)
+ {
+ print_apperr("Unknown image type");
+ close(hd);
+ return 1;
+ }
+ if (((part_num!=-1) || (afg & AFG_IS_FLOPPY)) && (fs==FST_MBR))
+ {
+ print_apperr("Should be a file system image");
+ close(hd);
+ return 1;
+ }
+ if ((part_num==-1) && ((afg & AFG_IS_FLOPPY)==0) && (fs!=FST_MBR))
+ {
+ print_apperr("Should be a disk image");
+ close(hd);
+ return 1;
+ }
+ if (fs==FST_MBR)
+ {
+ int n,nfs,sln;
+ unsigned long ofs;
+ unsigned char bs[1024];
+
+ ofs=0xFFFFFFFF;
+ for (n=0x1BE;n<0x1FE;n+=16)
+ if (prev_mbr[n+4])
+ {
+ if (ofs>get32(&prev_mbr[n],8))
+ ofs=get32(&prev_mbr[n],8);
+ }
+ if (ofs<(sizeof(prev_mbr)>>9))
+ {
+ print_apperr("Not enough room to install mbr");
+ close(hd);
+ return 1;
+ }
+ slen=sizeof(prev_mbr);
+ if (go_sect(hd,ofs))
+ {
+ print_apperr("Can\'t seek to the first partition");
+ close(hd);
+ return 1;
+ }
+ if (read(hd,bs,sizeof(bs))!=sizeof(bs))
+ {
+ print_apperr("Fail to read boot sector");
+ close(hd);
+ return 1;
+ }
+ nfs=get_fstype(bs);
+ if (nfs==FST_FAT32)
+ sln=0x5A - 0xB;
+ else if (nfs==FST_FAT16)
+ sln=0x3E - 0xB;
+ else
+ sln=0;
+ if (sln)
+ {
+ memcpy(&grub_mbr[0xB],&bs[0xB],sln);
+ set32(&grub_mbr[0],0x1C,0);
+ set16(&grub_mbr[0],0xE,get16(&grub_mbr[0],0xE) + ofs);
+ }
+ }
+ else if (fs==FST_NTFS)
+ slen=2048;
+ else
+ slen=512;
+
+ if (go_sect(hd,ssec))
+ {
+ print_apperr("Can\'t seek to the start sector");
+ close(hd);
+ return 1;
+ }
+
+ if (save_fn)
+ {
+ int h2;
+
+ h2=open(save_fn,O_CREAT | O_TRUNC | O_RDWR | O_BINARY,S_IREAD | S_IWRITE);
+ if (h2==-1)
+ {
+ print_syserr("open save file");
+ close(hd);
+ return errno;
+ }
+ nn=write(h2,prev_mbr,slen);
+ if (nn==-1)
+ {
+ print_syserr("write save file");
+ close(hd);
+ close(h2);
+ return errno;
+ }
+ if (nn<slen)
+ {
+ print_apperr("Can\'t write the whole MBR to the save file");
+ close(hd);
+ close(h2);
+ return 1;
+ }
+ close(h2);
+ }
+ if (afg & AFG_RESTORE_PREVMBR)
+ {
+ if (fs!=FST_MBR)
+ {
+ print_apperr("Not a disk image");
+ close(hd);
+ return 1;
+ }
+ if (memcmp(&prev_mbr[1024+3],"GRLDR",5))
+ {
+ print_apperr("GRLDR is not installed");
+ close(hd);
+ return 1;
+ }
+ if (get16(prev_mbr,512+510)!=0xAA55)
+ {
+ print_apperr("No previous saved MBR");
+ close(hd);
+ return 1;
+ }
+ memset(&grub_mbr,0,sizeof(grub_mbr));
+ memcpy(&grub_mbr,&prev_mbr[512],512);
+ memcpy(&grub_mbr[0x1b8],&prev_mbr[0x1b8],72);
+
+ if (afg & AFG_VERBOSE)
+ fprintf(stderr,"Restore previous MBR mode\n");
+ }
+ else
+ {
+ // Load MBR/BS from restore file or configure grub_mbr
+ if (restore_fn)
+ {
+ int h2;
+
+ h2=open(restore_fn,O_RDONLY | O_BINARY,S_IREAD);
+ if (h2==-1)
+ {
+ print_syserr("open restore file");
+ close(hd);
+ return errno;
+ }
+ nn=read(h2,grub_mbr,slen);
+ if (nn==-1)
+ {
+ print_syserr("read restore file");
+ close(hd);
+ close(h2);
+ return errno;
+ }
+ if ((nn<512) || ((nn & 0x1FF)!=0) ||
+ ((fs!=FST_EXT2) && (get16(grub_mbr,510)!=0xAA55)))
+ {
+ print_apperr("Invalid restore file");
+ close(hd);
+ close(h2);
+ return 1;
+ }
+ close(h2);
+ if (nn<slen)
+ memset(&grub_mbr[nn],0,slen-nn);
+
+ //if ((fs==FST_FAT16) || (fs==FST_FAT32) || (fs==FST_NTFS))
+ if (fs!=FST_EXT2)
+ {
+ int new_fs;
+
+ new_fs=get_fstype(grub_mbr);
+ if (new_fs!=fs)
+ {
+ print_apperr("Invalid restore file");
+ close(hd);
+ return 1;
+ }
+ }
+
+ if (afg & AFG_VERBOSE)
+ fprintf(stderr,"Restore mode\n");
+ }
+ else
+ {
+ if (fs==FST_MBR)
+ {
+ if (! (afg & AFG_NO_BACKUP_MBR))
+ {
+ int i;
+
+ if (afg & AFG_FORCE_BACKUP_MBR)
+ i=512;
+ else
+ for (i=1;i<512;i++)
+ if (prev_mbr[512+i]!=prev_mbr[512])
+ break;
+
+ if ((i==512) && (! is_grldr_mbr(prev_mbr)))
+ memcpy(&grub_mbr[512],prev_mbr,512);
+ else
+ memcpy(&grub_mbr[512],&prev_mbr[512],512);
+ }
+ memcpy(&grub_mbr[0x1b8],&prev_mbr[0x1b8],72);
+ }
+ else if (fs==FST_FAT16)
+ {
+ memcpy(grub_mbr,&grub_mbr[0x600],slen);
+ grub_mbr[0x41]=part_num;
+ }
+ else if (fs==FST_FAT32)
+ {
+ memcpy(grub_mbr,&grub_mbr[0x400],slen);
+ grub_mbr[0x5D]=part_num;
+ }
+ else if (fs==FST_NTFS)
+ {
+ memcpy(grub_mbr,&grub_mbr[0xA00],slen);
+ grub_mbr[0x57]=part_num;
+ }
+ else if (fs==FST_EXT2)
+ {
+ memcpy(&grub_mbr,&grub_mbr[0x800],slen);
+ grub_mbr[0x25]=part_num;
+ if (afg & AFG_LBA_MODE)
+ grub_mbr[2]=0x42;
+ else if (afg & AFG_CHS_MODE)
+ grub_mbr[2]=0x2;
+ if (def_spt!=-1)
+ set16(&grub_mbr,0x18,def_spt);
+ else if ((afg & AFG_IS_FLOPPY)==0)
+ set16(&grub_mbr,0x18,63);
+ if (def_hds!=-1)
+ set16(&grub_mbr,0x1A,def_hds);
+ else if ((afg & AFG_IS_FLOPPY)==0)
+ set16(&grub_mbr,0x1A,255);
+ if (def_tsc!=-1)
+ set32(&grub_mbr,0x20,def_tsc);
+ set32(&grub_mbr,0x1C,ssec);
+ // s_inode_size
+ if (prev_mbr[1024+0x4C]) // s_rev_level
+ set16(&grub_mbr,0x26,get16(&prev_mbr[1024],0x58));
+ else
+ set16(&grub_mbr,0x26,0x80);
+ // s_inodes_per_group
+ set32(&grub_mbr,0x28,get32(&prev_mbr[1024],0x28));
+ // s_first_data_block+1
+ set32(&grub_mbr,0x2C,get32(&prev_mbr[1024],0x14)+1);
+ }
+ else
+ {
+ // Shouldn't be here
+ print_apperr("Invalid file system");
+ close(hd);
+ return 1;
+ }
+ if ((fs==FST_FAT16) || (fs==FST_FAT32) || (fs==FST_NTFS))
+ {
+ if (afg & AFG_LBA_MODE)
+ grub_mbr[2]=0xe;
+ else if (afg & AFG_CHS_MODE)
+ grub_mbr[2]=0x90;
+ else
+ grub_mbr[2]=prev_mbr[2];
+ }
+
+ if (afg & AFG_VERBOSE)
+ fprintf(stderr,"Install mode\n");
+ }
+ // Patch the new MBR/BS with information from prev_mbr
+ if (fs==FST_MBR)
+ memcpy(&grub_mbr[0x1b8],&prev_mbr[0x1b8],72);
+ else if (fs==FST_FAT16)
+ {
+ memcpy(&grub_mbr[0xB],&prev_mbr[0xB],0x3E - 0xB);
+ set32(grub_mbr,0x1C,ssec);
+ }
+ else if (fs==FST_FAT32)
+ {
+ memcpy(&grub_mbr[0xB],&prev_mbr[0xB],0x5A - 0xB);
+ set32(grub_mbr,0x1C,ssec);
+ }
+ else if (fs==FST_NTFS)
+ {
+ memcpy(&grub_mbr[0xB],&prev_mbr[0xB],0x54 - 0xB);
+ set32(grub_mbr,0x1C,ssec);
+ }
+ }
+ if (! (afg & AFG_READ_ONLY))
+ {
+ nn=write(hd,grub_mbr,slen);
+ if (nn==-1)
+ {
+ print_syserr("write");
+ close(hd);
+ return errno;
+ }
+ if (nn<slen)
+ {
+ print_apperr("Can\'t write the whole mbr");
+ close(hd);
+ return 1;
+ }
+ }
+ else if (afg & AFG_VERBOSE)
+ fprintf(stderr,"Read only mode\n");
+quit:
+ close(hd);
+ if (afg & AFG_PAUSE)
+ {
+ fputs("The MBR/BS has been successfully installed\n",stderr);
+ print_pause;
+ }
+ return 0;
+}
+
+int main(int argc,char** argv)
+{
+ int idx;
+
+ afg=gfg=0;
+ part_num=def_drive=def_part=def_spt=def_hds=def_ssc=def_tsc=-1;
+ afg=0;
+ gfg=GFG_PREVMBR_LAST;
+ time_out=5;
+ hot_key=0x3920;
+ save_fn=NULL;
+ restore_fn=NULL;
+ for (idx=1;idx<argc;idx++)
+ {
+ if (argv[idx][0]!='-')
+ break;
+ if ((! strcmp(argv[idx],"--help"))
+ || (! strcmp(argv[idx],"-h")))
+ {
+ help();
+ print_pause;
+ return 1;
+ }
+ else if (! strcmp(argv[idx],"--version"))
+ {
+ fprintf(stderr,"grubinst version : " VERSION "\n");
+ print_pause;
+ return 1;
+ }
+ else if ((! strcmp(argv[idx],"--verbose")) ||
+ (! strcmp(argv[idx],"-v")))
+ afg |=AFG_VERBOSE;
+ else if (! strcmp(argv[idx],"--pause"))
+ afg|=AFG_PAUSE;
+ else if ((! strcmp(argv[idx],"--read-only"))
+ || (! strcmp(argv[idx],"-t")))
+ afg|=AFG_READ_ONLY;
+ else if (! strcmp(argv[idx],"--no-backup-mbr"))
+ afg|=AFG_NO_BACKUP_MBR;
+ else if (! strcmp(argv[idx],"--force-backup-mbr"))
+ afg|=AFG_FORCE_BACKUP_MBR;
+ else if (! strcmp(argv[idx],"--mbr-enable-floppy"))
+ gfg&=~GFG_DISABLE_FLOPPY;
+ else if (! strcmp(argv[idx],"--mbr-disable-floppy"))
+ gfg|=GFG_DISABLE_FLOPPY;
+ else if (! strcmp(argv[idx],"--mbr-enable-osbr"))
+ gfg&=~GFG_DISABLE_OSBR;
+ else if (! strcmp(argv[idx],"--mbr-disable-osbr"))
+ gfg|=GFG_DISABLE_OSBR;
+ else if (! strcmp(argv[idx],"--duce"))
+ gfg|=GFG_DUCE;
+ else if (! strcmp(argv[idx],"--boot-prevmbr-first"))
+ gfg&=~GFG_PREVMBR_LAST;
+ else if (! strcmp(argv[idx],"--boot-prevmbr-last"))
+ gfg|=GFG_PREVMBR_LAST;
+ else if (! strncmp(argv[idx],"--preferred-drive=",18))
+ {
+ def_drive=strtol(&argv[idx][18],NULL,0);
+ if ((def_drive<0) || (def_drive>=255))
+ {
+ print_apperr("Invalid preferred drive number");
+ return 1;
+ }
+ }
+ else if (! strncmp(argv[idx],"--preferred-partition=",22))
+ {
+ def_part=strtol(&argv[idx][22],NULL,0);
+ if ((def_part<0) || (def_part>=255))
+ {
+ print_apperr("Invalid preferred partition number");
+ return 1;
+ }
+ }
+ else if ((! strncmp(argv[idx],"--time-out=",11)) ||
+ (! strncmp(argv[idx],"-t=",3)))
+ {
+ time_out=strtol((argv[idx][2]=='=')?&argv[idx][3]:&argv[idx][11],NULL,0);
+ if ((time_out<0) || (time_out>255))
+ {
+ print_apperr("Invalid timeout value");
+ return 1;
+ }
+ }
+ else if ((! strncmp(argv[idx],"--key-name=",11)))
+ {
+ key_name=&argv[idx][11];
+ if (strlen(key_name)>13)
+ {
+ print_apperr("Key name too long");
+ return 1;
+ }
+ }
+ else if ((! strcmp(argv[idx],"--restore-prevmbr")) ||
+ (! strcmp(argv[idx],"-r")))
+ afg|=AFG_RESTORE_PREVMBR;
+ else if ((! strncmp(argv[idx],"--save=",7)) ||
+ (! strncmp(argv[idx],"-s=",3)))
+ {
+ save_fn=(argv[idx][2]=='=')?&argv[idx][3]:&argv[idx][7];
+ if (*save_fn==0)
+ {
+ print_apperr("Empty filename");
+ return 1;
+ }
+ }
+ else if ((! strncmp(argv[idx],"--restore=",10)) ||
+ (! strncmp(argv[idx],"-r=",3)))
+ {
+ restore_fn=(argv[idx][2]=='=')?&argv[idx][3]:&argv[idx][10];
+ if (*restore_fn==0)
+ {
+ print_apperr("Empty filename");
+ return 1;
+ }
+ }
+ else if ((! strcmp(argv[idx],"--list-part")) ||
+ (! strcmp(argv[idx],"-l")))
+ afg|=AFG_LIST_PART;
+ else if ((! strcmp(argv[idx],"--floppy")) ||
+ (! strcmp(argv[idx],"-f")))
+ afg|=AFG_IS_FLOPPY;
+ else if ((! strncmp(argv[idx],"--floppy=",9)) ||
+ (! strncmp(argv[idx],"--install-partition=",20)) ||
+ (! strncmp(argv[idx],"-p=",3)))
+ {
+ char *p;
+
+ if (argv[idx][2]=='f')
+ p=&argv[idx][9];
+ else if (argv[idx][2]=='i')
+ p=&argv[idx][20];
+ else
+ p=&argv[idx][3];
+ part_num=strtoul(p,NULL,0);
+ if ((part_num<0) || (part_num>=MAX_PARTS))
+ {
+ print_apperr("Invalid partition number");
+ return 1;
+ }
+ }
+ else if (! strcmp(argv[idx],"--lba"))
+ afg|=AFG_LBA_MODE;
+ else if (! strcmp(argv[idx],"--chs"))
+ afg|=AFG_CHS_MODE;
+ else if (! strncmp(argv[idx],"--sectors-per-track=",20))
+ {
+ def_spt=strtol(&argv[idx][10],NULL,0);
+ if ((def_spt<1) || (def_spt>63))
+ {
+ print_apperr("Invalid sector per track");
+ return 1;
+ }
+ }
+ else if (! strncmp(argv[idx],"--heads=",8))
+ {
+ def_hds=strtol(&argv[idx][8],NULL,0);
+ if ((def_hds<1) || (def_hds>255))
+ {
+ print_apperr("Invalid number of heads");
+ return 1;
+ }
+ }
+ else if (! strncmp(argv[idx],"--start-sector=",15))
+ {
+ def_spt=strtol(&argv[idx][15],NULL,0);
+ if (def_ssc<0)
+ {
+ print_apperr("Invalid start sector");
+ return 1;
+ }
+ }
+ else if (! strncmp(argv[idx],"--total-sectors=",16))
+ {
+ def_tsc=strtol(&argv[idx][16],NULL,0);
+ if (def_tsc<0)
+ {
+ print_apperr("Invalid total sectors");
+ return 1;
+ }
+ }
+ else if ((! strncmp(argv[idx],"--boot-file=",12)) ||
+ (! strncmp(argv[idx],"-b=",3)))
+ {
+ if (SetBootFile((argv[idx][2]=='=')?&argv[idx][3]:&argv[idx][12]))
+ {
+ print_apperr("Invalid boot file name");
+ return 1;
+ }
+ }
+ else if (! strncmp(argv[idx],"--load-seg=",11))
+ {
+ load_seg=strtoul(&argv[idx][11],NULL,16);
+ if (load_seg<0x1000)
+ {
+ print_apperr("Load address too small");
+ return 1;
+ }
+ }
+ else if ((! strcmp(argv[idx],"--grub2")) ||
+ (! strcmp(argv[idx],"-2")))
+ {
+ if (! boot_file)
+ {
+ boot_file="g2ldr";
+ strcpy(boot_file_83,"G2LDR ");
+ }
+ }
+ else if ((! strcmp(argv[idx],"--output")) ||
+ (! strcmp(argv[idx],"-o")))
+ afg|=AFG_OUTPUT;
+ else if ((! strcmp(argv[idx],"--edit")) ||
+ (! strcmp(argv[idx],"-e")))
+ afg|=AFG_EDIT;
+ else
+ {
+ print_apperr("Invalid option, please use --help to see all valid options");
+ return 1;
+ }
+ }
+ if (idx>=argc)
+ {
+ print_apperr("No filename specified");
+ return 1;
+ }
+ if (idx<argc-1)
+ {
+ print_apperr("Extra parameters");
+ return 1;
+ }
+ return install(parse_fname(argv[idx]));
+}
diff --git a/debian/grub-extras/ntldr-img/ntfsbs.S b/debian/grub-extras/ntldr-img/ntfsbs.S
new file mode 100644
index 0000000..039caf3
--- /dev/null
+++ b/debian/grub-extras/ntldr-img/ntfsbs.S
@@ -0,0 +1,1508 @@
+/*
+ * GRUB Utilities -- Utilities for GRUB Legacy, GRUB2 and GRUB for DOS
+ * Copyright (C) 2007 Bean (bean123@126.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* NTFS boot sector for loading GRLDR , written by bean
+ *
+ * This file can be compiled as standaolne boot sector, or it can be embeded in
+ * GRLDR.MBR at 0xA00 , right after the ext2 boot sector
+ *
+ * To compile the standalone ntfsbs.bin:
+ * gcc -c -o ntfsbs.o ntfsbs.S
+ * gcc -nostdlib -Wl,-N -Wl,-Ttext -Wl,7C00 -o ntfsbs_exec ntfsbs.o
+ * objcopy -O binary ntfsbs_exec ntfsbs.bin
+ *
+ * To install the standalone ntfsbs.bin:
+ * grubinst --restore=ntfsbs.bin DEVICE_OR_FILE
+ *
+ * Where DEVICE_OR_FILE specify a NTFS partition
+ *
+ * Limitations:
+ * 1. Don't support >1K MFT record size, >4K INDEX record size
+ * 2. Don't support encrypted file
+ * 3. Don't support >4K non-resident attribute list and $BITMAP
+ *
+ */
+
+#ifndef INSIDE_GRLDR
+
+ .text
+
+ .code16
+#endif
+
+#define AT_STANDARD_INFORMATION 0x10
+#define AT_ATTRIBUTE_LIST 0x20
+#define AT_FILENAME 0x30
+#define AT_OBJECT_ID 0x40
+#define AT_SECURITY_DESCRIPTOR 0x50
+#define AT_VOLUME_NAME 0x60
+#define AT_VOLUME_INFORMATION 0x70
+#define AT_DATA 0x80
+#define AT_INDEX_ROOT 0x90
+#define AT_INDEX_ALLOCATION 0xA0
+#define AT_BITMAP 0xB0
+#define AT_SYMLINK 0xC0
+#define AT_EA_INFORMATION 0xD0
+#define AT_EA 0xE0
+
+#define MAX_MFT_SIZE 1 // 1<<(1+9) = 1024
+#define MAX_IDX_SIZE 3 // 1<<(3+9) = 4096
+
+#define LOADSEG_NT 0x2000
+
+#define MMFT_BASE 0x2000
+#define MMFT_EMFT (MMFT_BASE +1024)
+#define MMFT_EBUF (MMFT_BASE + 2048)
+
+#define CMFT_BASE (MMFT_BASE + 6144)
+#define CMFT_EMFT (CMFT_BASE + 1024)
+#define CMFT_EBUF (CMFT_BASE + 2048)
+
+#define INDX_BASE (CMFT_BASE + 6144)
+
+#define SBUF_BASE (INDX_BASE + 4096)
+
+#define NTFS_Large_Structure_Error_Code 1
+#define NTFS_Corrupt_Error_Code 2
+#define NTFS_Run_Overflow_Error_Code 3
+#define NTFS_No_Data_Error_Code 4
+#define NTFS_Decompress_Error_Code 5
+
+#define NT_FG_COMP 1
+#define NT_FG_MMFT 2
+#define NT_FG_ALST 4
+#define NT_FG_GPOS 8
+
+#define nt_boot_drive -2(%bp)
+#define nt_blocksize -4(%bp)
+#define nt_spc -5(%bp)
+#define nt_mft_size -6(%bp)
+#define nt_idx_size -7(%bp)
+#define nt_mft_start -12(%bp)
+#define nt_remain_len -16(%bp)
+//#define nt_file_count -18(%bp)
+
+#define nt_flag (%di)
+#define nt_attr_cur 2(%di)
+#define nt_attr_nxt 4(%di)
+#define nt_attr_end 6(%di)
+#define nt_curr_vcn 8(%di)
+#define nt_curr_lcn 0x10(%di)
+#define nt_attr_ofs 0x14(%di)
+#define nt_target_vcn 0x18(%di)
+#define nt_read_count 0x1C(%di)
+#define nt_vcn_offset 0x20(%di)
+
+#define nt_emft_buf 1024(%di)
+#define nt_edat_buf 2048(%di)
+
+ .arch i586
+
+Entry_nt:
+ jmp 1f
+
+ . = Entry_nt + 0x02
+
+ .byte 0x90 /* for CHS. Another possible value is 0x0e for LBA */
+
+ .ascii "NTFS "
+
+ .word 0 /* 0B - Bytes per sector */
+ .byte 0 /* 0D - Sectors per cluster */
+ .word 0 /* 0E - reserved sectors, unused */
+ .byte 0 /* 10 - number of FATs, unused */
+ .word 0 /* 11 - Max dir entries for FAT12/FAT16, unused */
+ .word 0 /* 13 - total sectors for FAT12/FAT16, unused */
+ .byte 0xF8 /* 15 - Media descriptor */
+ .word 0 /* 16 - sectors per FAT for FAT12/FAT16, unused */
+ .word 255 /* 18 - Sectors per track */
+ .word 63 /* 1A - Number of heads */
+nt_part_ofs:
+ .long 0 /* 1C - hidden sectors */
+ .long 0 /* 20 - total sectors for FAT32, unused */
+ .long 0x800080
+ /* 24 - Usually 80 00 80 00, A value of 80 00 00 00 has
+ * been seen on a USB thumb drive which is formatted
+ * with NTFS under Windows XP. Note this is removable
+ * media and is not partitioned, the drive as a whole
+ * is NTFS formatted.
+ */
+ .long 0,0 /* 28 - Number of sectors in the volume */
+ .long 0,0 /* 30 - LCN of VCN 0 of the $MFT */
+ .long 0,0 /* 38 - LCN of VCN 0 of the $MFTMirr */
+ .long 0 /* 40 - Clusters per MFT Record */
+ .long 4 /* 44 - Clusters per Index Record */
+ .long 0,0 /* 48 - Volume serial number */
+ .long 0 /* 50 - Checksum, usually 0 */
+
+1:
+
+ . = Entry_nt + 0x54
+
+ cli
+ cld
+
+ . = Entry_nt + 0x56
+
+ /* the byte at offset 0x57 stores the real partition number for read.
+ * the format program or the caller should set it to a correct value.
+ * For floppies, it should be 0xff, which stands for whole drive.
+ */
+
+ movb $0xff, %dh /* boot partition number */
+
+ xorw %ax, %ax
+ movw %ax, %ds
+ movw $0x7c00, %bp
+ movw %ax, %es
+
+ movw %ax, %ss /* stack and BP-relative moves up, too */
+ leaw -0x20(%bp), %sp
+ sti
+
+ movw %dx, nt_boot_drive
+
+ /* Test if your BIOS support LBA mode */
+ movb $0x41, %ah
+ movw $0x55AA, %bx
+ int $0x13
+ jc 1f /* No EBIOS */
+ cmpw $0xAA55, %bx
+ jne 1f /* No EBIOS */
+ testb $1, %cl
+ jz 1f /* No EBIOS */
+ /* EBIOS supported */
+ movb $0x42, (ebios_nt - 1 - Entry_nt)(%bp)
+1:
+
+ cmpl $0x42555247, (nt_sector_mark - Entry_nt)(%bp)
+ jz 1f // Must be called from GRLDR.MBR
+
+ movw $0x7E00, %bx
+ movl (nt_part_ofs - Entry_nt)(%bp), %eax
+ incl %eax
+ call readDisk_nt // Load the second sector from disk
+ call readDisk_nt // Load the third sector from disk
+ call readDisk_nt
+1:
+
+ xorl %eax, %eax
+ movw 0xb(%bp), %ax // Bytes per sector (blocksize)
+ movw %ax, nt_blocksize
+
+ call convert_to_power_2
+ movb %cl, %bl
+ movb 0xd(%bp), %al // Sectors per cluster
+ call convert_to_power_2
+ movb %cl, %ch
+ addb %bl, %ch
+ subb $9, %ch // 1<<ch = sectors per cluster
+ movb %ch, nt_spc
+ movb 0x44(%bp), %al // Index record size (high bits of eax is 0)
+ call convert_size
+
+ cmpb $MAX_IDX_SIZE, %cl
+ jbe 1f
+
+NTFS_Large_Structure_Error:
+ movb $NTFS_Large_Structure_Error_Code, %al
+ jmp NTFS_Error
+
+1:
+ movb %cl, nt_idx_size
+
+ movb 0x40(%bp), %al // MFT record size
+ call convert_size
+
+ cmpb $MAX_MFT_SIZE, %cl
+ jnz NTFS_Large_Structure_Error
+
+ movb %cl, nt_mft_size
+
+ movl 0x30(%bp), %eax
+ movl 0x34(%bp), %edx
+
+ movb %ch, %cl // ch still contains nt_spc
+
+ shldl %cl, %eax, %edx
+ orl %edx, %edx
+ jnz NTFS_Large_Structure_Error
+
+ shll %cl, %eax
+ addl (nt_part_ofs - Entry_nt)(%bp), %eax
+ movl %eax, nt_mft_start
+
+ movw $1, %dx
+ movb nt_mft_size, %cl
+ shlw %cl, %dx
+ movw %dx, %cx
+
+ movw $MMFT_BASE, %bx
+ pushw %bx
+1:
+ call readDisk_nt
+ loop 1b
+
+ popw %bx
+ cmpw $0x4946, (%bx) // "FI"
+ jnz NTFS_Corrupt_Error
+
+ // dx should still contain the number of sectors in the MFT record
+ movw %dx, %cx
+ call ntfs_fixup
+
+ movw %bx, %di
+ movb $AT_DATA, %al // find $DATA
+
+ call ntfs_locate_attr
+ jc NTFS_Corrupt_Error
+
+ movw $CMFT_BASE, %bx
+ xorl %eax, %eax
+ movb $0x5, %al
+ call ntfs_read_mft
+ movw %bx, %di
+
+ jmp ntfs_search
+
+// Convert the size of MFT and IDX block
+// Input:
+// eax: size
+// ch: spc
+// Output:
+// cl: convert value
+convert_size:
+ orb %al, %al
+ js 1f
+ movb %ch, %cl
+ jmp 2f // Jump to 2 in convert_to_power_2
+1:
+ negb %al
+ subb $9, %al
+ movb %al, %cl
+ ret
+
+// Convert number to a power of 2
+// Input:
+// eax
+// Output:
+// cl: 1<<cl = eax
+// eax: 0
+
+convert_to_power_2:
+ xorb %cl, %cl
+2:
+ incb %cl
+ shrl $1, %eax
+ jnc 2b
+ decb %cl
+ ret
+
+// Fixup the "FILE" and "INDX" record
+// Input:
+// DS:BX - data buffer
+// CX - buffer length in sectors
+//
+
+ntfs_fixup:
+ push %bx
+ push %di
+ movw %bx, %di
+
+ movw 6(%bx), %ax // Size of Update Sequence
+ decw %ax
+ movw %ax, %bx
+
+ mulw nt_blocksize
+ shlw $9, %cx
+ cmpw %ax, %cx
+ jnz NTFS_Corrupt_Error // blocksize * count != size
+
+ movw %bx, %cx // cx = count
+
+ movw %di, %bx
+ addw 4(%bx), %bx // Offset to the update sequence
+ movw (%bx), %ax // Update Sequence Number
+ subw $2, %di
+
+1:
+ addw nt_blocksize, %di
+ addw $2, %bx
+ cmpw (%di), %ax
+ jnz NTFS_Corrupt_Error
+ movw (%bx), %dx
+ movw %dx, (%di)
+ loop 1b
+
+ popw %di
+ popw %bx
+ ret
+
+NTFS_Corrupt_Error:
+ movb $NTFS_Corrupt_Error_Code, %al
+ jmp NTFS_Error
+
+/* Read a sector from disk, using LBA or CHS
+ * input: EAX - 32-bit DOS sector number
+ * ES:BX - destination buffer
+ * (will be filled with 1 sector of data)
+ * output: ES:BX points one byte after the last byte read.
+ * EAX - next sector
+ */
+
+readDisk_nt:
+
+ pushal
+ xorl %edx, %edx /* EDX:EAX = LBA */
+ pushl %edx /* hi 32bit of sector number */
+ pushl %eax /* lo 32bit of sector number */
+ pushw %es /* buffer segment */
+ pushw %bx /* buffer offset */
+ pushw $1 /* 1 sector to read */
+ pushw $16 /* size of this parameter block */
+
+ xorl %ecx, %ecx
+ pushl 0x18(%bp) /* lo:sectors per track, hi:number of heads */
+ popw %cx /* ECX = sectors per track */
+ divl %ecx /* residue is in EDX */
+ /* quotient is in EAX */
+ incw %dx /* sector number in DL */
+ popw %cx /* ECX = number of heads */
+ pushw %dx /* push sector number into stack */
+ xorw %dx, %dx /* EDX:EAX = cylinder * TotalHeads + head */
+ divl %ecx /* residue is in EDX, head number */
+ /* quotient is in EAX, cylinder number */
+ xchgb %dl, %dh /* head number should be in DH */
+ /* DL = 0 */
+ popw %cx /* pop sector number from stack */
+ xchgb %al, %ch /* lo 8bit cylinder should be in CH */
+ /* AL = 0 */
+ shlb $6, %ah /* hi 2bit cylinder ... */
+ orb %ah, %cl /* ... should be in CL */
+
+ movw $0x201, %ax /* read 1 sector */
+ebios_nt: /* ebios_nt - 1 points to 0x02 that can be changed to 0x42 */
+
+// cmpb $0x0e, 2(%bp) /* force LBA? */
+// jnz 1f /* no, continue */
+// movb $0x42, %ah /* yes, use extended disk read */
+//1:
+ movw %sp, %si /* DS:SI points to disk address packet */
+ movb nt_boot_drive, %dl /* hard disk drive number */
+
+ int $0x13
+
+ popaw /* remove parameter block from stack */
+ popal
+ jc disk_error_nt /* disk read error, jc 1f if caller handles */
+ incl %eax /* next sector */
+ addw 0x0b(%bp), %bx /* bytes per sector */
+ jnc 1f /* 64K bound check */
+ pushw %dx
+ movw %es, %dx
+ addb $0x10, %dh /* add 1000h to ES */
+ /* here, carry is cleared */
+ movw %dx, %es
+ popw %dx
+1:
+ /* carry stored on disk read error */
+ ret
+
+msg_DiskReadError_nt:
+
+ .ascii "0\0"
+
+msg_NTFS_Not_Found_Error:
+ .ascii "No "
+
+nt_boot_image:
+#ifdef BOOTGRUB2
+ .ascii "g2ldr\0"
+#else
+ .ascii "grldr\0"
+#endif
+
+ . = nt_boot_image + 8
+
+nt_boot_image_end:
+
+NTFS_Error:
+ addb %al, (msg_DiskReadError_nt - Entry_nt)(%bp)
+ jmp disk_error_nt
+
+// Kernel load address, located at 0x1E8
+ . = Entry_nt + 0x1e8
+
+nt_loadseg_off:
+ .word 0
+ .word LOADSEG_NT
+
+// Boot image offset and length, located at 0x1EE
+// Lower 11 bit is offset, higher 5 bit is length
+ . = Entry_nt + 0x1ec
+
+nt_boot_image_ofs:
+ .word (nt_boot_image - Entry_nt)+(nt_boot_image_end - nt_boot_image-1)*2048
+
+ . = Entry_nt + 0x1ee
+
+disk_error_nt:
+
+ movw $(msg_DiskReadError_nt - Entry_nt + 0x7c00), %si
+
+boot_error_nt:
+
+/* prints string DS:SI (modifies AX BX SI) */
+
+//print_32:
+1:
+ lodsb (%si), %al /* get token */
+ //xorw %bx, %bx /* video page 0 */
+ movb $0x0e, %ah /* print it */
+ int $0x10 /* via TTY mode */
+ cmpb $0, %al /* end of string? */
+ jne 1b /* until done */
+
+ /* The caller will change this to
+ * ljmp $0x9400, $(try_next_partition - _start1)
+ */
+
+1: jmp 1b
+
+ . = Entry_nt + 0x1fc
+
+ .word 0, 0xAA55
+
+// Here starts sector #2
+
+// Input:
+// DI - current mft
+ntfs_search:
+ //movw $0, nt_file_count
+ call ntfs_init_attr
+ movb $AT_INDEX_ROOT, %al
+
+1:
+ call ntfs_find_attr
+ jc NTFS_Not_Found_Error
+
+ cmpl $0x180400, 8(%si) // resident
+ // namelen = 4
+ // name offset = 0x18
+ jnz 1b
+ //cmpl $0x490024, 0x18(%si) // "$I"
+ //jnz 1b
+ //cmpl $0x300033, 0x1C(%si)
+ //jnz 1b // "30"
+ //testw $0xC001, 12(%si) // not compressed, encrypted or sparse
+ //jnz 1b
+
+ addw 0x14(%si), %si // jump to attribute
+ cmpb $0x30, (%si)
+ jnz 1b // test if it index filenames
+
+ addw $0x10, %si // skip the index root
+ addw (%si), %si
+
+ call ntfs_find_grldr
+ jnc ntfs_final
+
+ call ntfs_init_attr
+ movb $AT_BITMAP, %al
+1:
+ call ntfs_find_attr
+ jc NTFS_Not_Found_Error
+ movw 9(%si), %bx
+ cmpb $4, %bl
+ jnz 1b
+ //shrw $4, %bx
+ //cmpl $0x490024, (%bx, %si) // "$I"
+ //jnz 1b
+ cmpb $0, 8(%si)
+ jnz 1f
+ pushw 0x10(%si)
+ addw 0x14(%si), %si
+ pushw %si
+ jmp 2f
+1:
+ pushw 0x30(%si)
+ xorl %edx, %edx
+ movl 0x28(%si), %ecx
+ cmpw $4096, %cx
+ ja NTFS_Not_Found_Error
+ shrl $9, %ecx
+ movw $SBUF_BASE, %bx
+ pushw %bx
+ call ntfs_read_data
+2:
+
+ movb $AT_INDEX_ALLOCATION, %al
+
+1:
+ call ntfs_locate_attr
+ jc NTFS_Not_Found_Error
+
+ cmpl $0x400401, 8(%si) // non-resident
+ // namelen = 4
+ // name offset = 0x40
+ jnz 1b
+ //cmpl $0x490024, 0x40(%si) // "$I"
+ //jnz 1b
+ //cmpl $0x300033, 0x44(%si)
+ //jnz 1b // "30"
+ //testw $0xC001, 12(%si) // not compressed, encrypted or sparse
+ //jnz 1b
+
+ movb nt_idx_size, %cl
+ xorl %ebx, %ebx
+ movb $1, %bl
+ shll %cl, %ebx // ebx - index size
+ xorl %edx, %edx // edx - index offset
+
+
+ popw %si
+ popw %cx
+
+1:
+ pushw %cx
+ lodsb (%si), %al
+
+ movw $8, %cx
+2:
+ pushw %cx
+ pushw %ax
+ testb $1, %al
+ jz 3f
+ pushw %si
+ pushl %edx
+ pushl %ebx
+
+ movl %ebx, %ecx
+ movw $INDX_BASE, %bx
+ call ntfs_read_attr
+ jc NTFS_Not_Found_Error
+ cmpw $0x4E49, (%bx) // "IN"
+ jnz NTFS_Not_Found_Error
+ call ntfs_fixup
+ movw %bx, %si
+ addw $0x18, %si
+ addw (%si), %si
+
+ call ntfs_find_grldr
+ jnc ntfs_final_0
+
+ popl %ebx
+ popl %edx
+ popw %si
+
+3:
+ addl %ebx, %edx
+
+ popw %ax
+ shrb $1, %al
+ popw %cx
+ loop 2b
+
+ popw %cx
+ loop 1b
+
+ //pushw nt_file_count
+ //call hex_out
+
+NTFS_Not_Found_Error:
+ leaw (msg_NTFS_Not_Found_Error - Entry_nt)(%bp), %si
+ jmp boot_error_nt
+
+ntfs_final_0:
+ //addw $16, %sp
+
+// Input:
+// DI - current mft
+// SI - index entry
+ntfs_final:
+ cmpw $0, 4(%si)
+ jnz NTFS_Large_Structure_Error
+
+ movl (%si), %eax
+ movw %di, %bx
+ call ntfs_read_mft
+
+ movb $AT_DATA, %al
+ call ntfs_locate_attr
+ jc NTFS_No_Data_Error
+
+ cmpb $1, 8(%si) // non-resident / resident
+ jz 1f
+
+ movw 0x10(%si), %cx // Resident
+ lesw (nt_loadseg_off - Entry_nt)(%bp), %di
+ addw 0x14(%si), %si
+ rep movsb (%si), %es:(%di)
+ jmp 2f
+
+1:
+
+ xorl %edx, %edx
+ movl 0x28(%si), %ecx // Use allocate size instead of real size
+ shrl $9, %ecx
+
+ lesw (nt_loadseg_off - Entry_nt)(%bp), %bx
+ call ntfs_read_data
+
+
+2:
+
+ //movb $1, (do_pause - Entry_nt)(%bp)
+ //call pause
+
+ movw nt_boot_drive, %dx
+ ljmp *(nt_loadseg_off - Entry_nt)(%bp)
+
+NTFS_No_Data_Error:
+ movb $NTFS_No_Data_Error_Code, %al
+ jmp NTFS_Error
+
+// Try to find GRLDR in the index
+// Input:
+// DS:SI - points to index entry
+// Output:
+// CF - status
+
+ntfs_find_grldr:
+ movw %si, %bx
+ testb $2, 0xC(%bx)
+ jz 1f
+ stc
+ ret
+1:
+ //incw nt_file_count
+
+ xorb %ch, %ch
+
+ pushw %si
+ leaw (nt_boot_image - Entry_nt)(%bp), %si
+ addw $0x52, %bx // The value at 0xA(%bx) is wrong sometimes (0x4C)
+ movb -2(%bx), %cl
+1:
+ lodsb (%si), %al
+ movb (%bx), %ah
+ cmpb $'A', %ah
+ jb 2f
+ cmpb $'Z', %ah
+ ja 2f
+ addb $('a'-'A'), %ah // Convert to lowercase
+2:
+
+ cmpb %ah, %al
+ jnz 3f // Not match
+
+ incw %bx
+ incw %bx
+ loop 1b
+
+ cmpb $0,(%si)
+ jnz 3f
+
+ popw %si
+ clc
+ ret // Match found
+
+3:
+
+ popw %si
+ addw 8(%si), %si
+
+ jmp ntfs_find_grldr
+
+// Locate an attribute
+// Input:
+// DI - pointer to buffer
+// AL - attribute
+ntfs_locate_attr:
+ call ntfs_init_attr
+ call ntfs_find_attr
+ jc 1f
+2:
+ testb $NT_FG_ALST, nt_flag
+ jnz 2f
+ call ntfs_find_attr
+ jnc 2b
+ call ntfs_init_attr
+ call ntfs_find_attr
+2:
+ clc
+1:
+ ret
+
+// Prepare to find attribute
+// Input:
+// DI - pointer to buffer
+ntfs_init_attr:
+ pushw %ax
+ xorw %ax, %ax
+ movw %ax, nt_flag
+ movw %ax, nt_attr_end
+ movw nt_attr_ofs, %ax
+ addw %di, %ax
+ movw %ax, nt_attr_nxt
+ popw %ax
+ cmpw $MMFT_BASE, %di
+ jnz 1f
+ orb $NT_FG_MMFT, nt_flag
+1:
+ ret
+
+// Find an attribute
+// Input:
+// DI - pointer to buffer
+// AL - attribute
+// Output:
+// SI - current item
+// CF - status
+ntfs_find_attr:
+ movw nt_attr_nxt, %bx
+ testb $NT_FG_ALST, nt_flag
+ jnz 6f
+1:
+ movw %bx, %si
+ cmpb $0xFF, (%si)
+ jz 3f
+
+ cmpb $AT_ATTRIBUTE_LIST, (%si)
+ jnz 2f
+ movw %si, nt_attr_end
+2:
+ addw 4(%bx), %bx
+ cmpb %al, (%si)
+ jnz 1b
+ movw %bx, nt_attr_nxt
+ movw %si, nt_attr_cur
+2:
+ ret
+3:
+ cmpw $1, nt_attr_end
+ jb 2b
+ movw nt_attr_end, %si
+ cmpb $0, 8(%si)
+ jnz 4f
+ movw %si, %bx
+ addw 0x14(%bx), %bx
+ addw 4(%si), %si
+ jmp 5f
+4:
+ movl 0x28(%si), %ecx
+ shrl $9, %ecx
+ cmpw $8, %cx
+ ja NTFS_Corrupt_Error
+ leaw nt_edat_buf, %bx
+ pushw %ax
+ xorl %edx, %edx
+ call ntfs_read_data
+ popw %ax
+ jc 2b
+ movw 0x30(%si), %si
+ addw %bx, %si
+5:
+ movw %si, nt_attr_end
+ orb $NT_FG_ALST, nt_flag
+ testb $NT_FG_MMFT, nt_flag
+ jz 6f
+ cmpb $AT_DATA, %al
+ jnz 6f
+ call ntfs_fix_mmft
+6:
+ movw %bx, %si
+ cmpw nt_attr_end, %bx
+ jb 1f
+7:
+ stc
+ ret
+1:
+ addw 4(%bx), %bx
+ cmpb %al, (%si)
+ jnz 6b
+
+ pushw %ax
+ pushw %es
+ pushw %ds
+ popw %es
+ movw %si, nt_attr_cur
+ movw %bx, nt_attr_nxt
+ movl 0x10(%si), %eax
+ leaw nt_emft_buf, %bx
+ testb $NT_FG_MMFT, nt_flag
+ jnz 2f
+ call ntfs_read_mft
+ jmp 3f
+2:
+ pushw %bx
+ call readDisk_nt
+ movl 0x14(%si), %eax
+ call readDisk_nt
+ popw %bx
+ cmpw $0x4946, (%bx) // "FI"
+ jnz NTFS_Corrupt_Error
+ movw $2, %cx
+ call ntfs_fixup
+3:
+ popw %es
+ popw %ax
+ addw 0x14(%bx), %bx
+4:
+ cmpb $0xFF, (%bx)
+ jz 7b
+ cmpb %al, (%bx)
+ jz 5f
+ addw 4(%bx), %bx
+ jmp 4b
+5:
+ movw %bx, %si
+ ret
+
+// Fix $MFT
+// Input:
+// DI - pointer to buffer
+// BX - attr cur
+ntfs_fix_mmft:
+ pushw %ax
+ orb $NT_FG_GPOS, nt_flag
+
+1:
+ cmpw nt_attr_end, %bx
+ jae NTFS_Corrupt_Error
+ cmpb %al, (%bx)
+ jz 2f
+ addw 4(%bx), %bx
+ jmp 1b
+2:
+
+ movw %bx, nt_attr_cur
+
+ movl nt_mft_start, %eax
+ movl %eax, 0x10(%bx)
+ incl %eax
+ movl %eax, 0x14(%bx)
+1:
+ addw 4(%bx), %bx
+
+ cmpw nt_attr_end, %bx
+ jae 2f
+ cmpb $AT_DATA, (%bx)
+ jnz 2f
+
+ movl 0x10(%bx), %edx
+ movb nt_mft_size, %cl
+ shll %cl, %edx
+
+ call ntfs_read_attr
+
+ orl %eax, %eax
+ jz NTFS_Corrupt_Error
+ movl %eax, 0x10(%bx)
+ movl %edx, 0x14(%bx)
+ jmp 1b
+2:
+ movw nt_attr_cur, %bx
+ andb $(~NT_FG_GPOS), nt_flag
+ popw %ax
+
+ ret
+
+// Read MFT record
+// Input:
+// DS:BX - buffer
+// EAX - mft number
+ntfs_read_mft:
+ pushw %di
+ movw $MMFT_BASE, %di
+ movb nt_mft_size, %cl
+ shll %cl, %eax
+ movl %eax, %edx
+ movl $1, %eax
+ shll %cl, %eax
+ movl %eax, %ecx
+ call ntfs_read_attr
+ jc NTFS_Corrupt_Error
+ cmpw $0x4946, (%bx) // "FI"
+ jnz NTFS_Corrupt_Error
+ call ntfs_fixup
+ popw %di
+ ret
+
+// Read attribute
+// Input:
+// DI - pointer to buffer
+// ES:BX - buffer
+// EDX - start sector
+// ECX - sector count
+// Output:
+// CF - status
+ntfs_read_attr:
+ pushw nt_attr_cur
+ pushl %edx
+ pushl %ecx
+ pushw %bx
+
+ movw nt_attr_cur, %si
+ movb (%si), %al
+
+ testb $NT_FG_ALST, nt_flag
+ jz 2f
+ movw %si, %bx
+ movb nt_spc, %cl
+ shrl %cl, %edx
+
+1:
+ cmpw nt_attr_end, %bx
+ jae 2f
+ cmpb %al, (%bx)
+ jnz 2f
+ cmpl %edx, 8(%bx)
+ ja 2f
+ movw %bx, %si
+ addw 4(%bx), %bx
+ jmp 1b
+2:
+
+ movw %si, nt_attr_nxt
+ call ntfs_find_attr
+
+ popw %bx
+ popl %ecx
+ popl %edx
+ jc 1f
+ call ntfs_read_data
+ clc
+1:
+ popw nt_attr_cur
+ ret
+
+// Read data
+// Input:
+// DI: pointer to buffer
+// SI: current item
+// ES:BX: buffer
+// EDX: start sector
+// ECX: sector count
+ntfs_read_data:
+ pushw %cx
+ pushw %bx
+ testb $1, 8(%si)
+ jz NTFS_Corrupt_Error
+ movb 0xC(%si), %al
+ andb $1, %al
+ orb %al, nt_flag
+
+ movl %ecx, nt_read_count
+ movb nt_spc, %cl
+
+ movl %edx, %eax
+ shrl %cl, %eax
+ movl %eax, nt_target_vcn
+ shll %cl, %eax
+ subl %eax, %edx
+ movl %edx, nt_vcn_offset
+
+ xorw %dx, %dx // edx - next VCN
+ movl %edx, nt_curr_lcn
+
+ movl 0x10(%si), %edx
+
+ addw 0x20(%si), %si
+1:
+ call ntfs_runlist_read_block
+
+ cmpl nt_target_vcn, %edx
+ jbe 1b
+1:
+ movb nt_spc, %cl
+
+ orl %eax, %eax // sparse
+ jz 2f
+
+ movl nt_target_vcn, %eax
+ subl nt_curr_vcn, %eax
+ addl nt_curr_lcn, %eax
+
+ shll %cl, %eax
+ addl nt_vcn_offset, %eax
+
+ testb $NT_FG_GPOS, nt_flag
+ jz 3f
+ pushl %eax
+ incl %eax
+ subl nt_curr_vcn, %edx
+ addl nt_curr_lcn, %edx
+ shll %cl, %edx
+ cmpl %eax, %edx
+ jnz 4f
+ pushw %cx
+ call ntfs_runlist_read_block
+ popw %cx
+ movl nt_curr_lcn, %eax
+ shll %cl, %eax
+4:
+ movl %eax, %edx
+ popl %eax
+ addl (nt_part_ofs - Entry_nt)(%bp), %edx
+3:
+
+ addl (nt_part_ofs - Entry_nt)(%bp), %eax
+
+2:
+ testb $NT_FG_GPOS, nt_flag
+ jnz 1f
+
+ pushl %ebx
+ movl %edx, %ebx
+ subl nt_target_vcn, %ebx
+ shll %cl, %ebx
+ movl %ebx, %ecx
+ popl %ebx
+
+ subl nt_vcn_offset, %ecx
+ movl $0, nt_vcn_offset
+ cmpl nt_read_count, %ecx
+ jbe 2f
+ movl nt_read_count, %ecx
+2:
+
+ pushl %ecx
+
+ orl %eax, %eax
+ jnz 3f
+ call ntfs_sparse_block
+ jmp 4f
+
+3:
+ call readDisk_nt
+ loop 3b
+
+4:
+ popl %ecx
+ subl %ecx, nt_read_count
+ jbe 1f
+
+ movl %edx, nt_target_vcn
+ call ntfs_runlist_read_block
+ jmp 1b
+
+1:
+ popw %bx
+ popw %cx
+ ret
+
+// Read run list data
+// Input:
+// CL = number of bytes
+// Output:
+// EAX = read bytes
+// SI points to the next unhandled byte
+
+ntfs_runlist_read_data:
+ pushw %cx
+ orb %cl, %cl
+ jnz 1f
+ popw %cx
+ xorl %eax, %eax
+ ret
+1:
+ lodsb (%si), %al
+ rorl $8, %eax
+ decb %cl
+ jnz 1b
+
+ popw %cx
+ negb %cl
+ add $4, %cl
+ shlb $3, %cl
+ ret
+
+NTFS_Run_Overflow_Error:
+ movb $NTFS_Run_Overflow_Error_Code, %al
+ jmp NTFS_Error
+
+// Read run list block
+// Output:
+// EDX = Next VCN
+// SI points to the next unhandled byte
+
+ntfs_runlist_read_block:
+ lodsb (%si), %al
+ movb %al, %cl
+ movb %cl, %ch
+ andb $0xF, %cl // cl - Size of length field
+ jz 1f
+ shrb $0x4, %ch // ch - Size of offset field
+
+ call ntfs_runlist_read_data
+ shrl %cl, %eax
+
+ movl %edx, nt_curr_vcn
+ addl %eax, %edx
+
+ movb %ch, %cl
+ call ntfs_runlist_read_data
+ sarl %cl, %eax
+
+ addl %eax, nt_curr_lcn
+
+ ret
+
+1:
+ testb $NT_FG_ALST, nt_flag
+ jz NTFS_Run_Overflow_Error
+
+ pushl %edx
+ pushw %bx
+ movw nt_attr_cur, %si
+ movb (%si), %al
+ call ntfs_find_attr
+ jc NTFS_Run_Overflow_Error
+ cmpb $0, 8(%si)
+ jz NTFS_Run_Overflow_Error
+ movl $0, nt_curr_lcn
+ popw %bx
+ popl %edx
+ addw 0x20(%si), %si
+ jmp ntfs_runlist_read_block
+
+// Convert seg:ofs to linear address
+// Input:
+// On stack: seg:ofs
+// Output:
+// eax:
+seg_to_lin:
+ pushw %bp
+ movw %sp, %bp
+ xorl %eax, %eax
+ xchgw 6(%bp), %ax
+ shll $4, %eax
+ addl 4(%bp), %eax
+ popw %bp
+ ret $4
+
+// Convert linear address to seg:ofs
+// Input:
+// on stack: linear address
+// Output:
+// On stack: seg:ofs
+lin_to_seg:
+ pushw %bp
+ movw %sp, %bp
+ shll $12, 4(%bp)
+ shrw $12, 4(%bp)
+ popw %bp
+ ret
+
+fix_segs:
+ pushw %ds
+ pushw %si
+ call seg_to_lin
+ pushl %eax
+ call lin_to_seg
+ popw %si
+ popw %ds
+
+fix_es_di:
+ pushw %es
+ pushw %di
+ call seg_to_lin
+ pushl %eax
+ call lin_to_seg
+ popw %di
+ popw %es
+ ret
+
+// Handle sparse block
+// DI: points to buffer
+// ES:BX: points to buffer
+// ECX: number of sectors
+// EDX: next VCN
+
+ntfs_sparse_block:
+ pushw %di
+ pushl %edx
+
+ shll $9, %ecx // ecx - totel number of bytes
+
+ testb $1, nt_flag // Not compressed
+ jz 2f
+
+ xorl %edx, %edx
+ movb nt_target_vcn, %dl
+ andb $0xF, %dl
+ jz 2f
+
+ movw %bx, %di
+
+ pushw %cx
+
+ movb nt_spc, %cl
+ addb $9, %cl
+ shll %cl, %edx // edx: offset from the start of cluster
+
+ push %es
+ push %di
+ call seg_to_lin
+ subl %edx, %eax // eax: linear address
+
+ movl $16, nt_remain_len
+ shll %cl, nt_remain_len
+
+ popw %cx
+
+ addl %edx, %ecx
+ subl nt_remain_len, %ecx
+
+ pushl %ecx
+ call ntfs_decomp_block
+ popl %ecx
+
+ addl nt_remain_len, %ecx
+
+ jecxz 1f
+
+ movw %di, %bx
+
+2:
+ movw %bx, %di
+ movl %ecx, %edx
+ xorl %eax, %eax
+ movl %eax, %ecx
+ call fix_es_di
+
+3:
+ movw $0x8000, %cx
+ cmpl %edx, %ecx
+ jbe 4f
+ movw %dx, %cx
+4:
+ pushw %cx
+ shrw $2, %cx
+
+ rep stosl %eax, %es:(%di)
+ call fix_es_di
+ popw %cx
+ subl %ecx, %edx
+ jnz 3b
+
+1:
+ movw %di, %bx
+
+ popl %edx
+ popw %di
+
+ ret
+
+// Decompress block
+// Input:
+// eax: linear address at the beginning of the compressed block
+// Output:
+// ES:DI: points to the end of the block
+ntfs_decomp_block:
+ pushw %ds
+ pushw %si
+
+ pushl %eax
+ call lin_to_seg
+ popw %si
+ popw %ds
+ movl nt_remain_len, %edx
+ addl %edx, %eax
+ pushl %eax
+ call lin_to_seg
+ popw %di
+ popw %es
+
+ pushw %es
+ pushw %di
+ pushw %ds
+ pushw %si
+
+ xorl %ecx, %ecx
+
+1:
+ movw $0x8000, %cx
+ cmpl %edx, %ecx
+ jbe 2f
+ movw %dx, %cx
+2:
+ pushw %cx
+ shrw $2, %cx
+ rep movsl (%si), %es:(%di)
+ call fix_segs
+ popw %cx
+ subl %ecx, %edx
+ jnz 1b
+
+ popw %di
+ popw %es
+ popw %si
+ popw %ds
+
+1:
+ xorl %edx, %edx // edx - copied bytes
+
+ lodsw (%si), %ax
+ testb $0x80, %ah
+ jnz 2f
+ movw $0x800, %cx
+ rep movsw (%si), %es:(%di)
+ movw $0x1000, %dx
+ jmp 7f // The block is not compressed
+
+2:
+ movw %ax, %cx
+ andw $0xFFF, %cx
+ incw %cx // ecx = block length
+ addw %si, %cx // cx: end marker
+ xorb %bh, %bh
+
+3:
+ cmpw $0x1000, %dx
+ ja NTFS_Decompress_Error
+
+ orb %bh, %bh
+ jnz 4f
+ lodsb (%si), %al
+ movb %al, %bl // bl: tag, bh: count
+ movb $8, %bh
+4:
+
+ testb $1, %bl
+ jz 5f
+
+ movw %dx, %ax
+ decw %ax
+
+ pushw %cx
+ pushw %bx
+
+ movb $12, %cl
+6:
+ cmpw $0x10, %ax
+ jb 6f
+ shrw $1, %ax
+ decb %cl
+ jmp 6b
+6:
+
+ lodsw (%si), %ax
+ movw %ax, %bx
+ shrw %cl, %bx // bx: delta
+
+ pushw %dx
+ movw $1, %dx
+ shlw %cl, %dx
+ decw %dx
+ andw %dx, %ax
+ popw %dx
+
+ addw $3, %ax
+ movw %ax, %cx // cx: length
+ negw %bx
+ decw %bx
+
+6:
+ movb %es:(%bx, %di), %al
+ stosb %al, %es:(%di)
+ incw %dx
+ loop 6b
+
+ popw %bx
+ popw %cx
+ jmp 4f
+
+5:
+ movsb (%si), %es:(%di)
+ incw %dx
+4:
+ shrb $1, %bl
+ decb %bh
+
+ cmpw %cx, %si
+ jb 3b
+
+7:
+ call fix_segs
+
+ subl %edx, nt_remain_len // End of block
+ jz 1f
+
+ cmpw $0x1000, %dx
+ je 1b
+
+1:
+
+ popw %si
+ popw %ds
+ ret
+
+NTFS_Decompress_Error:
+ pushw %ss
+ popw %ds
+ movb $NTFS_Decompress_Error_Code, %al
+ jmp NTFS_Error
+
+/*
+do_pause:
+ .byte 0
+
+pause:
+ cmpb $0, (do_pause - Entry_nt)(%bp)
+ jnz 1f
+ ret
+1:
+ xorw %bp, %bp
+1:
+ jmp 1b
+*/
+
+/*
+hex_out:
+ pushw %bp
+ movw %sp, %bp
+ pushaw
+ movb $0xE, %ah
+ movw $7, %bx
+ movw $4, %cx
+ movw 4(%bp), %dx
+1:
+ rol $4, %dx
+ movb %dl, %al
+ andb $0xF, %al
+ cmpb $10, %al
+ jb 2f
+ subb $('0'-'A'+10), %al
+2:
+ addb $'0', %al
+ int $0x10
+ loop 1b
+ movb $' ', %al
+ int $0x10
+ popaw
+ popw %bp
+ ret $2
+*/
+
+ . = Entry_nt + 0x7fc
+
+nt_sector_mark:
+ .long 0x42555247 // "GRUB"
diff --git a/debian/grub-extras/ntldr-img/utils.c b/debian/grub-extras/ntldr-img/utils.c
new file mode 100644
index 0000000..d1f3bfa
--- /dev/null
+++ b/debian/grub-extras/ntldr-img/utils.c
@@ -0,0 +1,392 @@
+/*
+ * GRUB Utilities -- Utilities for GRUB Legacy, GRUB2 and GRUB for DOS
+ * Copyright (C) 2007 Bean (bean123@126.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef LINUX
+
+#define _FILE_OFFSET_BITS 64 // This is required to enable 64-bit off_t
+#include <unistd.h>
+
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "utils.h"
+
+static unsigned char ebuf[512];
+
+#if defined(WIN32)
+
+#ifdef __GNUC__ // Mingw or Cygwin
+
+#define u_off_t off64_t
+#define u_lseek lseek64
+
+#else
+
+#define u_off_t __int64
+#define u_lseek _lseeki64
+
+#endif
+
+#else
+
+#define u_off_t off_t // In FreeBSD, off_t is 64-bit !
+#define u_lseek lseek
+
+#endif
+
+int go_sect(int hd,unsigned long sec)
+{
+ // Test if 64-bit seek is supported
+ if (sizeof(u_off_t)>=8)
+ {
+ u_off_t bs,rs;
+
+ bs=sec;
+ bs<<=9;
+ rs=u_lseek(hd,bs,SEEK_SET);
+ return (bs!=rs);
+ }
+ else
+ {
+ unsigned long bs[2];
+
+ bs[0]=sec<<9;
+ bs[1]=sec>>23;
+ if (bs[1])
+ return 1;
+ return (lseek(hd,bs[0],SEEK_SET)!=(off_t)bs[0]);
+ }
+}
+
+// Partition enumerator
+// xe->cur is the current partition number, before the first call to xd_enum,
+// it should be set to 0xFF
+// xe->nxt is the target partition number, if it equals 0xFF, it means enumerate
+// all partitions, otherwise, it means jump to the specific partition.
+int xd_enum(int hd,xde_t* xe)
+{
+ int nn=512,kk=1,cc;
+
+ for (cc=xe->cur;;)
+ {
+ if (cc==0xFF)
+ {
+ unsigned long pt[4][2];
+ int i,j,np;
+
+ if (go_sect(hd,0))
+ return 1;
+ if (read(hd,ebuf,nn)!=nn)
+ return 1;
+ if (get16(ebuf,0x1FE)!=0xAA55)
+ return 1;
+ np=0;
+ for (i=0x1BE;i<0x1FE;i+=16)
+ if (ebuf[i+4])
+ {
+ if ((pt[np][1]=get32(ebuf,i+12))==0)
+ return 1;
+ pt[np++][0]=get32(ebuf,i+8);
+ }
+ if (np==0)
+ return 1;
+ // Sort partition table base on start address
+ for (i=0;i<np-1;i++)
+ {
+ int k=i;
+ for (j=i+1;j<np;j++)
+ if (pt[k][0]>pt[j][0]) k=j;
+ if (k!=i)
+ {
+ unsigned long tt;
+
+ tt=pt[i][0];
+ pt[i][0]=pt[k][0];
+ pt[k][0]=tt;
+ tt=pt[i][1];
+ pt[i][1]=pt[k][1];
+ pt[k][1]=tt;
+ }
+ }
+ // Should have space for MBR
+ if (pt[0][0]==0)
+ return 1;
+ // Check for partition overlap
+ for (i=0;i<np-1;i++)
+ if (pt[i][0]+pt[i][1]>pt[i+1][0])
+ return 1;
+ cc=0;
+ }
+ else if (kk)
+ cc++;
+ if ((unsigned char)cc>xe->nxt)
+ return 1;
+ if (cc<4)
+ {
+ if (xe->nxt<4)
+ {
+ // Empty partition
+ if (! ebuf[xe->nxt*16+4+0x1BE])
+ return 1;
+ xe->cur=xe->nxt;
+ xe->dfs=ebuf[xe->nxt*16+4+0x1BE];
+ xe->bse=get32(ebuf,xe->nxt*16+8+0x1BE);
+ xe->len=get32(ebuf,xe->nxt*16+12+0x1BE);
+ return 0;
+ }
+ else if (xe->nxt!=0xFF)
+ cc=4;
+ else while (cc<4)
+ {
+ if (ebuf[cc*16+4+0x1BE])
+ {
+ xe->cur=cc;
+ xe->dfs=ebuf[cc*16+4+0x1BE];
+ xe->bse=get32(ebuf,cc*16+8+0x1BE);
+ xe->len=get32(ebuf,cc*16+12+0x1BE);
+ return 0;
+ }
+ cc++;
+ }
+ }
+ if ((cc==4) && (kk))
+ {
+ int i;
+
+ // Scan for extended partition
+ for (i=0;i<4;i++)
+ if ((ebuf[i*16+4+0x1BE]==5) || (ebuf[i*16+4+0x1BE]==0xF)) break;
+ if (i==4)
+ return 1;
+ xe->ebs=xe->bse=get32(ebuf,i*16+8+0x1BE);
+ }
+ else
+ {
+ // Is end of extended partition chain ?
+ if (((ebuf[4+0x1CE]!=0x5) && (ebuf[4+0x1CE]!=0xF)) ||
+ (get32(ebuf,8+0x1CE)==0))
+ return 1;
+ xe->bse=xe->ebs+get32(ebuf,8+0x1CE);
+ }
+ {
+ while (1)
+ {
+ if (go_sect(hd,xe->bse))
+ return 1;
+
+ if (read(hd,ebuf,nn)!=nn)
+ return 1;
+
+ if (get16(ebuf,0x1FE)!=0xAA55)
+ return 1;
+
+ if ((ebuf[4+0x1BE]==5) || (ebuf[4+0x1BE]==0xF))
+ {
+ if (get32(ebuf,8+0x1BE)==0)
+ return 1;
+ else
+ {
+ xe->bse=xe->ebs+get32(ebuf,8+0x1BE);
+ continue;
+ }
+ }
+ break;
+ }
+ kk=(ebuf[4+0x1BE]!=0);
+ if ((kk) && ((xe->nxt==0xFF) || (cc==xe->nxt)))
+ {
+ xe->cur=cc;
+ xe->dfs=ebuf[4+0x1BE];
+ xe->bse+=get32(ebuf,8+0x1BE);
+ xe->len=get32(ebuf,12+0x1BE);
+ return 0;
+ }
+ }
+ }
+}
+
+#define EXT2_SUPER_MAGIC 0xEF53
+
+int mbr_nhd, mbr_spt;
+
+static void split_chs(unsigned char* chs,unsigned long* c,unsigned long* h,unsigned long* s)
+{
+ *h=chs[0];
+ *s=(chs[1] & 0x3F)-1;
+ *c=((unsigned long)(chs[1]>>6))*256+chs[2];
+}
+
+static int chk_chs(unsigned long nhd,unsigned long spt,unsigned long lba,unsigned char* chs)
+{
+ unsigned long c,h,s;
+
+ split_chs(chs,&c,&h,&s);
+ if (c==0x3FF)
+ return ((nhd==h+1) && (spt==s+1));
+ else
+ return (c*nhd*spt+h*spt+s==lba);
+}
+
+static int chk_mbr(unsigned char* buf)
+{
+ unsigned long nhd,spt,a1,a2,c2,h2,s2;
+ int i;
+
+ i=0x1BE;
+ while ((i<0x1FE) && (buf[i+4]==0))
+ i+=16;
+ if (i>=0x1FE)
+ return 0;
+ a1=get32(&buf[i],8);
+ a2=a1+get32(&buf[i],12)-1;
+ if (a1>=a2)
+ return 0;
+ split_chs(buf+i+5,&c2,&h2,&s2);
+ if (c2==0x3FF)
+ {
+ nhd=h2+1;
+ spt=s2+1;
+ if (! chk_chs(nhd,spt,a1,buf+i+1))
+ return 0;
+ }
+ else
+ {
+ unsigned long c1,h1,s1;
+ long n1,n2;
+
+ split_chs(buf+i+1,&c1,&h1,&s1);
+ if ((c1==0x3FF) || (c1>c2))
+ return 0;
+ n1=(long)(c1*a2)-(long)(c2*a1)-(long)(c1*s2)+(long)(c2*s1);
+ n2=(long)(c1*h2)-(long)(c2*h1);
+ if (n2<0)
+ {
+ n2=-n2;
+ n1=-n1;
+ }
+ if ((n2==0) || (n1<=0) || (n1 % n2))
+ return 0;
+ spt=(unsigned long)(n1/n2);
+ if (c2)
+ {
+ n1=(long)a2-(long)s2-(long)(h2*spt);
+ n2=(long)(c2*spt);
+ if ((n2==0) || (n1<=0) || (n1 % n2))
+ return 0;
+ nhd=(unsigned long)(n1/n2);
+ }
+ else
+ nhd=h2+1;
+ }
+ if ((nhd==0) || (nhd>255) || (spt==0) || (spt>63))
+ return 0;
+ i+=16;
+ while (i<0x1FE)
+ {
+ if (buf[i+4])
+ {
+ if ((! chk_chs(nhd,spt,get32(&buf[i],8),buf+i+1)) ||
+ (! chk_chs(nhd,spt,get32(&buf[i],8)+get32(&buf[i],12)-1,buf+i+5)))
+ return 0;
+ }
+ i+=16;
+ }
+ mbr_nhd=(int)nhd;
+ mbr_spt=(int)spt;
+ return 1;
+}
+
+int get_fstype(unsigned char* buf)
+{
+ if (chk_mbr(buf))
+ return FST_MBR;
+
+ // The first sector of EXT2 might not contain the 0xAA55 signature
+ if (get16(&buf[1024],56)==EXT2_SUPER_MAGIC)
+ return FST_EXT2;
+ if (get16(&buf[0],0x1FE)!=0xAA55)
+ return FST_OTHER;
+ if (! memcmp(&buf[0x36],"FAT",3))
+ return ((buf[0x26]==0x28) || (buf[0x26]==0x29))?FST_FAT16:FST_OTHER;
+ if (! memcmp(&buf[0x52],"FAT32",5))
+ return ((buf[0x42]==0x28) || (buf[0x42]==0x29))?FST_FAT32:FST_OTHER;
+ if (! memcmp(&buf[0x3],"NTFS",4))
+ return ((buf[0]==0xEB) && (buf[1]==0x52))?FST_NTFS:FST_OTHER;
+ return FST_OTHER;
+}
+
+const char* fst2str(int fs)
+{
+ switch (fs) {
+ case FST_OTHER:
+ return "Other";
+ case FST_MBR:
+ return "MBR";
+ case FST_FAT16:
+ return "FAT12/FAT16";
+ case FST_FAT32:
+ return "FAT32";
+ case FST_NTFS:
+ return "NTFS";
+ case FST_EXT2:
+ return "EXT2/EXT3";
+ default:
+ return "Unknown";
+ }
+}
+
+typedef struct {
+ int id;
+ const char* str;
+} fstab_t;
+
+static fstab_t fstab[]= {
+ {0x1,"FAT12"},
+ {0x4,"FAT16"},
+ {0x5,"Extended"},
+ {0x6,"FAT16B"},
+ {0x7,"NTFS"},
+ {0xB,"FAT32"},
+ {0xC,"FAT32X"},
+ {0xE,"FAT16X"},
+ {0xF,"ExtendedX"},
+ {0x11,"(H)FAT12"},
+ {0x14,"(H)FAT16"},
+ {0x16,"(H)FAT16B"},
+ {0x17,"(H)NTFS"},
+ {0x1B,"(H)FAT32"},
+ {0x1C,"(H)FAT32X"},
+ {0x1E,"(H)FAT16X"},
+ {0x82,"Swap"},
+ {0x83,"Ext2"},
+ {0xA5,"FBSD"},
+ {0,"Other"}};
+
+const char* dfs2str(int fs)
+{
+ int i;
+
+ for (i=0;fstab[i].id;i++)
+ if (fs==fstab[i].id)
+ return fstab[i].str;
+ return fstab[i].str;
+}
diff --git a/debian/grub-extras/ntldr-img/utils.h b/debian/grub-extras/ntldr-img/utils.h
new file mode 100644
index 0000000..e48aac8
--- /dev/null
+++ b/debian/grub-extras/ntldr-img/utils.h
@@ -0,0 +1,88 @@
+/*
+ * GRUB Utilities -- Utilities for GRUB Legacy, GRUB2 and GRUB for DOS
+ * Copyright (C) 2007 Bean (bean123@126.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __UTILS_H
+#define __UTILS_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define MAX_DISKS 10
+#define MAX_PARTS 30
+
+#define FST_OTHER 0
+#define FST_MBR 1
+#define FST_FAT16 2
+#define FST_FAT32 3
+#define FST_NTFS 4
+#define FST_EXT2 5
+
+typedef struct {
+ unsigned char cur; // Current partition number
+ unsigned char nxt; // Next partition number
+ unsigned char dfs; // File system flag
+ unsigned char pad; // Padding
+ unsigned long bse; // Partition start address
+ unsigned long len; // Partition length
+ unsigned long ebs; // Base address for the extended partition
+} __attribute__ ((packed)) xde_t;
+
+static inline unsigned short
+get16 (const void *buf_, unsigned offset)
+{
+ unsigned char *buf = (unsigned char *) buf_ + offset;
+ return buf[0] | (buf[1] << 8);
+}
+static inline unsigned int
+get32 (const void *buf_, unsigned offset)
+{
+ unsigned char *buf = (unsigned char *) buf_ + offset;
+ return buf[0] | (buf[1] << 8) | (buf[1] << 16) | (buf[1] << 24);
+}
+
+static inline void
+set16 (void *buf_, unsigned offset, unsigned short val)
+{
+ unsigned char *buf = (unsigned char *) buf_ + offset;
+ buf[0] = val;
+ buf[1] = val >> 8;
+}
+
+static inline void
+set32 (void *buf_, unsigned offset, unsigned int val)
+{
+ unsigned char *buf = (unsigned char *) buf_ + offset;
+ buf[0] = val;
+ buf[1] = val >> 8;
+ buf[2] = val >> 16;
+ buf[3] = val >> 24;
+}
+
+extern int mbr_nhd, mbr_spt;
+int go_sect(int,unsigned long);
+int xd_enum(int,xde_t*);
+int get_fstype(unsigned char*);
+const char* fst2str(int);
+const char* dfs2str(int);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+#endif /* __UTILS_H */
diff --git a/debian/grub-extras/ntldr-img/version.h b/debian/grub-extras/ntldr-img/version.h
new file mode 100644
index 0000000..ce84ad6
--- /dev/null
+++ b/debian/grub-extras/ntldr-img/version.h
@@ -0,0 +1,3 @@
+#define VERSION "1.1"
+#define VER_MAJOR 1
+#define VER_MINOR 1