diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2008-02-25 22:25:15 -0500 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2008-02-25 22:25:15 -0500 |
commit | f076a3eeb9a0185b06a2abbba8c798a7761b2bdf (patch) | |
tree | c4a56a0d43fc683678e91ab10a9fe561f9ef65ca |
Initial checkin.
-rw-r--r-- | COPYING | 674 | ||||
-rw-r--r-- | Makefile | 88 | ||||
-rw-r--r-- | README | 71 | ||||
-rw-r--r-- | TODO | 22 | ||||
-rw-r--r-- | src/biosvar.h | 184 | ||||
-rw-r--r-- | src/boot.c | 118 | ||||
-rw-r--r-- | src/cbt.c | 8 | ||||
-rw-r--r-- | src/clock.c | 54 | ||||
-rw-r--r-- | src/cmos.h | 51 | ||||
-rw-r--r-- | src/config.h | 8 | ||||
-rw-r--r-- | src/disk.c | 67 | ||||
-rw-r--r-- | src/disk.h | 33 | ||||
-rw-r--r-- | src/farptr.h | 57 | ||||
-rw-r--r-- | src/floppy.c | 757 | ||||
-rw-r--r-- | src/font.c | 139 | ||||
-rw-r--r-- | src/ioport.h | 56 | ||||
-rw-r--r-- | src/kbd.c | 35 | ||||
-rw-r--r-- | src/output.c | 161 | ||||
-rw-r--r-- | src/post.c | 312 | ||||
-rw-r--r-- | src/rombios32.lds.S | 31 | ||||
-rw-r--r-- | src/romlayout.S | 304 | ||||
-rw-r--r-- | src/serial.c | 23 | ||||
-rw-r--r-- | src/system.c | 529 | ||||
-rw-r--r-- | src/types.h | 21 | ||||
-rw-r--r-- | src/util.h | 55 | ||||
-rwxr-xr-x | tools/buildrom.py | 78 | ||||
-rwxr-xr-x | tools/defsyms.py | 38 |
27 files changed, 3974 insertions, 0 deletions
@@ -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 @@ -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. @@ -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() |