aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYING674
-rw-r--r--Makefile88
-rw-r--r--README71
-rw-r--r--TODO22
-rw-r--r--src/biosvar.h184
-rw-r--r--src/boot.c118
-rw-r--r--src/cbt.c8
-rw-r--r--src/clock.c54
-rw-r--r--src/cmos.h51
-rw-r--r--src/config.h8
-rw-r--r--src/disk.c67
-rw-r--r--src/disk.h33
-rw-r--r--src/farptr.h57
-rw-r--r--src/floppy.c757
-rw-r--r--src/font.c139
-rw-r--r--src/ioport.h56
-rw-r--r--src/kbd.c35
-rw-r--r--src/output.c161
-rw-r--r--src/post.c312
-rw-r--r--src/rombios32.lds.S31
-rw-r--r--src/romlayout.S304
-rw-r--r--src/serial.c23
-rw-r--r--src/system.c529
-rw-r--r--src/types.h21
-rw-r--r--src/util.h55
-rwxr-xr-xtools/buildrom.py78
-rwxr-xr-xtools/defsyms.py38
27 files changed, 3974 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/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/Makefile b/Makefile
new file mode 100644
index 0000000..28ac276
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,88 @@
+# Legacy Bios build system
+#
+# Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Output directory
+OUT=out/
+
+# Source files
+SRC16=floppy.c disk.c system.c clock.c serial.c kbd.c output.c boot.c
+SRC32=post.c output.c
+
+# Default compiler flags (note -march=armv4 is needed for 16 bit insns)
+CFLAGS = -Wall -Os -MD -m32 -march=i386 -mregparm=2 -ffreestanding
+CFLAGS16 = -Wall -Os -MD -m32 -DMODE16 -march=i386 -mregparm=2 -ffreestanding -fno-jump-tables
+
+all: $(OUT) $(OUT)rom.bin
+
+# Run with "make V=1" to see the actual compile commands
+ifdef V
+Q=
+else
+Q=@
+endif
+
+.PHONY : all FORCE
+
+vpath %.c src
+vpath %.S src
+
+################ Build rules
+$(OUT)%.proc.16.s: $(OUT)%.16.s
+ @echo " Moving data sections to text in $<"
+ $(Q)sed 's/\t.section\t.rodata.*// ; s/\t.data//' < $< > $@
+
+$(OUT)%.16.s: %.c
+ @echo " Generating assembler for $<"
+ $(Q)$(CC) $(CFLAGS16) -fwhole-program -S -combine -c $< -o $@
+
+$(OUT)%.lds: %.lds.S
+ @echo " Precompiling $<"
+ $(Q)$(CPP) -P $< -o $@
+
+$(OUT)%.bin: $(OUT)%.o
+ @echo " Extracting binary $@"
+ $(Q)objcopy -O binary $< $@
+
+$(OUT)%.offset.auto.h: $(OUT)%.o
+ @echo " Generating symbol offset header $@"
+ $(Q)nm $< | ./tools/defsyms.py > $@
+
+$(OUT)blob.16.s:
+ @echo " Generating whole program assembler $@"
+ $(Q)$(CC) $(CFLAGS16) -fwhole-program -S -combine -c $(addprefix src/, $(SRC16)) -o $@
+
+$(OUT)romlayout16.o: romlayout.S $(OUT)blob.proc.16.s $(OUT)font.proc.16.s $(OUT)cbt.proc.16.s
+ @echo " Generating 16bit layout of $@"
+ $(Q)$(CC) $(CFLAGS16) -c $< -o $@
+
+$(OUT)rom16.o: $(OUT)romlayout16.o
+ @echo " Linking $@"
+ $(Q)ld -melf_i386 -Ttext 0 $< -o $@
+
+$(OUT)rom16.bin: $(OUT)rom16.o
+ @echo " Extracting binary $@"
+ $(Q)objcopy -O binary $< $@
+
+$(OUT)romlayout32.o: $(OUT)rom16.offset.auto.h
+ @echo " Compiling whole program $@"
+ $(Q)$(CC) $(CFLAGS) -fwhole-program -combine -c $(addprefix src/, $(SRC32)) -o $@
+
+$(OUT)rom32.o: $(OUT)romlayout32.o $(OUT)rombios32.lds
+ @echo " Linking $@"
+ $(Q)ld -T $(OUT)rombios32.lds $< -o $@
+
+$(OUT)rom.bin: $(OUT)rom16.bin $(OUT)rom32.bin $(OUT)rom16.offset.auto.h $(OUT)rom32.offset.auto.h
+ @echo " Building $@"
+ $(Q)./tools/buildrom.py
+
+####### Generic rules
+clean:
+ rm -rf $(OUT)
+
+$(OUT):
+ mkdir $@
+
+-include $(OUT)*.d
diff --git a/README b/README
new file mode 100644
index 0000000..ce80499
--- /dev/null
+++ b/README
@@ -0,0 +1,71 @@
+This code implements an X86 legacy bios. It is intended to be
+compiled using standard gnu tools (eg, gas and gcc).
+
+To build, one should be able to run "make" in the main directory. The
+resulting file "out/rom.bin" contains the processed bios image.
+
+The code has been successfully compiled with gcc 4.1.2 and gas
+2.17.50.0.18.
+
+
+Overview of files:
+
+The src/ directory contains the bios source code. The post.c code is
+compiled in 32bit mode. The output.c code is compiled twice - once in
+16bit mode and once in 32bit mode. The remaining c files are compiled
+in 16bit mode.
+
+The tools/ directory contains helper utilities for manipulating and
+building the final rom.
+
+The out/ directory is created by the build process - it contains all
+temporary and final files.
+
+
+Build overview:
+
+The 16bit code is compiled via gcc to assembler (file out/blob.16.s).
+The gcc "-fwhole-program" option is used to optimize the process so
+that gcc can efficiently compile and discard unneeded code.
+
+This resulting assembler code is pulled into romlayout.S. The gas
+option ".code16gcc" is used prior to including the gcc generated
+assembler - this option enables gcc to be used to generate valid 16
+bit code. The romlayout.S also defines all the mandatory bios visible
+memory locations.
+
+The post code (post.c) is written in 32bits. The 16bit post vector
+(in romlayout.S) transitions the cpu into 32 bit mode before calling
+the initialization code in post.c.
+
+In the last step, the compiled 32 bit code is merged into the 16 bit
+code so that one binary file contains both. Currently, both 16bit and
+32bit code will be located in the 64K block at segment 0xf000.
+
+
+GCC 16 bit limitations:
+
+Although the 16bit code is compiled with gcc, developers need to be
+aware of the environment. In particular, global variables _must_ be
+treated specially.
+
+The code has full access to stack variables and general purpose
+registers. The entry code in romlayout.S will push the original
+registers on the stack before calling the C code and then pop them off
+(including any required changes) before returning from the interrupt.
+Changes to CS, DS, and ES segment registers in C code is also safe.
+Changes to other segment registers (SS, FS, GS) need to be restored
+manually.
+
+Stack variables (and pointers to stack variables) work as they
+normally do in standard C code.
+
+However, variables stored outside the stack need to be accessed via
+the GET_VAR and SET_VAR macros. This is due to the 16bit segment
+nature of the X86 cpu when it is in "real mode". The C entry code
+will set DS and SS to point to the stack segment. Variables not on
+the stack need to be accessed via an explicit segment register.
+Global constant definitions (those in 0xf000) can be accessed via the
+CS segment register. Any other access requires altering one of the
+other segment registers (usually ES) and then accessing the variable
+via that segment register.
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..a528399
--- /dev/null
+++ b/TODO
@@ -0,0 +1,22 @@
+Make header files work with either 32bit or 16bit code.
+
+Fix makefiles so that they rebuild the required files automatically.
+
+Make sure gdt/idt tables are properly aligned
+
+Cleanup setting of ES on GET/SET_BDA
+
+Make sure inline assembly isn't preventing inlining of calling
+functions.
+
+Convert remaining parts of rombios.c to new code.
+
+Convert rombios32 and apm bios stuff to new code.
+
+Allow one to select adding 32 bit code to 0xf000 or in a separate
+location.
+
+Try generating bios tables at compile time.
+
+Move e820 map generation to post time (just have e820 code copy pre
+made tables back to user).
diff --git a/src/biosvar.h b/src/biosvar.h
new file mode 100644
index 0000000..8b15f5b
--- /dev/null
+++ b/src/biosvar.h
@@ -0,0 +1,184 @@
+// Variable layouts of bios.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "types.h" // u8
+#include "farptr.h" // SET_SEG
+
+
+/****************************************************************
+ * Bios Data Area (BDA)
+ ****************************************************************/
+
+struct ivec {
+ u16 offset;
+ u16 seg;
+};
+
+struct bios_data_area_s {
+ // 00:00
+ struct ivec ivecs[256];
+ // 30:00
+// u8 stack[256];
+ // 40:00
+ u16 port_com1, port_com2, port_com3, port_com4;
+ u16 port_lpt1, port_lpt2, port_lpt3;
+ u16 ebda_seg;
+ // 40:10
+ u16 equipment_list_flags;
+ u8 pad1;
+ u16 mem_size_kb;
+ u8 pad2;
+ u8 ps2_ctrl_flag;
+ u16 kbd_flag;
+ u8 alt_keypad;
+ u16 kbd_buf_head;
+ u16 kbd_buf_tail;
+ // 40:1e
+ u8 kbd_buf[32];
+ u8 floppy_recalibration_status;
+ u8 floppy_motor_status;
+ // 40:40
+ u8 floppy_motor_counter;
+ u8 floppy_last_status;
+ u8 floppy_return_status[7];
+ u8 other1[0x7];
+ // 40:50
+ u8 other2[0x1c];
+ // 40:6c
+ u32 timer_counter;
+ // 40:70
+ u8 timer_rollover;
+ u8 other4[0x0f];
+ // 40:80
+ u16 kbd_buf_start_offset;
+ u16 kbd_buf_end_offset;
+ u8 other5[7];
+ u8 floppy_last_data_rate;
+ u8 other6[3];
+ u8 floppy_harddisk_info;
+ // 40:90
+ u8 floppy_media_state[4];
+ u8 floppy_track0;
+ u8 floppy_track1;
+ u8 kbd_mode;
+ u8 kbd_led;
+ u32 ptr_user_wait_complete_flag;
+ u32 user_wait_timeout;
+ // 40:A0
+ u8 rtc_wait_flag;
+} __attribute__((packed));
+
+// BDA floppy_recalibration_status bitdefs
+#define FRS_TIMEOUT (1<<7)
+
+// BDA rtc_wait_flag bitdefs
+#define RWS_WAIT_PENDING (1<<0)
+#define RWS_WAIT_ELAPSED (1<<7)
+
+// BDA floppy_media_state bitdefs
+#define FMS_DRIVE_STATE_MASK (0x07)
+#define FMS_MEDIA_DRIVE_ESTABLISHED (1<<4)
+#define FMS_DOUBLE_STEPPING (1<<5)
+#define FMS_DATA_RATE_MASK (0xc0)
+
+// Accessor functions
+#define GET_BDA(var) ({ \
+ SET_SEG(ES, 0x0000); \
+ GET_VAR(ES, ((struct bios_data_area_s *)0)->var); })
+#define SET_BDA(var, val) do { \
+ SET_SEG(ES, 0x0000); \
+ SET_VAR(ES, ((struct bios_data_area_s *)0)->var, val); \
+ } while (0)
+#define CLEARBITS_BDA(var, val) do { \
+ typeof(((struct bios_data_area_s *)0)->var) __val = GET_BDA(var); \
+ SET_BDA(var, (__val & ~(val))); \
+ } while (0)
+#define SETBITS_BDA(var, val) do { \
+ typeof(((struct bios_data_area_s *)0)->var) __val = GET_BDA(var); \
+ SET_BDA(var, (__val | (val))); \
+ } while (0)
+
+
+/****************************************************************
+ * Extended Bios Data Area (EBDA)
+ ****************************************************************/
+
+struct extended_bios_data_area_s {
+ u8 size;
+ u8 other1[0x3c];
+
+ // FDPT - Can be splitted in data members if needed
+ u8 fdpt0[0x10];
+ u8 fdpt1[0x10];
+
+ u8 other2[0xC4];
+
+ // ATA Driver data
+ //ata_t ata;
+
+#if BX_ELTORITO_BOOT
+ // El Torito Emulation data
+ cdemu_t cdemu;
+#endif // BX_ELTORITO_BOOT
+};
+
+
+/****************************************************************
+ * Extended Bios Data Area (EBDA)
+ ****************************************************************/
+
+#define UREG(ER, R, RH, RL) union { u32 ER; struct { u16 R; u16 R ## _hi; }; struct { u8 RL; u8 RH; u8 R ## _hilo; u8 R ## _hihi; }; }
+
+struct bregs {
+ u16 ds;
+ u16 es;
+ UREG(edi, di, di_hi, di_lo);
+ UREG(esi, si, si_hi, si_lo);
+ UREG(ebp, bp, bp_hi, bp_lo);
+ UREG(esp, sp, sp_hi, sp_lo);
+ UREG(ebx, bx, bh, bl);
+ UREG(edx, dx, dh, dl);
+ UREG(ecx, cx, ch, cl);
+ UREG(eax, ax, ah, al);
+ u16 ip;
+ u16 cs;
+ u16 flags;
+} __attribute__((packed));
+
+// bregs flags bitdefs
+#define F_CF (1<<9)
+
+static inline void
+set_cf(struct bregs *regs, int cond)
+{
+ if (cond)
+ regs->flags |= F_CF;
+ else
+ regs->flags &= ~F_CF;
+}
+
+
+/****************************************************************
+ * Bios Config Table
+ ****************************************************************/
+
+struct bios_config_table_s {
+ // XXX
+ u8 x;
+};
+
+extern struct bios_config_table_s BIOS_CONFIG_TABLE;
+
+
+/****************************************************************
+ * Memory layout info
+ ****************************************************************/
+
+#define SEG_BIOS 0xf000
+
+#define EBDA_SEG 0x9FC0
+#define EBDA_SIZE 1 // In KiB
+#define BASE_MEM_IN_K (640 - EBDA_SIZE)
diff --git a/src/boot.c b/src/boot.c
new file mode 100644
index 0000000..828be14
--- /dev/null
+++ b/src/boot.c
@@ -0,0 +1,118 @@
+// 16bit code to load disk image and start system boot.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "types.h" // VISIBLE
+#include "util.h" // irq_enable
+#include "biosvar.h" // struct bregs
+#include "farptr.h" // SET_SEG
+
+static inline void
+__call_irq(u8 nr)
+{
+ asm volatile("int %0" : : "N" (nr));
+}
+
+static inline u32
+call_irq(u8 nr, struct bregs *callregs)
+{
+ u32 flags;
+ asm volatile(
+ // Save current registers
+ "pushal\n"
+ // Pull in calling registers.
+ "movl 0x04(%%eax), %%edi\n"
+ "movl 0x08(%%eax), %%esi\n"
+ "movl 0x0c(%%eax), %%ebp\n"
+ "movl 0x14(%%eax), %%ebx\n"
+ "movl 0x18(%%eax), %%edx\n"
+ "movl 0x1c(%%eax), %%ecx\n"
+ "movl 0x20(%%eax), %%eax\n"
+ // Invoke interrupt
+ "int %1\n"
+ // Restore registers
+ "popal\n"
+ // Exract flags
+ "pushfw\n"
+ "popl %%eax\n"
+ : "=a" (flags): "N" (nr), "a" (callregs), "m" (*callregs));
+ return flags;
+}
+
+static void
+print_boot_failure()
+{
+ bprintf(0, "Boot failed\n");
+}
+
+static void
+try_boot()
+{
+ // XXX - assume floppy
+ u16 bootseg = 0x07c0;
+ u8 bootdrv = 0;
+
+ // Read sector
+ struct bregs cr;
+ memset(&cr, 0, sizeof(cr));
+ cr.dl = bootdrv;
+ SET_SEG(ES, bootseg);
+ cr.bx = 0;
+ cr.ah = 2;
+ cr.al = 1;
+ cr.ch = 0;
+ cr.cl = 1;
+ cr.dh = 0;
+ u32 status = call_irq(0x13, &cr);
+
+ if (status & F_CF) {
+ print_boot_failure();
+ return;
+ }
+
+ u16 bootip = (bootseg & 0x0fff) << 4;
+ bootseg &= 0xf000;
+
+ u32 segoff = (bootseg << 16) | bootip;
+ asm volatile (
+ "pushf\n"
+ "pushl %0\n"
+ "movb %b1, %%dl\n"
+ // Set the magic number in ax and the boot drive in dl.
+ "movw $0xaa55, %%ax\n"
+ // Zero some of the other registers.
+ "xorw %%bx, %%bx\n"
+ "movw %%bx, %%ds\n"
+ "movw %%bx, %%es\n"
+ "movw %%bx, %%bp\n"
+ // Go!
+ "iretw\n"
+ : : "r" (segoff), "ri" (bootdrv));
+}
+
+// Boot Failure recovery: try the next device.
+void VISIBLE
+handle_18(struct bregs *regs)
+{
+ debug_enter(regs);
+ try_boot();
+}
+
+// INT 19h Boot Load Service Entry Point
+void VISIBLE
+handle_19(struct bregs *regs)
+{
+ debug_enter(regs);
+ try_boot();
+}
+
+// Callback from 32bit entry - start boot process
+void VISIBLE
+begin_boot()
+{
+ irq_enable();
+ __call_irq(0x19);
+}
diff --git a/src/cbt.c b/src/cbt.c
new file mode 100644
index 0000000..015f16f
--- /dev/null
+++ b/src/cbt.c
@@ -0,0 +1,8 @@
+#include "biosvar.h" // CONFIG_BIOS_TABLE
+
+// bios variables
+
+struct bios_config_table_s BIOS_CONFIG_TABLE = {
+ // XXX
+ 18,
+};
diff --git a/src/clock.c b/src/clock.c
new file mode 100644
index 0000000..5ca2b5c
--- /dev/null
+++ b/src/clock.c
@@ -0,0 +1,54 @@
+// 16bit code to handle system clocks.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "biosvar.h" // struct bregs
+#include "util.h" // debug_enter
+#include "disk.h" // floppy_tick
+
+// INT 1Ah Time-of-day Service Entry Point
+void VISIBLE
+handle_1a(struct bregs *regs)
+{
+ debug_enter(regs);
+ set_cf(regs, 1);
+}
+
+// User Timer Tick
+void VISIBLE
+handle_1c(struct bregs *regs)
+{
+ debug_enter(regs);
+}
+
+// INT 08h System Timer ISR Entry Point
+void VISIBLE
+handle_08(struct bregs *regs)
+{
+// debug_enter(regs);
+
+ floppy_tick();
+
+ u32 counter = GET_BDA(timer_counter);
+ counter++;
+ // compare to one days worth of timer ticks at 18.2 hz
+ if (counter >= 0x001800B0) {
+ // there has been a midnight rollover at this point
+ counter = 0;
+ SET_BDA(timer_rollover, GET_BDA(timer_rollover) + 1);
+ }
+
+ SET_BDA(timer_counter, counter);
+ // XXX - int #0x1c
+ eoi_master_pic();
+}
+
+// int70h: IRQ8 - CMOS RTC
+void VISIBLE
+handle_70(struct bregs *regs)
+{
+ debug_enter(regs);
+}
diff --git a/src/cmos.h b/src/cmos.h
new file mode 100644
index 0000000..33cde16
--- /dev/null
+++ b/src/cmos.h
@@ -0,0 +1,51 @@
+// Definitions for X86 CMOS non-volatile memory access.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+#ifndef __CMOS_H
+#define __CMOS_H
+
+#include "ioport.h" // inb, outb
+
+#define CMOS_RTC_SECONDS 0x00
+#define CMOS_RTC_SECONDS_ALARM 0x01
+#define CMOS_RTC_MINUTES 0x02
+#define CMOS_RTC_MINUTES_ALARM 0x03
+#define CMOS_RTC_HOURS 0x04
+#define CMOS_RTC_HOURS_ALARM 0x05
+#define CMOS_STATUS_B 0x0b
+#define CMOS_RESET_CODE 0x0f
+#define CMOS_FLOPPY_DRIVE_TYPE 0x10
+#define CMOS_EQUIPMENT_INFO 0x14
+#define CMOS_EXTMEM_LOW 0x30
+#define CMOS_EXTMEM_HIGH 0x31
+#define CMOS_EXTMEM2_LOW 0x34
+#define CMOS_EXTMEM2_HIGH 0x35
+
+// CMOS_STATUS_B bitdefs
+#define CSB_EN_ALARM_IRQ (1<<5)
+
+// CMOS_FLOPPY_DRIVE_TYPE bitdefs
+#define CFD_NO_DRIVE 0
+#define CFD_360KB 1
+#define CFD_12MB 2
+#define CFD_720KB 3
+#define CFD_144MB 4
+#define CFD_288MB 5
+
+static inline u8
+inb_cmos(u8 reg)
+{
+ outb(reg, PORT_CMOS_INDEX);
+ return inb(PORT_CMOS_DATA);
+}
+
+static inline void
+outb_cmos(u8 val, u8 reg)
+{
+ outb(reg, PORT_CMOS_INDEX);
+ outb(val, PORT_CMOS_DATA);
+}
+
+#endif // cmos.h
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 0000000..53996b4
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,8 @@
+// Configuration definitions.
+
+#define CONFIG_FLOPPY_SUPPORT 1
+#define CONFIG_PS2_MOUSE 0
+#define CONFIG_ATA 0
+#define CONFIG_STACK16_SEGMENT 0x00
+#define CONFIG_STACK16_OFFSET 0xfffe
+#define CONFIG_STACK32_OFFSET 0x80000
diff --git a/src/disk.c b/src/disk.c
new file mode 100644
index 0000000..8901b7d
--- /dev/null
+++ b/src/disk.c
@@ -0,0 +1,67 @@
+// 16bit code to access hard drives.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "disk.h" // floppy_13
+#include "biosvar.h" // struct bregs
+#include "util.h" // debug_enter
+
+static void
+disk_13(struct bregs *regs, u8 drive)
+{
+ set_cf(regs, 1);
+}
+
+static void
+handle_legacy_disk(struct bregs *regs, u8 drive)
+{
+ if (drive < 0x80) {
+ floppy_13(regs, drive);
+ return;
+ }
+#if BX_USE_ATADRV
+ if (drive >= 0xE0) {
+ int13_cdrom(regs); // xxx
+ return;
+ }
+#endif
+
+ disk_13(regs, drive);
+}
+
+void VISIBLE
+handle_40(struct bregs *regs)
+{
+ debug_enter(regs);
+ handle_legacy_disk(regs, regs->dl);
+ debug_exit(regs);
+}
+
+// INT 13h Fixed Disk Services Entry Point
+void VISIBLE
+handle_13(struct bregs *regs)
+{
+ debug_enter(regs);
+ u8 drive = regs->dl;
+#if BX_ELTORITO_BOOT
+ if (regs->ah >= 0x4a || regs->ah <= 0x4d) {
+ int13_eltorito(regs);
+ } else if (cdemu_isactive() && cdrom_emulated_drive()) {
+ int13_cdemu(regs);
+ } else
+#endif
+ handle_legacy_disk(regs, drive);
+ debug_exit(regs);
+}
+
+// record completion in BIOS task complete flag
+void VISIBLE
+handle_76(struct bregs *regs)
+{
+ debug_enter(regs);
+ SET_BDA(floppy_harddisk_info, 0xff);
+ eoi_both_pics();
+}
diff --git a/src/disk.h b/src/disk.h
new file mode 100644
index 0000000..d7b3547
--- /dev/null
+++ b/src/disk.h
@@ -0,0 +1,33 @@
+// Definitions for X86 bios disks.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "ioport.h" // outb
+
+#define DISK_RET_SUCCESS 0x00
+#define DISK_RET_EPARAM 0x01
+#define DISK_RET_ECHANGED 0x06
+#define DISK_RET_EBOUNDARY 0x09
+#define DISK_RET_ECONTROLLER 0x20
+#define DISK_RET_ETIMEOUT 0x80
+#define DISK_RET_EMEDIA 0xC0
+
+static inline void
+eoi_master_pic()
+{
+ outb(PIC1_IRQ5, PORT_PIC1);
+}
+
+static inline void
+eoi_both_pics()
+{
+ outb(PIC2_IRQ13, PORT_PIC2);
+ eoi_master_pic();
+}
+
+// floppy.c
+struct bregs;
+void floppy_13(struct bregs *regs, u8 drive);
+void floppy_tick();
diff --git a/src/farptr.h b/src/farptr.h
new file mode 100644
index 0000000..1c3044b
--- /dev/null
+++ b/src/farptr.h
@@ -0,0 +1,57 @@
+// Code to access multiple segments within gcc.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#define READ8_SEG(SEG, var) ({ \
+ u8 __value; \
+ __asm__ __volatile__("movb %%" #SEG ":%1, %b0" \
+ : "=Qi"(__value) : "m"(var)); \
+ __value; })
+#define READ16_SEG(SEG, var) ({ \
+ u16 __value; \
+ __asm__ __volatile__("movw %%" #SEG ":%1, %w0" \
+ : "=ri"(__value) : "m"(var)); \
+ __value; })
+#define READ32_SEG(SEG, var) ({ \
+ u32 __value; \
+ __asm__ __volatile__("movl %%" #SEG ":%1, %0" \
+ : "=ri"(__value) : "m"(var)); \
+ __value; })
+#define WRITE8_SEG(SEG, var, value) \
+ __asm__ __volatile__("movb %b0, %%" #SEG ":%1" \
+ : : "Q"(value), "m"(var))
+#define WRITE16_SEG(SEG, var, value) \
+ __asm__ __volatile__("movw %w0, %%" #SEG ":%1" \
+ : : "r"(value), "m"(var))
+#define WRITE32_SEG(SEG, var, value) \
+ __asm__ __volatile__("movl %0, %%" #SEG ":%1" \
+ : : "r"(value), "m"(var))
+
+#define GET_VAR(seg, var) ({ \
+ typeof(var) __val; \
+ if (__builtin_types_compatible_p(typeof(__val), u8)) \
+ __val = READ8_SEG(seg, var); \
+ else if (__builtin_types_compatible_p(typeof(__val), u16)) \
+ __val = READ16_SEG(seg, var); \
+ else if (__builtin_types_compatible_p(typeof(__val), u32)) \
+ __val = READ32_SEG(seg, var); \
+ __val; })
+
+#define SET_VAR(seg, var, val) do { \
+ if (__builtin_types_compatible_p(typeof(var), u8)) \
+ WRITE8_SEG(seg, var, (val)); \
+ else if (__builtin_types_compatible_p(typeof(var), u16)) \
+ WRITE16_SEG(seg, var, (val)); \
+ else if (__builtin_types_compatible_p(typeof(var), u32)) \
+ WRITE32_SEG(seg, var, (val)); \
+ } while (0)
+
+#define SET_SEG(SEG, value) \
+ __asm__ __volatile__("movw %w0, %%" #SEG : : "r"(value))
+#define GET_SEG(SEG) ({ \
+ u16 __seg; \
+ __asm__ __volatile__("movw %%" #SEG ", %w0" : "=r"(__seg)); \
+ __seg;})
+
diff --git a/src/floppy.c b/src/floppy.c
new file mode 100644
index 0000000..5e70df2
--- /dev/null
+++ b/src/floppy.c
@@ -0,0 +1,757 @@
+// 16bit code to access floppy drives.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "types.h" // u8
+#include "disk.h" // DISK_RET_SUCCESS
+#include "config.h" // CONFIG_FLOPPY_SUPPORT
+#include "biosvar.h" // struct bregs
+#include "util.h" // irq_disable
+#include "cmos.h" // inb_cmos
+
+#define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
+
+////.org 0xefc7
+// Since no provisions are made for multiple drive types, most
+// values in this table are ignored. I set parameters for 1.44M
+// floppy here
+char diskette_param_table[11] = {
+ 0xAF,
+ 0x02, // head load time 0000001, DMA used
+ 0x25,
+ 0x02,
+ 18,
+ 0x1B,
+ 0xFF,
+ 0x6C,
+ 0xF6,
+ 0x0F,
+ 0x08,
+};
+
+// New diskette parameter table adding 3 parameters from IBM
+// Since no provisions are made for multiple drive types, most
+// values in this table are ignored. I set parameters for 1.44M
+// floppy here
+char diskette_param_table2[14] VISIBLE = {
+ 0xAF,
+ 0x02, // head load time 0000001, DMA used
+ 0x25,
+ 0x02,
+ 18,
+ 0x1B,
+ 0xFF,
+ 0x6C,
+ 0xF6,
+ 0x0F,
+ 0x08,
+ 79, // maximum track
+ 0, // data transfer rate
+ 4, // drive type in cmos
+};
+
+// Oddities:
+// Return codes vary greatly - AL not cleared consistenlty, BDA return
+// status not set consistently, sometimes panics.
+// Extra outb(0x000a, 0x02) in read?
+// Does not disable interrupts on failure paths.
+// numfloppies used before set in int_1308
+// int_1305 verifies track but doesn't use it?
+
+static inline void
+set_diskette_current_cyl(u8 drive, u8 cyl)
+{
+ if (drive)
+ SET_BDA(floppy_track1, cyl);
+ else
+ SET_BDA(floppy_track0, cyl);
+}
+
+static u16
+get_drive_type(u8 drive)
+{
+ // check CMOS to see if drive exists
+ u8 drive_type = inb_cmos(CMOS_FLOPPY_DRIVE_TYPE);
+ if (drive == 0)
+ drive_type >>= 4;
+ else
+ drive_type &= 0x0f;
+ return drive_type;
+}
+
+static u16
+floppy_media_known(u8 drive)
+{
+ if (!(GET_BDA(floppy_recalibration_status) & (1<<drive)))
+ return 0;
+ u8 v = GET_BDA(floppy_media_state[drive]);
+ if (!(v & FMS_MEDIA_DRIVE_ESTABLISHED))
+ return 0;
+ return 1;
+}
+
+static void
+floppy_reset_controller()
+{
+ // Reset controller
+ u8 val8 = inb(PORT_FD_DOR);
+ outb(val8 & ~0x04, PORT_FD_DOR);
+ outb(val8 | 0x04, PORT_FD_DOR);
+
+ // Wait for controller to come out of reset
+ while ((inb(PORT_FD_STATUS) & 0xc0) != 0x80)
+ ;
+}
+
+static void
+floppy_prepare_controller(u8 drive)
+{
+ CLEARBITS_BDA(floppy_recalibration_status, FRS_TIMEOUT);
+
+ // turn on motor of selected drive, DMA & int enabled, normal operation
+ u8 prev_reset = inb(PORT_FD_DOR) & 0x04;
+ u8 dor = 0x10;
+ if (drive)
+ dor = 0x20;
+ dor |= 0x0c;
+ dor |= drive;
+ outb(dor, PORT_FD_DOR);
+
+ // reset the disk motor timeout value of INT 08
+ SET_BDA(floppy_motor_counter, BX_FLOPPY_ON_CNT);
+
+ // wait for drive readiness
+ while ((inb(PORT_FD_STATUS) & 0xc0) != 0x80)
+ ;
+
+ if (prev_reset == 0) {
+ irq_enable();
+ u8 v;
+ do {
+ v = GET_BDA(floppy_recalibration_status);
+ } while ((v & FRS_TIMEOUT) == 0);
+ irq_disable();
+
+ v &= ~FRS_TIMEOUT;
+ SET_BDA(floppy_recalibration_status, v);
+ }
+}
+
+static u8
+floppy_pio(u8 *cmd, u8 cmdlen)
+{
+ floppy_prepare_controller(cmd[1] & 1);
+
+ // send command to controller
+ u8 i;
+ for (i=0; i<cmdlen; i++)
+ outb(cmd[i], PORT_FD_DATA);
+
+ irq_enable();
+ u8 v;
+ do {
+ if (!GET_BDA(floppy_motor_counter)) {
+ irq_disable();
+ floppy_reset_controller();
+ return DISK_RET_ETIMEOUT;
+ }
+ v = GET_BDA(floppy_recalibration_status);
+ } while (!(v & FRS_TIMEOUT));
+ irq_disable();
+
+ v &= ~FRS_TIMEOUT;
+ SET_BDA(floppy_recalibration_status, v);
+
+ if ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0)
+ BX_PANIC("int13_diskette: ctrl not ready\n");
+
+ return 0;
+}
+
+static u8
+floppy_cmd(struct bregs *regs, u16 count, u8 *cmd, u8 cmdlen)
+{
+ // es:bx = pointer to where to place information from diskette
+ // port 04: DMA-1 base and current address, channel 2
+ // port 05: DMA-1 base and current count, channel 2
+ u16 page = regs->es >> 12; // upper 4 bits
+ u16 base_es = regs->es << 4; // lower 16bits contributed by ES
+ u16 base_address = base_es + regs->bx; // lower 16 bits of address
+ // contributed by ES:BX
+ if (base_address < base_es)
+ // in case of carry, adjust page by 1
+ page++;
+
+ // check for 64K boundary overrun
+ u16 last_addr = base_address + count;
+ if (last_addr < base_address)
+ return DISK_RET_EBOUNDARY;
+
+ u8 mode_register = 0x4a; // single mode, increment, autoinit disable,
+ if (cmd[0] == 0xe6)
+ // read
+ mode_register = 0x46;
+
+ DEBUGF("floppy dma c2");
+ outb(0x06, PORT_DMA1_MASK_REG);
+ outb(0x00, PORT_DMA1_CLEAR_FF_REG); // clear flip-flop
+ outb(base_address, PORT_DMA_ADDR_2);
+ outb(base_address>>8, PORT_DMA_ADDR_2);
+ outb(0x00, PORT_DMA1_CLEAR_FF_REG); // clear flip-flop
+ outb(count, PORT_DMA_CNT_2);
+ outb(count>>8, PORT_DMA_CNT_2);
+
+ // port 0b: DMA-1 Mode Register
+ // transfer type=write, channel 2
+ outb(mode_register, PORT_DMA1_MODE_REG);
+
+ // port 81: DMA-1 Page Register, channel 2
+ outb(page, PORT_DMA_PAGE_2);
+
+ outb(0x02, PORT_DMA1_MASK_REG); // unmask channel 2
+
+ u8 ret = floppy_pio(cmd, cmdlen);
+ if (ret)
+ return ret;
+
+ // read 7 return status bytes from controller
+ u8 i;
+ for (i=0; i<7; i++) {
+ u8 v = inb(PORT_FD_DATA);
+ cmd[i] = v;
+ SET_BDA(floppy_return_status[i], v);
+ }
+
+ return 0;
+}
+
+static void
+floppy_drive_recal(u8 drive)
+{
+ // send Recalibrate command (2 bytes) to controller
+ u8 data[12];
+ data[0] = 0x07; // 07: Recalibrate
+ data[1] = drive; // 0=drive0, 1=drive1
+ floppy_pio(data, 2);
+
+ SETBITS_BDA(floppy_recalibration_status, 1<<drive);
+ set_diskette_current_cyl(drive, 0);
+}
+
+static u16
+floppy_media_sense(u8 drive)
+{
+ u16 rv;
+ u8 config_data, media_state;
+
+ floppy_drive_recal(drive);
+
+ // for now cheat and get drive type from CMOS,
+ // assume media is same as drive type
+
+ // ** config_data **
+ // Bitfields for diskette media control:
+ // Bit(s) Description (Table M0028)
+ // 7-6 last data rate set by controller
+ // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
+ // 5-4 last diskette drive step rate selected
+ // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
+ // 3-2 {data rate at start of operation}
+ // 1-0 reserved
+
+ // ** media_state **
+ // Bitfields for diskette drive media state:
+ // Bit(s) Description (Table M0030)
+ // 7-6 data rate
+ // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
+ // 5 double stepping required (e.g. 360kB in 1.2MB)
+ // 4 media type established
+ // 3 drive capable of supporting 4MB media
+ // 2-0 on exit from BIOS, contains
+ // 000 trying 360kB in 360kB
+ // 001 trying 360kB in 1.2MB
+ // 010 trying 1.2MB in 1.2MB
+ // 011 360kB in 360kB established
+ // 100 360kB in 1.2MB established
+ // 101 1.2MB in 1.2MB established
+ // 110 reserved
+ // 111 all other formats/drives
+
+ switch (get_drive_type(drive)) {
+ case 1:
+ // 360K 5.25" drive
+ config_data = 0x00; // 0000 0000
+ media_state = 0x25; // 0010 0101
+ rv = 1;
+ break;
+ case 2:
+ // 1.2 MB 5.25" drive
+ config_data = 0x00; // 0000 0000
+ media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
+ rv = 1;
+ break;
+ case 3:
+ // 720K 3.5" drive
+ config_data = 0x00; // 0000 0000 ???
+ media_state = 0x17; // 0001 0111
+ rv = 1;
+ break;
+ case 4:
+ // 1.44 MB 3.5" drive
+ config_data = 0x00; // 0000 0000
+ media_state = 0x17; // 0001 0111
+ rv = 1;
+ break;
+ case 5:
+ // 2.88 MB 3.5" drive
+ config_data = 0xCC; // 1100 1100
+ media_state = 0xD7; // 1101 0111
+ rv = 1;
+ break;
+ //
+ // Extended floppy size uses special cmos setting
+ case 6:
+ // 160k 5.25" drive
+ config_data = 0x00; // 0000 0000
+ media_state = 0x27; // 0010 0111
+ rv = 1;
+ break;
+ case 7:
+ // 180k 5.25" drive
+ config_data = 0x00; // 0000 0000
+ media_state = 0x27; // 0010 0111
+ rv = 1;
+ break;
+ case 8:
+ // 320k 5.25" drive
+ config_data = 0x00; // 0000 0000
+ media_state = 0x27; // 0010 0111
+ rv = 1;
+ break;
+ default:
+ // not recognized
+ config_data = 0x00; // 0000 0000
+ media_state = 0x00; // 0000 0000
+ rv = 0;
+ }
+
+ SET_BDA(floppy_last_data_rate, config_data);
+ SET_BDA(floppy_media_state[drive], media_state);
+ return rv;
+}
+
+static inline void
+floppy_ret(struct bregs *regs, u8 code)
+{
+ regs->ah = code;
+ SET_BDA(floppy_last_status, code);
+ set_cf(regs, code);
+}
+
+static inline void
+floppy_fail(struct bregs *regs, u8 code)
+{
+ regs->al = 0; // no sectors read
+ floppy_ret(regs, code);
+}
+
+static u16
+check_drive(struct bregs *regs, u8 drive)
+{
+ // see if drive exists
+ if (drive > 1 || !get_drive_type(drive)) {
+ floppy_fail(regs, DISK_RET_ETIMEOUT);
+ return 1;
+ }
+
+ // see if media in drive, and type is known
+ if (floppy_media_known(drive) == 0 && floppy_media_sense(drive) == 0) {
+ floppy_fail(regs, DISK_RET_EMEDIA);
+ return 1;
+ }
+ return 0;
+}
+
+// diskette controller reset
+static void
+floppy_1300(struct bregs *regs, u8 drive)
+{
+ if (drive > 1) {
+ floppy_ret(regs, DISK_RET_EPARAM);
+ return;
+ }
+ if (!get_drive_type(drive)) {
+ floppy_ret(regs, DISK_RET_ETIMEOUT);
+ return;
+ }
+ set_diskette_current_cyl(drive, 0); // current cylinder
+ floppy_ret(regs, DISK_RET_SUCCESS);
+}
+
+// Read Diskette Status
+static void
+floppy_1301(struct bregs *regs, u8 drive)
+{
+ u8 v = GET_BDA(floppy_last_status);
+ regs->ah = v;
+ set_cf(regs, v);
+}
+
+// Read Diskette Sectors
+static void
+floppy_1302(struct bregs *regs, u8 drive)
+{
+ if (check_drive(regs, drive))
+ return;
+
+ u8 num_sectors = regs->al;
+ u8 track = regs->ch;
+ u8 sector = regs->cl;
+ u8 head = regs->dh;
+
+ if (head > 1 || sector == 0 || num_sectors == 0
+ || track > 79 || num_sectors > 72) {
+ BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
+ floppy_fail(regs, DISK_RET_EPARAM);
+ return;
+ }
+
+ // send read-normal-data command (9 bytes) to controller
+ u8 data[12];
+ data[0] = 0xe6; // e6: read normal data
+ data[1] = (head << 2) | drive; // HD DR1 DR2
+ data[2] = track;
+ data[3] = head;
+ data[4] = sector;
+ data[5] = 2; // 512 byte sector size
+ data[6] = sector + num_sectors - 1; // last sector to read on track
+ data[7] = 0; // Gap length
+ data[8] = 0xff; // Gap length
+
+ u16 ret = floppy_cmd(regs, (num_sectors * 512) - 1, data, 9);
+ if (ret) {
+ floppy_fail(regs, ret);
+ return;
+ }
+
+ if (data[0] & 0xc0) {
+ floppy_fail(regs, DISK_RET_ECONTROLLER);
+ return;
+ }
+
+ // ??? should track be new val from return_status[3] ?
+ set_diskette_current_cyl(drive, track);
+ // AL = number of sectors read (same value as passed)
+ floppy_ret(regs, DISK_RET_SUCCESS);
+}
+
+// Write Diskette Sectors
+static void
+floppy_1303(struct bregs *regs, u8 drive)
+{
+ if (check_drive(regs, drive))
+ return;
+
+ u8 num_sectors = regs->al;
+ u8 track = regs->ch;
+ u8 sector = regs->cl;
+ u8 head = regs->dh;
+
+ if (head > 1 || sector == 0 || num_sectors == 0
+ || track > 79 || num_sectors > 72) {
+ BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
+ floppy_fail(regs, DISK_RET_EPARAM);
+ return;
+ }
+
+ // send write-normal-data command (9 bytes) to controller
+ u8 data[12];
+ data[0] = 0xc5; // c5: write normal data
+ data[1] = (head << 2) | drive; // HD DR1 DR2
+ data[2] = track;
+ data[3] = head;
+ data[4] = sector;
+ data[5] = 2; // 512 byte sector size
+ data[6] = sector + num_sectors - 1; // last sector to write on track
+ data[7] = 0; // Gap length
+ data[8] = 0xff; // Gap length
+
+ u8 ret = floppy_cmd(regs, (num_sectors * 512) - 1, data, 9);
+ if (ret) {
+ floppy_fail(regs, ret);
+ return;
+ }
+
+ if (data[0] & 0xc0) {
+ if (data[1] & 0x02) {
+ regs->ax = 0x0300;
+ set_cf(regs, 1);
+ return;
+ }
+ BX_PANIC("int13_diskette_function: read error\n");
+ }
+
+ // ??? should track be new val from return_status[3] ?
+ set_diskette_current_cyl(drive, track);
+ // AL = number of sectors read (same value as passed)
+ floppy_ret(regs, DISK_RET_SUCCESS);
+}
+
+// Verify Diskette Sectors
+static void
+floppy_1304(struct bregs *regs, u8 drive)
+{
+ if (check_drive(regs, drive))
+ return;
+
+ u8 num_sectors = regs->al;
+ u8 track = regs->ch;
+ u8 sector = regs->cl;
+ u8 head = regs->dh;
+
+ if (head > 1 || sector == 0 || num_sectors == 0
+ || track > 79 || num_sectors > 72) {
+ BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
+ floppy_fail(regs, DISK_RET_EPARAM);
+ return;
+ }
+
+ // ??? should track be new val from return_status[3] ?
+ set_diskette_current_cyl(drive, track);
+ // AL = number of sectors verified (same value as passed)
+ floppy_ret(regs, DISK_RET_SUCCESS);
+}
+
+// format diskette track
+static void
+floppy_1305(struct bregs *regs, u8 drive)
+{
+ DEBUGF("floppy f05\n");
+
+ if (check_drive(regs, drive))
+ return;
+
+ u8 num_sectors = regs->al;
+ u8 head = regs->dh;
+
+ if (head > 1 || num_sectors == 0 || num_sectors > 18) {
+ BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
+ floppy_fail(regs, DISK_RET_EPARAM);
+ return;
+ }
+
+ // send format-track command (6 bytes) to controller
+ u8 data[12];
+ data[0] = 0x4d; // 4d: format track
+ data[1] = (head << 2) | drive; // HD DR1 DR2
+ data[2] = 2; // 512 byte sector size
+ data[3] = num_sectors; // number of sectors per track
+ data[4] = 0; // Gap length
+ data[5] = 0xf6; // Fill byte
+
+ u8 ret = floppy_cmd(regs, (num_sectors * 4) - 1, data, 6);
+ if (ret) {
+ floppy_fail(regs, ret);
+ return;
+ }
+
+ if (data[0] & 0xc0) {
+ if (data[1] & 0x02) {
+ regs->ax = 0x0300;
+ set_cf(regs, 1);
+ return;
+ }
+ BX_PANIC("int13_diskette_function: read error\n");
+ }
+
+ set_diskette_current_cyl(drive, 0);
+ floppy_ret(regs, 0);
+}
+
+// read diskette drive parameters
+static void
+floppy_1308(struct bregs *regs, u8 drive)
+{
+ DEBUGF("floppy f08\n");
+
+ u8 drive_type = inb_cmos(CMOS_FLOPPY_DRIVE_TYPE);
+ u8 num_floppies = 0;
+ if (drive_type & 0xf0)
+ num_floppies++;
+ if (drive_type & 0x0f)
+ num_floppies++;
+
+ if (drive > 1) {
+ regs->ax = 0;
+ regs->bx = 0;
+ regs->cx = 0;
+ regs->dx = 0;
+ regs->es = 0;
+ regs->di = 0;
+ regs->dl = num_floppies;
+ set_cf(regs, 0);
+ return;
+ }
+
+ if (drive == 0)
+ drive_type >>= 4;
+ else
+ drive_type &= 0x0f;
+
+ regs->bh = 0;
+ regs->bl = drive_type;
+ regs->ah = 0;
+ regs->al = 0;
+ regs->dl = num_floppies;
+
+ switch (drive_type) {
+ case 0: // none
+ regs->cx = 0;
+ regs->dh = 0; // max head #
+ break;
+
+ case 1: // 360KB, 5.25"
+ regs->cx = 0x2709; // 40 tracks, 9 sectors
+ regs->dh = 1; // max head #
+ break;
+
+ case 2: // 1.2MB, 5.25"
+ regs->cx = 0x4f0f; // 80 tracks, 15 sectors
+ regs->dh = 1; // max head #
+ break;
+
+ case 3: // 720KB, 3.5"
+ regs->cx = 0x4f09; // 80 tracks, 9 sectors
+ regs->dh = 1; // max head #
+ break;
+
+ case 4: // 1.44MB, 3.5"
+ regs->cx = 0x4f12; // 80 tracks, 18 sectors
+ regs->dh = 1; // max head #
+ break;
+
+ case 5: // 2.88MB, 3.5"
+ regs->cx = 0x4f24; // 80 tracks, 36 sectors
+ regs->dh = 1; // max head #
+ break;
+
+ case 6: // 160k, 5.25"
+ regs->cx = 0x2708; // 40 tracks, 8 sectors
+ regs->dh = 0; // max head #
+ break;
+
+ case 7: // 180k, 5.25"
+ regs->cx = 0x2709; // 40 tracks, 9 sectors
+ regs->dh = 0; // max head #
+ break;
+
+ case 8: // 320k, 5.25"
+ regs->cx = 0x2708; // 40 tracks, 8 sectors
+ regs->dh = 1; // max head #
+ break;
+
+ default: // ?
+ BX_PANIC("floppy: int13: bad floppy type\n");
+ }
+
+ /* set es & di to point to 11 byte diskette param table in ROM */
+ regs->es = SEG_BIOS;
+ regs->di = (u16)diskette_param_table2;
+ /* disk status not changed upon success */
+}
+
+// read diskette drive type
+static void
+floppy_1315(struct bregs *regs, u8 drive)
+{
+ DEBUGF("floppy f15\n");
+ if (drive > 1) {
+ regs->ah = 0; // only 2 drives supported
+ // set_diskette_ret_status here ???
+ set_cf(regs, 1);
+ return;
+ }
+ u8 drive_type = get_drive_type(drive);
+
+ regs->ah = (drive_type != 0);
+ set_cf(regs, 0);
+}
+
+// get diskette change line status
+static void
+floppy_1316(struct bregs *regs, u8 drive)
+{
+ DEBUGF("floppy f16\n");
+ if (drive > 1) {
+ floppy_ret(regs, DISK_RET_EPARAM);
+ return;
+ }
+ floppy_ret(regs, DISK_RET_ECHANGED);
+}
+
+static void
+floppy_13XX(struct bregs *regs, u8 drive)
+{
+ BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
+ floppy_ret(regs, DISK_RET_EPARAM);
+}
+
+void
+floppy_13(struct bregs *regs, u8 drive)
+{
+ if (CONFIG_FLOPPY_SUPPORT) {
+ switch (regs->ah) {
+ case 0x00: floppy_1300(regs, drive); break;
+ case 0x01: floppy_1301(regs, drive); break;
+ case 0x02: floppy_1302(regs, drive); break;
+ case 0x03: floppy_1303(regs, drive); break;
+ case 0x04: floppy_1304(regs, drive); break;
+ case 0x05: floppy_1305(regs, drive); break;
+ case 0x08: floppy_1308(regs, drive); break;
+ case 0x15: floppy_1315(regs, drive); break;
+ case 0x16: floppy_1316(regs, drive); break;
+ default: floppy_13XX(regs, drive); break;
+ }
+ } else {
+ switch (regs->ah) {
+ case 0x01: floppy_1301(regs, drive); break;
+ default: floppy_13XX(regs, drive); break;
+ }
+ }
+}
+
+// INT 0Eh Diskette Hardware ISR Entry Point
+void VISIBLE
+handle_0e(struct bregs *regs)
+{
+ debug_enter(regs);
+ if ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0) {
+ outb(0x08, PORT_FD_DATA); // sense interrupt status
+ while ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0)
+ ;
+ do {
+ inb(PORT_FD_DATA);
+ } while ((inb(PORT_FD_STATUS) & 0xc0) == 0xc0);
+ }
+ eoi_master_pic();
+ // diskette interrupt has occurred
+ SETBITS_BDA(floppy_recalibration_status, FRS_TIMEOUT);
+}
+
+// Called from int08 handler.
+void
+floppy_tick()
+{
+ // time to turn off drive(s)?
+ u8 fcount = GET_BDA(floppy_motor_counter);
+ if (fcount) {
+ fcount--;
+ SET_BDA(floppy_motor_counter, fcount);
+ if (fcount == 0)
+ // turn motor(s) off
+ outb(inb(PORT_FD_DOR) & 0xcf, PORT_FD_DOR);
+ }
+}
diff --git a/src/font.c b/src/font.c
new file mode 100644
index 0000000..01c73ed
--- /dev/null
+++ b/src/font.c
@@ -0,0 +1,139 @@
+#include "types.h" // u8
+
+// Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
+
+/*
+ * This font comes from the fntcol16.zip package (c) by Joseph Gil
+ * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
+ * This font is public domain
+ */
+const u8 vgafont8[128*8] __attribute__((aligned (1))) = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
+ 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
+ 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+ 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+ 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
+ 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
+ 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
+ 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
+ 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
+ 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
+ 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
+ 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
+ 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
+ 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
+ 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
+ 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
+ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
+ 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
+ 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
+ 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
+ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
+ 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
+ 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
+ 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
+ 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
+ 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
+ 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
+ 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
+ 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
+ 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
+ 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
+ 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
+ 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
+ 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
+ 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
+ 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
+ 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
+ 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
+ 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
+ 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
+ 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
+ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
+ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
+ 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
+ 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
+ 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
+ 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
+ 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
+ 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
+ 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
+ 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
+ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
+ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
+ 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
+ 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
+ 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
+ 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
+ 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
+ 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
+ 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
+ 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+ 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
+ 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
+ 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
+ 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
+ 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
+ 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
+ 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
+ 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
+ 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
+ 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
+ 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
+ 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
+ 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
+ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
+ 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
+ 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+ 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
+ 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
+ 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
+ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
+ 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
+ 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
+};
diff --git a/src/ioport.h b/src/ioport.h
new file mode 100644
index 0000000..344803e
--- /dev/null
+++ b/src/ioport.h
@@ -0,0 +1,56 @@
+// Definitions for X86 IO port access.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+#ifndef __IOPORT_H
+#define __IOPORT_H
+
+#include "types.h" // u8
+
+#define PORT_DMA_ADDR_2 0x0004
+#define PORT_DMA_CNT_2 0x0005
+#define PORT_DMA1_MASK_REG 0x000a
+#define PORT_DMA1_MODE_REG 0x000b
+#define PORT_DMA1_CLEAR_FF_REG 0x000c
+#define PORT_DMA1_MASTER_CLEAR 0x000d
+#define PORT_PIC1 0x0020
+#define PORT_PIC1_DATA 0x0021
+#define PORT_PIT_COUNTER0 0x0040
+#define PORT_PIT_COUNTER1 0x0041
+#define PORT_PIT_COUNTER2 0x0042
+#define PORT_PIT_MODE 0x0043
+#define PORT_KBD_CTRLB 0x0061
+#define PORT_CMOS_INDEX 0x0070
+#define PORT_CMOS_DATA 0x0071
+#define PORT_DMA_PAGE_2 0x0081
+#define PORT_A20 0x0092
+#define PORT_PIC2 0x00a0
+#define PORT_PIC2_DATA 0x00a1
+#define PORT_DMA2_MASK_REG 0x00d4
+#define PORT_DMA2_MODE_REG 0x00d6
+#define PORT_DMA2_MASTER_CLEAR 0x00da
+#define PORT_FD_DOR 0x03f2
+#define PORT_FD_STATUS 0x03f4
+#define PORT_FD_DATA 0x03f5
+
+// PORT_PIC1 bitdefs
+#define PIC1_IRQ5 (1<<5)
+// PORT_PIC2 bitdefs
+#define PIC2_IRQ8 (1<<0)
+#define PIC2_IRQ13 (1<<5)
+
+// PORT_KBD_CTRLB bitdefs
+#define KBD_REFRESH (1<<4)
+
+
+static inline void outb(u8 value, u16 port) {
+ __asm__ __volatile__("outb %b0, %w1" : : "a"(value), "Nd"(port));
+}
+static inline u8 inb(u16 port) {
+ u8 value;
+ __asm__ __volatile__("inb %w1, %b0" : "=a"(value) : "Nd"(port));
+ return value;
+}
+
+#endif // ioport.h
diff --git a/src/kbd.c b/src/kbd.c
new file mode 100644
index 0000000..bcc1a59
--- /dev/null
+++ b/src/kbd.c
@@ -0,0 +1,35 @@
+// 16bit code to handle keyboard requests.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "biosvar.h" // struct bregs
+#include "util.h" // debug_enter
+
+void
+handle_15c2(struct bregs *regs)
+{
+}
+
+// INT 16h Keyboard Service Entry Point
+void VISIBLE
+handle_16(struct bregs *regs)
+{
+ //debug_enter(regs);
+}
+
+// INT09h : Keyboard Hardware Service Entry Point
+void VISIBLE
+handle_09(struct bregs *regs)
+{
+ debug_enter(regs);
+}
+
+// INT74h : PS/2 mouse hardware interrupt
+void VISIBLE
+handle_74(struct bregs *regs)
+{
+ debug_enter(regs);
+}
diff --git a/src/output.c b/src/output.c
new file mode 100644
index 0000000..9670163
--- /dev/null
+++ b/src/output.c
@@ -0,0 +1,161 @@
+// Raw screen writing code.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include <stdarg.h> // va_list
+
+#include "farptr.h" // GET_VAR
+#include "util.h" // bprintf
+#include "biosvar.h" // struct bregs
+
+static void
+screenc(char c)
+{
+ // XXX
+}
+
+// XXX
+#define PORT_DEBUG 0x403
+
+// Write a charcter to the framebuffer.
+static void
+putc(u16 action, char c)
+{
+ screenc(c);
+ outb(c, PORT_DEBUG);
+}
+
+// Write a string to the framebuffer.
+static void
+puts(u16 action, const char *s)
+{
+ for (; *s; s++)
+ putc(action, *s);
+}
+
+// Write a string to the framebuffer.
+static void
+puts_cs(u16 action, const char *s)
+{
+ for (;; s++) {
+ char c = GET_VAR(CS, (u8)*s);
+ if (!c)
+ break;
+ putc(action, c);
+ }
+}
+
+// Write an unsigned integer to the screen.
+static void
+putuint(u16 action, u32 val)
+{
+ char buf[12];
+ char *d = &buf[sizeof(buf) - 1];
+ *d-- = '\0';
+ for (;;) {
+ *d = val % 10;
+ val /= 10;
+ if (!val)
+ break;
+ d--;
+ }
+ puts(action, d);
+}
+
+// Write a single digit hex character to the screen.
+static inline void
+putsinglehex(u16 action, u32 val)
+{
+ if (val <= 9)
+ val = '0' + val;
+ else
+ val = 'a' + val - 10;
+ putc(action, val);
+}
+
+// Write an integer in hexadecimal to the screen.
+static void
+puthex(u16 action, u32 val)
+{
+ putsinglehex(action, (val >> 28) & 0xf);
+ putsinglehex(action, (val >> 24) & 0xf);
+ putsinglehex(action, (val >> 20) & 0xf);
+ putsinglehex(action, (val >> 16) & 0xf);
+ putsinglehex(action, (val >> 12) & 0xf);
+ putsinglehex(action, (val >> 8) & 0xf);
+ putsinglehex(action, (val >> 4) & 0xf);
+ putsinglehex(action, (val >> 0) & 0xf);
+}
+
+void
+bprintf(u16 action, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ const char *s = fmt;
+ for (;; s++) {
+ char c = GET_VAR(CS, (u8)*s);
+ if (!c)
+ break;
+ if (c != '%') {
+ putc(action, c);
+ continue;
+ }
+ const char *n = s+1;
+ c = GET_VAR(CS, (u8)*n);
+ s32 val;
+ const char *sarg;
+ switch (c) {
+ case '%':
+ putc(action, '%');
+ break;
+ case 'd':
+ val = va_arg(args, s32);
+ if (val < 0) {
+ putc(action, '-');
+ val = -val;
+ }
+ putuint(action, val);
+ break;
+ case 'u':
+ val = va_arg(args, s32);
+ putuint(action, val);
+ break;
+ case 'x':
+ val = va_arg(args, s32);
+ puthex(action, val);
+ break;
+ case 's':
+ sarg = va_arg(args, const char *);
+ puts_cs(action, sarg);
+ break;
+ default:
+ putc(action, *s);
+ n = s;
+ }
+ s = n;
+ }
+ va_end(args);
+}
+
+// Function called on handler startup.
+void
+__debug_enter(const char *fname, struct bregs *regs)
+{
+ bprintf(0, "enter %s: a=%x b=%x c=%x d=%x si=%x di=%x\n"
+ , fname, regs->eax, regs->ebx, regs->ecx, regs->edx
+ , regs->esi, regs->edi);
+ bprintf(0, "&=%x ds=%x es=%x bp=%x sp=%x ip=%x cs=%x f=%x\n"
+ , (u32)regs, regs->ds, regs->es, regs->ebp, regs->esp
+ , regs->ip, regs->cs, regs->flags);
+}
+
+void
+__debug_exit(const char *fname, struct bregs *regs)
+{
+ bprintf(0, "exit %s: a=%x b=%x c=%x d=%x s=%x i=%x\n"
+ , fname, regs->eax, regs->ebx, regs->ecx, regs->edx
+ , regs->esi, regs->edi);
+}
diff --git a/src/post.c b/src/post.c
new file mode 100644
index 0000000..8d35f97
--- /dev/null
+++ b/src/post.c
@@ -0,0 +1,312 @@
+// 32bit code to Power On Self Test (POST) a machine.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "ioport.h" // PORT_*
+#include "../out/rom16.offset.auto.h" // OFFSET_*
+#include "config.h" // CONFIG_*
+#include "cmos.h" // CMOS_*
+#include "util.h" // memset
+#include "biosvar.h" // struct bios_data_area_s
+
+#define bda ((struct bios_data_area_s *)0)
+#define ebda ((struct extended_bios_data_area_s *)(EBDA_SEG<<4))
+
+static void
+init_bda()
+{
+ memset(bda, 0, sizeof(*bda));
+
+ int i;
+ for (i=0; i<256; i++) {
+ bda->ivecs[i].seg = 0xf000;
+ bda->ivecs[i].offset = OFFSET_dummy_iret_handler;
+ }
+
+ bda->mem_size_kb = BASE_MEM_IN_K;
+}
+
+static void
+init_handlers()
+{
+ // set vector 0x79 to zero
+ // this is used by 'gardian angel' protection system
+ bda->ivecs[0x79].seg = 0;
+ bda->ivecs[0x79].offset = 0;
+
+ bda->ivecs[0x40].offset = OFFSET_entry_40;
+ bda->ivecs[0x0e].offset = OFFSET_entry_0e;
+ bda->ivecs[0x13].offset = OFFSET_entry_13;
+ bda->ivecs[0x76].offset = OFFSET_entry_76;
+ bda->ivecs[0x17].offset = OFFSET_entry_17;
+ bda->ivecs[0x18].offset = OFFSET_entry_18;
+ bda->ivecs[0x19].offset = OFFSET_entry_19;
+ bda->ivecs[0x1c].offset = OFFSET_entry_1c;
+ bda->ivecs[0x12].offset = OFFSET_entry_12;
+ bda->ivecs[0x11].offset = OFFSET_entry_11;
+ bda->ivecs[0x15].offset = OFFSET_entry_15;
+ bda->ivecs[0x08].offset = OFFSET_entry_08;
+ bda->ivecs[0x09].offset = OFFSET_entry_09;
+ bda->ivecs[0x16].offset = OFFSET_entry_16;
+ bda->ivecs[0x14].offset = OFFSET_entry_14;
+ bda->ivecs[0x1a].offset = OFFSET_entry_1a;
+ bda->ivecs[0x70].offset = OFFSET_entry_70;
+ bda->ivecs[0x74].offset = OFFSET_entry_74;
+ bda->ivecs[0x75].offset = OFFSET_entry_75;
+ bda->ivecs[0x10].offset = OFFSET_entry_10;
+}
+
+static void
+init_ebda()
+{
+ ebda->size = EBDA_SIZE;
+ bda->ebda_seg = EBDA_SEG;
+ bda->ivecs[0x41].seg = EBDA_SEG;
+ bda->ivecs[0x41].offset = 0x3d; // XXX
+ bda->ivecs[0x46].seg = EBDA_SEG;
+ bda->ivecs[0x46].offset = 0x4d; // XXX
+}
+
+static void
+pit_setup()
+{
+ // timer0: binary count, 16bit count, mode 2
+ outb(0x34, PORT_PIT_MODE);
+ // maximum count of 0000H = 18.2Hz
+ outb(0x0, PORT_PIT_COUNTER0);
+ outb(0x0, PORT_PIT_COUNTER0);
+}
+
+static void
+kbd_init()
+{
+}
+
+static void
+kbd_setup()
+{
+ bda->kbd_mode = 0x10;
+ bda->kbd_buf_head = bda->kbd_buf_tail = offsetof(struct bios_data_area_s, kbd_buf);
+ bda->kbd_buf_start_offset = offsetof(struct bios_data_area_s, kbd_buf);
+ bda->kbd_buf_end_offset = offsetof(struct bios_data_area_s, kbd_buf[sizeof(bda->kbd_buf)]);
+ kbd_init();
+
+ // XXX
+ u16 eqb = bda->equipment_list_flags;
+ eqb = (eqb & 0xff00) | inb_cmos(CMOS_EQUIPMENT_INFO);
+ bda->equipment_list_flags = eqb;
+}
+
+static void
+lpt_setup()
+{
+ // XXX
+}
+
+static void
+serial_setup()
+{
+ // XXX
+}
+
+static u32
+bcd2bin(u8 val)
+{
+ return (val & 0xf) + ((val >> 4) * 10);
+}
+
+static void
+timer_setup()
+{
+ u32 seconds = bcd2bin(inb_cmos(CMOS_RTC_SECONDS));
+ u32 ticks = (seconds * 18206507) / 1000000;
+ u32 minutes = bcd2bin(inb_cmos(CMOS_RTC_MINUTES));
+ ticks += (minutes * 10923904) / 10000;
+ u32 hours = bcd2bin(inb_cmos(CMOS_RTC_HOURS));
+ ticks += (hours * 65543427) / 1000;
+ bda->timer_counter = ticks;
+ bda->timer_rollover = 0;
+}
+
+static void
+pic_setup()
+{
+ outb(0x11, PORT_PIC1);
+ outb(0x11, PORT_PIC2_DATA);
+ outb(0x08, PORT_PIC1_DATA);
+ outb(0x70, PORT_PIC2_DATA);
+ outb(0x04, PORT_PIC1_DATA);
+ outb(0x02, PORT_PIC2_DATA);
+ outb(0x01, PORT_PIC1_DATA);
+ outb(0x01, PORT_PIC2_DATA);
+ outb(0xb8, PORT_PIC1_DATA);
+ if (CONFIG_PS2_MOUSE)
+ outb(0x8f, PORT_PIC2_DATA);
+ else
+ outb(0x9f, PORT_PIC2_DATA);
+}
+
+static void
+floppy_drive_post()
+{
+ u8 type = inb_cmos(CMOS_FLOPPY_DRIVE_TYPE);
+ u8 out = 0;
+ if (type & 0xf0)
+ out |= 0x07;
+ if (type & 0x0f)
+ out |= 0x70;
+ bda->floppy_harddisk_info = out;
+ outb(0x02, PORT_DMA1_MASK_REG);
+
+ bda->ivecs[0x1E].offset = OFFSET_diskette_param_table2;
+}
+
+static void
+cdemu_init()
+{
+ //ebda->cdemu.active = 0;
+}
+
+static void
+ata_init()
+{
+}
+
+static void
+ata_detect()
+{
+}
+
+static void
+hard_drive_post()
+{
+}
+
+static void
+init_boot_vectors()
+{
+}
+
+static void __attribute__((noinline))
+call16(u16 seg, u16 offset)
+{
+ u32 segoff = (seg << 16) | offset;
+ asm volatile(
+ "pushal\n" // Save registers
+ "ljmp $0x20, %0\n" // Jump to 16bit transition code
+ ".globl call16_resume\n"
+ "call16_resume:\n" // point of return
+ "popal\n" // restore registers
+ : : "Z" (OFFSET_call16), "b" (segoff));
+}
+
+static int
+checksum(u8 *p, u32 len)
+{
+ u32 i;
+ u8 sum = 0;
+ for (i=0; i<len; i++)
+ sum += p[i];
+ return sum;
+}
+
+#define PTR_TO_SEG(p) ((((u32)(p)) >> 4) & 0xf000)
+#define PTR_TO_OFFSET(p) (((u32)(p)) & 0xffff)
+
+static void
+rom_scan()
+{
+ u8 *p = (u8*)0xc0000;
+ for (; p <= (u8*)0xe0000; p += 2048) {
+ u8 *rom = p;
+ if (*(u16*)rom != 0xaa55)
+ continue;
+ u32 len = rom[2] * 512;
+ if (checksum(rom, len) != 0)
+ continue;
+ p = (u8*)(((u32)p + len) / 2048 * 2048);
+ call16(PTR_TO_SEG(rom), PTR_TO_OFFSET(rom + 3));
+
+ // Look at the ROM's PnP Expansion header. Properly, we're supposed
+ // to init all the ROMs and then go back and build an IPL table of
+ // all the bootable devices, but we can get away with one pass.
+ if (rom[0x1a] != '$' || rom[0x1b] != 'P'
+ || rom[0x1c] != 'n' || rom[0x1d] != 'P')
+ continue;
+ // 0x1A is also the offset into the expansion header of...
+ // the Bootstrap Entry Vector, or zero if there is none.
+ u16 entry = *(u16*)&rom[0x1a+0x1a];
+ if (!entry)
+ continue;
+ // Found a device that thinks it can boot the system. Record
+ // its BEV and product name string.
+
+ // XXX
+ }
+}
+
+static void
+status_restart(u8 status)
+{
+#if 0
+ if (status == 0x05)
+ eoi_jmp_post();
+#endif
+
+ BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
+}
+
+static void
+post()
+{
+ // first reset the DMA controllers
+ outb(0, PORT_DMA1_MASTER_CLEAR);
+ outb(0, PORT_DMA2_MASTER_CLEAR);
+
+ // then initialize the DMA controllers
+ outb(0xc0, PORT_DMA2_MODE_REG);
+ outb(0x00, PORT_DMA2_MASK_REG);
+
+ // Get and then clear CMOS shutdown status.
+ u8 status = inb_cmos(CMOS_RESET_CODE);
+ outb_cmos(0, CMOS_RESET_CODE);
+
+ if (status != 0x00 && status != 0x09 && status < 0x0d)
+ status_restart(status);
+
+ BX_INFO("Start bios");
+
+ init_bda();
+ init_handlers();
+ init_ebda();
+
+ pit_setup();
+ kbd_setup();
+ lpt_setup();
+ serial_setup();
+ timer_setup();
+ pic_setup();
+ //pci_setup();
+ init_boot_vectors();
+ rom_scan();
+
+ printf("BIOS - begin\n\n");
+
+ floppy_drive_post();
+ hard_drive_post();
+ if (CONFIG_ATA) {
+ ata_init();
+ ata_detect();
+ }
+ cdemu_init();
+ call16(0xf000, OFFSET_begin_boot);
+}
+
+void VISIBLE
+_start()
+{
+ post();
+}
diff --git a/src/rombios32.lds.S b/src/rombios32.lds.S
new file mode 100644
index 0000000..dae62d8
--- /dev/null
+++ b/src/rombios32.lds.S
@@ -0,0 +1,31 @@
+// Linker definitions for 32bit code
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "config.h"
+#include "../out/rom16.offset.auto.h"
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start);
+SECTIONS
+{
+ . = (OFFSET_bios16c_end | 0xf0000);
+ . = ALIGN(16);
+ _text32_start = . ;
+ .text : { *(.text) }
+ .rodata : { *(.rodata) }
+ . = ALIGN(16);
+ .data : { *(.data) }
+ __bss_start = . ;
+ .bss : { *(.bss) *(COMMON) }
+ _end = . ;
+ /DISCARD/ : { *(.stab)
+ *(.stabstr)
+ *(.comment)
+ *(.note)
+ }
+}
diff --git a/src/romlayout.S b/src/romlayout.S
new file mode 100644
index 0000000..c9cc6ef
--- /dev/null
+++ b/src/romlayout.S
@@ -0,0 +1,304 @@
+// Rom layout and bios assembler to C interface.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "config.h"
+
+ .code16gcc
+ .text
+ .globl bios16c_start, bios16c_end
+bios16c_start:
+.include "out/blob.proc.16.s"
+ .text
+bios16c_end:
+
+
+ .org 0xe05b
+ .globl _start
+_start:
+ .globl post16
+post16:
+
+ // Entry point of rombios32 code - the actual instruction is
+ // altered later in the build process.
+ .globl set_entry32
+set_entry32:
+ mov $0xf0000000, %ebx
+
+ // init the stack pointer
+ movl $ CONFIG_STACK32_OFFSET , %esp
+
+transition32:
+ // Disable irqs
+ cli
+
+ // enable a20
+ inb $0x92, %al
+ orb $0x02, %al
+ outb %al, $0x92
+
+ // Set segment descriptors
+ lidt %cs:pmode_IDT_info
+ lgdt %cs:rombios32_gdt_48
+
+ // set PE bit in CR0
+ movl %cr0, %eax
+ orb $0x01, %al
+ movl %eax, %cr0
+
+ // start protected mode code
+ .word 0xea66, 1f, 0x000f, 0x0010 // ljmpl $0x10, $(post32 | 0xf0000)
+
+ .code32
+1:
+ // init data segments
+ movl $0x18, %eax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %ss
+ xorl %eax, %eax
+ movw %ax, %fs
+ movw %ax, %gs
+
+ cld
+
+ jmp *%ebx
+
+ .code16gcc
+
+// We need a copy of this string, but we are not actually a PnP BIOS,
+// so make sure it is *not* aligned, so OSes will not see it if they
+// scan.
+ .align 2
+ .byte 0
+pnp_string:
+ .ascii "$PnP"
+
+// Return from 32bit code to 16bit code - must pass in destination
+// code segment,offset (%ebx) and the return stack position (%esp).
+
+ .globl call16
+call16:
+ // restore data segment limits to 0xffff
+ movw $0x28, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %ss
+ movw %ax, %fs
+ movw %ax, %gs
+
+ // reset PE bit in CR0
+ movl %cr0, %eax
+ andb $0xfe, %al
+ movl %eax, %cr0
+
+ // far jump to flush CPU queue after transition to real mode
+ ljmpw $0xf000, $1f
+1:
+ // restore IDT to normal real-mode defaults
+ lidt %cs:rmode_IDT_info
+
+ // Setup segment registers
+ xorw %ax, %ax
+ movw %ax, %ds
+ movw %ax, %fs
+ movw %ax, %gs
+ movw $0xf000, %ax
+ movw %ax, %es
+ lea pnp_string, %di
+ movw $ CONFIG_STACK16_SEGMENT , %ax
+ movw %ax, %ss
+ movl %esp, %eax
+ movl $ CONFIG_STACK16_OFFSET , %esp
+
+ // Save info
+ pushl %eax
+ pushl %ebx
+ movl %esp, %ebp
+
+ lcallw %ss:*(%bp)
+
+ // Restore stack and jump back to 32bit mode.
+ popl %eax
+ popl %esp
+
+ // Resume point of rombios32 code - the actual instruction is
+ // altered later in the build process.
+ .globl set_resume32
+set_resume32:
+ mov $0xf0000000, %ebx
+
+ jmp transition32
+
+
+// Protected mode IDT descriptor
+//
+// I just make the limit 0, so the machine will shutdown
+// if an exception occurs during protected mode memory
+// transfers.
+//
+// Set base to f0000 to correspond to beginning of BIOS,
+// in case I actually define an IDT later
+// Set limit to 0
+pmode_IDT_info:
+ .word 0x0000 // limit 15:00
+ .word 0x0000 // base 15:00
+ .byte 0x0f // base 23:16
+
+// Real mode IDT descriptor
+//
+// Set to typical real-mode values.
+// base = 000000
+// limit = 03ff
+rmode_IDT_info:
+ .word 0x03ff // limit 15:00
+ .word 0x0000 // base 15:00
+ .byte 0x00 // base 23:16
+
+rombios32_gdt_48:
+ .word 0x30
+ .word rombios32_gdt
+ .word 0x000f
+
+rombios32_gdt:
+ .word 0, 0, 0, 0
+ .word 0, 0, 0, 0
+ .word 0xffff, 0, 0x9b00, 0x00cf // 32 bit flat code segment (0x10)
+ .word 0xffff, 0, 0x9300, 0x00cf // 32 bit flat data segment (0x18)
+ .word 0xffff, 0, 0x9b0f, 0x0000 // 16 bit code segment base=0xf0000 limit=0xffff
+ .word 0xffff, 0, 0x9300, 0x0000 // 16 bit data segment base=0x0 limit=0xffff
+
+
+ .macro ENTRY cfunc
+ pushal
+ pushw %es
+ pushw %ds
+ movw %ss, %ax
+ movw %ax, %ds
+ mov %esp, %eax
+ call \cfunc
+ popw %ds
+ popw %es
+ popal
+ .endm
+
+ .macro IRQ_ENTRY num
+ .globl entry_\num
+ entry_\num :
+ ENTRY handle_\num
+ iretw
+ .endm
+
+
+ .org 0xe2c3
+ IRQ_ENTRY nmi
+
+ IRQ_ENTRY 13
+ IRQ_ENTRY 19
+ IRQ_ENTRY 12
+ IRQ_ENTRY 11
+ IRQ_ENTRY 76
+ IRQ_ENTRY 18
+ IRQ_ENTRY 1c
+ IRQ_ENTRY 70
+ IRQ_ENTRY 74
+ IRQ_ENTRY 75
+
+ .org 0xe3fe
+ jmp entry_13
+
+ .org 0xe401
+ // XXX - Fixed Disk Parameter Table
+
+ .org 0xe6f2
+ jmp entry_19
+
+ .org 0xe6f5
+.include "out/cbt.proc.16.s"
+ .text
+
+ .org 0xe729
+ // XXX - Baud Rate Generator Table
+
+ .org 0xe739
+ IRQ_ENTRY 14
+
+ .org 0xe82e
+ IRQ_ENTRY 16
+
+ .org 0xe987
+ IRQ_ENTRY 09
+
+ .org 0xec59
+ IRQ_ENTRY 40
+
+ .org 0xef57
+ IRQ_ENTRY 0e
+
+ .org 0xefc7
+ // XXX - Diskette Controller Parameter Table
+
+ .org 0xefd2
+ IRQ_ENTRY 17
+
+ .org 0xf045
+ // XXX int 10
+ iretw
+
+ .org 0xf065
+ IRQ_ENTRY 10
+
+ .org 0xf0a4
+ // XXX int 1D
+ iretw
+
+ .org 0xf841
+ jmp entry_12
+
+ .org 0xf84d
+ jmp entry_11
+
+ .org 0xf859
+ IRQ_ENTRY 15
+
+ .org 0xfa6e
+.include "out/font.proc.16.s"
+ .text
+
+ .org 0xfe6e
+ IRQ_ENTRY 1a
+
+ .org 0xfea5
+ IRQ_ENTRY 08
+
+ .org 0xfef3
+ // XXX - Initial Interrupt Vector Offsets Loaded by POST
+
+ .org 0xff00
+ // XXX - BIOS_COPYRIGHT_STRING
+ .ascii "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
+
+ .org 0xff53
+ .globl dummy_iret_handler
+dummy_iret_handler:
+ iretw
+
+ .org 0xff54
+ IRQ_ENTRY 05
+
+ .org 0xfff0 // Power-up Entry Point
+ ljmpw $0xf000, $post16
+
+ .org 0xfff5
+ // BIOS build date
+ .ascii "06/23/99"
+
+ .org 0xfffe
+ // model byte 0xFC = AT
+ .byte 0xfc
+ .byte 0x00
+
+ .end
diff --git a/src/serial.c b/src/serial.c
new file mode 100644
index 0000000..5541089
--- /dev/null
+++ b/src/serial.c
@@ -0,0 +1,23 @@
+// 16bit code to handle serial and printer services.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "biosvar.h" // struct bregs
+#include "util.h" // debug_enter
+
+// INT 14h Serial Communications Service Entry Point
+void VISIBLE
+handle_14(struct bregs *regs)
+{
+ debug_enter(regs);
+}
+
+// INT17h : Printer Service Entry Point
+void VISIBLE
+handle_17(struct bregs *regs)
+{
+ debug_enter(regs);
+}
diff --git a/src/system.c b/src/system.c
new file mode 100644
index 0000000..3967fc4
--- /dev/null
+++ b/src/system.c
@@ -0,0 +1,529 @@
+// 16bit system callbacks
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "util.h" // irq_restore
+#include "biosvar.h" // CONFIG_BIOS_TABLE
+#include "ioport.h" // inb
+#include "cmos.h" // inb_cmos
+
+#define RET_EUNSUPPORTED 0x86
+
+
+// Use PS2 System Control port A to set A20 enable
+static inline u8
+set_a20(u8 cond)
+{
+ // get current setting first
+ u8 newval, oldval = inb(PORT_A20);
+ if (cond)
+ newval = oldval | 0x02;
+ else
+ newval = oldval & ~0x02;
+ outb(newval, PORT_A20);
+
+ return (newval & 0x02) != 0;
+}
+
+static inline void
+handle_ret(struct bregs *regs, u8 code)
+{
+ regs->ah = code;
+ set_cf(regs, code);
+}
+
+static void
+handle_152400(struct bregs *regs)
+{
+ set_a20(0);
+ handle_ret(regs, 0);
+}
+
+static void
+handle_152401(struct bregs *regs)
+{
+ set_a20(1);
+ handle_ret(regs, 0);
+}
+
+static void
+handle_152402(struct bregs *regs)
+{
+ regs->al = !!(inb(PORT_A20) & 0x20);
+ handle_ret(regs, 0);
+}
+
+static void
+handle_152403(struct bregs *regs)
+{
+ regs->bx = 3;
+ handle_ret(regs, 0);
+}
+
+static void
+handle_1524XX(struct bregs *regs)
+{
+ handle_ret(regs, RET_EUNSUPPORTED);
+}
+
+// removable media eject
+static void
+handle_1552(struct bregs *regs)
+{
+ handle_ret(regs, 0);
+}
+
+// Set Interval requested.
+static void
+handle_158300(struct bregs *regs)
+{
+ if (GET_BDA(rtc_wait_flag) & RWS_WAIT_PENDING) {
+ // Interval already set.
+ DEBUGF("int15: Func 83h, failed, already waiting.\n" );
+ handle_ret(regs, RET_EUNSUPPORTED);
+ }
+ // Interval not already set.
+ SET_BDA(rtc_wait_flag, RWS_WAIT_PENDING); // Set status byte.
+ u32 v = (regs->es << 16) | regs->bx;
+ SET_BDA(ptr_user_wait_complete_flag, v);
+ v = (regs->dx << 16) | regs->cx;
+ SET_BDA(user_wait_timeout, v);
+
+ // Unmask IRQ8 so INT70 will get through.
+ u8 irqDisable = inb(PORT_PIC2_DATA);
+ outb(irqDisable & ~PIC2_IRQ8, PORT_PIC2_DATA);
+ // Turn on the Periodic Interrupt timer
+ u8 bRegister = inb_cmos(CMOS_STATUS_B);
+ outb_cmos(CMOS_STATUS_B, bRegister | CSB_EN_ALARM_IRQ);
+
+ set_cf(regs, 0); // XXX - no set ah?
+}
+
+// Clear interval requested
+static void
+handle_158301(struct bregs *regs)
+{
+ SET_BDA(rtc_wait_flag, 0); // Clear status byte
+ // Turn off the Periodic Interrupt timer
+ u8 bRegister = inb_cmos(CMOS_STATUS_B);
+ outb_cmos(CMOS_STATUS_B, bRegister & ~CSB_EN_ALARM_IRQ);
+ set_cf(regs, 0); // XXX - no set ah?
+}
+
+static void
+handle_1583XX(struct bregs *regs)
+{
+ regs->al--;
+ handle_ret(regs, RET_EUNSUPPORTED);
+}
+
+// Sleep for n microseconds. currently using the
+// refresh request port 0x61 bit4, toggling every 15usec
+static void
+usleep(u32 count)
+{
+ count = count / 15;
+ u8 kbd = inb(PORT_KBD_CTRLB);
+ while (count)
+ if ((inb(PORT_KBD_CTRLB) ^ kbd) & KBD_REFRESH)
+ count--;
+}
+
+// Wait for CX:DX microseconds. currently using the
+// refresh request port 0x61 bit4, toggling every 15usec
+static void
+handle_1586(struct bregs *regs)
+{
+ irq_enable();
+ usleep((regs->cx << 16) | regs->dx);
+ irq_disable();
+}
+
+static void
+handle_1587(struct bregs *regs)
+{
+ // +++ should probably have descriptor checks
+ // +++ should have exception handlers
+
+ // turn off interrupts
+ unsigned long flags = irq_save();
+
+ u8 prev_a20_enable = set_a20(1); // enable A20 line
+
+ // 128K max of transfer on 386+ ???
+ // source == destination ???
+
+ // ES:SI points to descriptor table
+ // offset use initially comments
+ // ==============================================
+ // 00..07 Unused zeros Null descriptor
+ // 08..0f GDT zeros filled in by BIOS
+ // 10..17 source ssssssss source of data
+ // 18..1f dest dddddddd destination of data
+ // 20..27 CS zeros filled in by BIOS
+ // 28..2f SS zeros filled in by BIOS
+
+ //es:si
+ //eeee0
+ //0ssss
+ //-----
+
+// check for access rights of source & dest here
+
+ // Initialize GDT descriptor
+ u16 si = regs->si;
+ u16 base15_00 = (regs->es << 4) + si;
+ u16 base23_16 = regs->es >> 12;
+ if (base15_00 < (regs->es<<4))
+ base23_16++;
+ SET_VAR(ES, *(u16*)(si+0x08+0), 47); // limit 15:00 = 6 * 8bytes/descriptor
+ SET_VAR(ES, *(u16*)(si+0x08+2), base15_00);// base 15:00
+ SET_VAR(ES, *(u8 *)(si+0x08+4), base23_16);// base 23:16
+ SET_VAR(ES, *(u8 *)(si+0x08+5), 0x93); // access
+ SET_VAR(ES, *(u16*)(si+0x08+6), 0x0000); // base 31:24/reserved/limit 19:16
+
+ // Initialize CS descriptor
+ SET_VAR(ES, *(u16*)(si+0x20+0), 0xffff);// limit 15:00 = normal 64K limit
+ SET_VAR(ES, *(u16*)(si+0x20+2), 0x0000);// base 15:00
+ SET_VAR(ES, *(u8 *)(si+0x20+4), 0x000f);// base 23:16
+ SET_VAR(ES, *(u8 *)(si+0x20+5), 0x9b); // access
+ SET_VAR(ES, *(u16*)(si+0x20+6), 0x0000);// base 31:24/reserved/limit 19:16
+
+ // Initialize SS descriptor
+ u16 ss = GET_SEG(SS);
+ base15_00 = ss << 4;
+ base23_16 = ss >> 12;
+ SET_VAR(ES, *(u16*)(si+0x28+0), 0xffff); // limit 15:00 = normal 64K limit
+ SET_VAR(ES, *(u16*)(si+0x28+2), base15_00);// base 15:00
+ SET_VAR(ES, *(u8 *)(si+0x28+4), base23_16);// base 23:16
+ SET_VAR(ES, *(u8 *)(si+0x28+5), 0x93); // access
+ SET_VAR(ES, *(u16*)(si+0x28+6), 0x0000); // base 31:24/reserved/limit 19:16
+
+ asm volatile(
+ // Save registers
+ "pushw %%ds\n"
+ "pushw %%es\n"
+ "pushal\n"
+
+ // Load new descriptor tables
+ "lgdt %%es:(%1)\n"
+ "lidt %%cs:pmode_IDT_info\n"
+
+ // set PE bit in CR0
+ "movl %%cr0, %%eax\n"
+ "orb $0x01, %%al\n"
+ "movl %%eax, %%cr0\n"
+
+ // far jump to flush CPU queue after transition to protected mode
+ "ljmpw $0xf000, $1f\n"
+ "1:\n"
+
+ // GDT points to valid descriptor table, now load DS, ES
+ "movw $0x10, %%ax\n" // 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
+ "movw %%ax, %%ds\n"
+ "movw $0x18, %%ax\n" // 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
+ "movw %%ax, %%es\n"
+
+ // move CX words from DS:SI to ES:DI
+ "xorw %%si, %%si\n"
+ "xorw %%di, %%di\n"
+ "cld\n"
+ "rep movsw\n"
+
+ // reset PG bit in CR0 ???
+ "movl %%cr0, %%eax\n"
+ "andb $0xfe, %%al\n"
+ "movl %%eax, %%cr0\n"
+
+ // far jump to flush CPU queue after transition to real mode
+ "ljmpw $0xf000, $2f\n"
+ "2:\n"
+
+ // restore IDT to normal real-mode defaults
+ "lidt %%cs:rmode_IDT_info\n"
+
+ // restore regisers
+ "popal\n"
+ "popw %%es\n"
+ "popw %%ds\n" : : "c" (regs->cx), "r" (si + 8));
+
+ set_a20(prev_a20_enable);
+
+ irq_restore(flags);
+
+ handle_ret(regs, 0);
+}
+
+// Get the amount of extended memory (above 1M)
+static void
+handle_1588(struct bregs *regs)
+{
+ regs->al = inb_cmos(CMOS_EXTMEM_LOW);
+ regs->ah = inb_cmos(CMOS_EXTMEM_HIGH);
+ // According to Ralf Brown's interrupt the limit should be 15M,
+ // but real machines mostly return max. 63M.
+ if (regs->ax > 0xffc0)
+ regs->ax = 0xffc0;
+ set_cf(regs, 0);
+}
+
+// Device busy interrupt. Called by Int 16h when no key available
+static void
+handle_1590(struct bregs *regs)
+{
+}
+
+// Interrupt complete. Called by Int 16h when key becomes available
+static void
+handle_1591(struct bregs *regs)
+{
+}
+
+static void
+handle_15c0(struct bregs *regs)
+{
+ regs->es = SEG_BIOS;
+ regs->bx = (u16)&BIOS_CONFIG_TABLE;
+}
+
+static void
+handle_15c1(struct bregs *regs)
+{
+ regs->es = GET_BDA(ebda_seg);
+ set_cf(regs, 0);
+}
+
+static void
+handle_15e801(struct bregs *regs)
+{
+ // my real system sets ax and bx to 0
+ // this is confirmed by Ralph Brown list
+ // but syslinux v1.48 is known to behave
+ // strangely if ax is set to 0
+ // regs.u.r16.ax = 0;
+ // regs.u.r16.bx = 0;
+
+ // Get the amount of extended memory (above 1M)
+ regs->cl = inb_cmos(CMOS_EXTMEM_LOW);
+ regs->ch = inb_cmos(CMOS_EXTMEM_HIGH);
+
+ // limit to 15M
+ if (regs->cx > 0x3c00)
+ regs->cx = 0x3c00;
+
+ // Get the amount of extended memory above 16M in 64k blocs
+ regs->dl = inb_cmos(CMOS_EXTMEM2_LOW);
+ regs->dh = inb_cmos(CMOS_EXTMEM2_HIGH);
+
+ // Set configured memory equal to extended memory
+ regs->ax = regs->cx;
+ regs->bx = regs->dx;
+
+ set_cf(regs, 0);
+}
+
+#define ACPI_DATA_SIZE 0x00010000L
+
+static void
+set_e820_range(u16 DI, u32 start, u32 end, u16 type)
+{
+ SET_VAR(ES, *(u16*)(DI+0), start);
+ SET_VAR(ES, *(u16*)(DI+2), start >> 16);
+ SET_VAR(ES, *(u16*)(DI+4), 0x00);
+ SET_VAR(ES, *(u16*)(DI+6), 0x00);
+
+ end -= start;
+ SET_VAR(ES, *(u16*)(DI+8), end);
+ SET_VAR(ES, *(u16*)(DI+10), end >> 16);
+ SET_VAR(ES, *(u16*)(DI+12), 0x0000);
+ SET_VAR(ES, *(u16*)(DI+14), 0x0000);
+
+ SET_VAR(ES, *(u16*)(DI+16), type);
+ SET_VAR(ES, *(u16*)(DI+18), 0x0);
+}
+
+// XXX - should create e820 memory map in post and just copy it here.
+static void
+handle_15e820(struct bregs *regs)
+{
+ if (regs->edx != 0x534D4150) {
+ handle_ret(regs, RET_EUNSUPPORTED);
+ return;
+ }
+
+ u32 extended_memory_size = inb_cmos(CMOS_EXTMEM2_HIGH);
+ extended_memory_size <<= 8;
+ extended_memory_size |= inb_cmos(CMOS_EXTMEM2_LOW);
+ extended_memory_size *= 64;
+ // greater than EFF00000???
+ if (extended_memory_size > 0x3bc000)
+ // everything after this is reserved memory until we get to 0x100000000
+ extended_memory_size = 0x3bc000;
+ extended_memory_size *= 1024;
+ extended_memory_size += (16L * 1024 * 1024);
+
+ if (extended_memory_size <= (16L * 1024 * 1024)) {
+ extended_memory_size = inb_cmos(CMOS_EXTMEM_HIGH);
+ extended_memory_size <<= 8;
+ extended_memory_size |= inb_cmos(CMOS_EXTMEM_LOW);
+ extended_memory_size *= 1024;
+ }
+
+ switch (regs->bx) {
+ case 0:
+ set_e820_range(regs->di, 0x0000000L, 0x0009fc00L, 1);
+ regs->ebx = 1;
+ regs->eax = 0x534D4150;
+ regs->ecx = 0x14;
+ set_cf(regs, 0);
+ break;
+ case 1:
+ set_e820_range(regs->di, 0x0009fc00L, 0x000a0000L, 2);
+ regs->ebx = 2;
+ regs->eax = 0x534D4150;
+ regs->ecx = 0x14;
+ set_cf(regs, 0);
+ break;
+ case 2:
+ set_e820_range(regs->di, 0x000e8000L, 0x00100000L, 2);
+ regs->ebx = 3;
+ regs->eax = 0x534D4150;
+ regs->ecx = 0x14;
+ set_cf(regs, 0);
+ break;
+ case 3:
+ set_e820_range(regs->di, 0x00100000L,
+ extended_memory_size - ACPI_DATA_SIZE, 1);
+ regs->ebx = 4;
+ regs->eax = 0x534D4150;
+ regs->ecx = 0x14;
+ set_cf(regs, 0);
+ break;
+ case 4:
+ set_e820_range(regs->di,
+ extended_memory_size - ACPI_DATA_SIZE,
+ extended_memory_size, 3); // ACPI RAM
+ regs->ebx = 5;
+ regs->eax = 0x534D4150;
+ regs->ecx = 0x14;
+ set_cf(regs, 0);
+ break;
+ case 5:
+ /* 256KB BIOS area at the end of 4 GB */
+ set_e820_range(regs->di, 0xfffc0000L, 0x00000000L, 2);
+ regs->ebx = 0;
+ regs->eax = 0x534D4150;
+ regs->ecx = 0x14;
+ set_cf(regs, 0);
+ break;
+ default: /* AX=E820, DX=534D4150, BX unrecognized */
+ handle_ret(regs, RET_EUNSUPPORTED);
+ }
+}
+
+static void
+handle_15e8XX(struct bregs *regs)
+{
+ regs->al--;
+ handle_ret(regs, RET_EUNSUPPORTED);
+}
+
+static void
+handle_15XX(struct bregs *regs)
+{
+ regs->al--;
+ handle_ret(regs, RET_EUNSUPPORTED);
+}
+
+// INT 15h System Services Entry Point
+void VISIBLE
+handle_15(struct bregs *regs)
+{
+ debug_enter(regs);
+ switch (regs->ah) {
+ case 0x24:
+ switch (regs->al) {
+ case 0x00: handle_152400(regs); break;
+ case 0x01: handle_152401(regs); break;
+ case 0x02: handle_152402(regs); break;
+ case 0x03: handle_152403(regs); break;
+ default: handle_1524XX(regs); break;
+ }
+ break;
+ case 0x52: handle_1552(regs); break;
+ case 0x83:
+ switch (regs->al) {
+ case 0x00: handle_158300(regs); break;
+ case 0x01: handle_158301(regs); break;
+ default: handle_1583XX(regs); break;
+ }
+ break;
+ case 0x86: handle_1586(regs); break;
+ case 0x87: handle_1587(regs); break;
+ case 0x88: handle_1588(regs); break;
+ case 0x90: handle_1590(regs); break;
+ case 0x91: handle_1591(regs); break;
+ case 0xc0: handle_15c0(regs); break;
+ case 0xc1: handle_15c1(regs); break;
+ case 0xc2: handle_15c2(regs); break;
+ case 0xe8:
+ switch (regs->al) {
+ case 0x01: handle_15e801(regs); break;
+ case 0x20: handle_15e820(regs); break;
+ default: handle_15e8XX(regs); break;
+ }
+ break;
+ default: handle_15XX(regs); break;
+ }
+ debug_exit(regs);
+}
+
+// INT 12h Memory Size Service Entry Point
+void VISIBLE
+handle_12(struct bregs *regs)
+{
+ debug_enter(regs);
+ regs->ax = GET_BDA(mem_size_kb);
+ debug_exit(regs);
+}
+
+// INT 11h Equipment List Service Entry Point
+void VISIBLE
+handle_11(struct bregs *regs)
+{
+ debug_enter(regs);
+ regs->ax = GET_BDA(equipment_list_flags);
+ debug_exit(regs);
+}
+
+// INT 05h Print Screen Service Entry Point
+void VISIBLE
+handle_05(struct bregs *regs)
+{
+ debug_enter(regs);
+}
+
+// INT 10h Video Support Service Entry Point
+void VISIBLE
+handle_10(struct bregs *regs)
+{
+ debug_enter(regs);
+ // dont do anything, since the VGA BIOS handles int10h requests
+}
+
+void VISIBLE
+handle_nmi(struct bregs *regs)
+{
+ debug_enter(regs);
+ // XXX
+}
+
+// INT 75 - IRQ13 - MATH COPROCESSOR EXCEPTION
+void VISIBLE
+handle_75(struct bregs *regs)
+{
+ debug_enter(regs);
+}
diff --git a/src/types.h b/src/types.h
new file mode 100644
index 0000000..ea245bf
--- /dev/null
+++ b/src/types.h
@@ -0,0 +1,21 @@
+// Basic type definitions for X86 cpus.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+#ifndef __TYPES_H
+#define __TYPES_H
+
+typedef unsigned char u8;
+typedef signed char s8;
+typedef unsigned short u16;
+typedef signed short s16;
+typedef unsigned int u32;
+typedef signed int s32;
+typedef u32 size_t;
+
+#define VISIBLE __attribute__((externally_visible))
+
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+#endif // types.h
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..0870ad5
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,55 @@
+// Basic x86 asm functions and function defs.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "ioport.h" // outb
+
+static inline void irq_disable(void) {
+ asm volatile("cli": : :"memory");
+}
+
+static inline void irq_enable(void) {
+ asm volatile("sti": : :"memory");
+}
+
+static inline unsigned long irq_save(void)
+{
+ unsigned long flags;
+ asm volatile("pushfl ; popl %0" : "=g" (flags));
+ irq_disable();
+ return flags;
+}
+
+static inline void irq_restore(unsigned long flags)
+{
+ asm volatile("pushl %0 ; popfl" : : "g" (flags) : "memory", "cc");
+}
+
+#define DEBUGF(fmt, args...)
+#define BX_PANIC(fmt, args...)
+#define BX_INFO(fmt, args...)
+
+static inline void
+memset(void *s, int c, size_t n)
+{
+ while (n)
+ ((char *)s)[n--] = c;
+}
+
+// output.c
+void bprintf(u16 action, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+struct bregs;
+void __debug_enter(const char *fname, struct bregs *regs);
+void __debug_exit(const char *fname, struct bregs *regs);
+#define debug_enter(regs) \
+ __debug_enter(__func__, regs)
+#define debug_exit(regs) \
+ __debug_exit(__func__, regs)
+#define printf(fmt, args...) \
+ bprintf(0, fmt , ##args )
+
+// kbd.c
+void handle_15c2(struct bregs *regs);
diff --git a/tools/buildrom.py b/tools/buildrom.py
new file mode 100755
index 0000000..beb51ac
--- /dev/null
+++ b/tools/buildrom.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+# Script to merge a rom32.bin file into a rom16.bin file.
+#
+# Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import sys
+import struct
+
+ROM16='out/rom16.bin'
+ROM32='out/rom32.bin'
+OFFSETS16='out/rom16.offset.auto.h'
+OFFSETS32='out/rom32.offset.auto.h'
+OUT='out/rom.bin'
+
+def align(v, a):
+ return (v + a - 1) // a * a
+
+def scanconfig(file):
+ f = open(file, 'rb')
+ opts = {}
+ for l in f.readlines():
+ parts = l.split()
+ if len(parts) != 3:
+ continue
+ if parts[0] != '#define':
+ continue
+ opts[parts[1]] = parts[2]
+ return opts
+
+def alteraddr(data, offset, ptr):
+ rel = struct.pack("<i", ptr)
+ return data[:offset] + rel + data[offset+4:]
+
+
+def main():
+ # Read in files
+ f = open(ROM16, 'rb')
+ data16 = f.read()
+ f = open(ROM32, 'rb')
+ data32 = f.read()
+
+ if len(data16) != 65536:
+ print "16bit code is not 65536 bytes long"
+ sys.exit(1)
+
+ # Get config options
+ o16 = scanconfig(OFFSETS16)
+ o32 = scanconfig(OFFSETS32)
+
+ # Inject 32bit code
+ spos = align(int(o16['OFFSET_bios16c_end'], 16), 16)
+ epos = int(o16['OFFSET_post16'], 16)
+ size32 = len(data32)
+ freespace = epos - spos
+ if size32 > freespace:
+ print "32bit code too large (%d vs %d)" % (size32, freespace)
+ sys.exit(1)
+ outrom = data16[:spos] + data32 + data16[spos+size32:]
+
+ # Fixup initial jump to 32 bit code
+ jmppos = int(o16['OFFSET_set_entry32'], 16)
+ start32 = int(o32['OFFSET__start'], 16)
+ outrom = alteraddr(outrom, jmppos+2, start32)
+
+ # Fixup resume from 16 jump to 32 bit code
+ jmppos = int(o16['OFFSET_set_resume32'], 16)
+ resume32 = int(o32['OFFSET_call16_resume'], 16)
+ outrom = alteraddr(outrom, jmppos+2, resume32)
+
+ # Write output rom
+ f = open(OUT, 'wb')
+ f.write(outrom)
+ f.close()
+
+if __name__ == '__main__':
+ main()
diff --git a/tools/defsyms.py b/tools/defsyms.py
new file mode 100755
index 0000000..fe18d90
--- /dev/null
+++ b/tools/defsyms.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+# Simple script to convert the output from 'nm' to a C style header
+# file with defined offsets.
+#
+# Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import sys
+import string
+
+def main():
+ syms = []
+ lines = sys.stdin.readlines()
+ for line in lines:
+ addr, type, sym = line.split()
+ if type not in 'TA':
+ # Only interested in global symbols in text segment
+ continue
+ for c in sym:
+ if c not in string.letters + string.digits + '_':
+ break
+ else:
+ syms.append((sym, addr))
+ print """
+#ifndef __OFFSET16_AUTO_H
+#define __OFFSET16_AUTO_H
+// Auto generated file - please see defsyms.py.
+// This file contains symbol offsets of a compiled binary.
+"""
+ for sym, addr in syms:
+ print "#define OFFSET_%s 0x%s" % (sym, addr)
+ print """
+#endif // __OFFSET16_AUTO_H
+"""
+
+if __name__ == '__main__':
+ main()