From: Jack Lange Date: Fri, 7 Jun 2013 20:01:11 +0000 (-0500) Subject: imported SEABIOS source tree X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=ab1e08bb6653d0d65ff64ea8f42506b9fd502357 imported SEABIOS source tree --- diff --git a/bios/seabios/.config b/bios/seabios/.config new file mode 100644 index 0000000..992484a --- /dev/null +++ b/bios/seabios/.config @@ -0,0 +1,72 @@ +# +# Automatically generated make config: don't edit +# SeaBIOS Configuration +# Wed Mar 14 18:51:09 2012 +# + +# +# General Features +# +# CONFIG_COREBOOT is not set +# CONFIG_XEN is not set +# CONFIG_THREADS is not set +CONFIG_RELOCATE_INIT=y +CONFIG_BOOTMENU=y +CONFIG_BOOTSPLASH=y +CONFIG_BOOTORDER=y + +# +# Hardware support +# +CONFIG_ATA=y +CONFIG_ATA_DMA=y +CONFIG_ATA_PIO32=y +# CONFIG_AHCI is not set +CONFIG_VIRTIO_BLK=y +CONFIG_FLOPPY=y +CONFIG_PS2PORT=y +CONFIG_USB=y +CONFIG_USB_UHCI=y +CONFIG_USB_OHCI=y +CONFIG_USB_EHCI=y +CONFIG_USB_MSC=y +CONFIG_USB_HUB=y +CONFIG_USB_KEYBOARD=y +CONFIG_USB_MOUSE=y +CONFIG_SERIAL=y +CONFIG_LPT=y +CONFIG_USE_SMM=y +# CONFIG_MTRR_INIT is not set + +# +# BIOS interfaces +# +CONFIG_DRIVES=y +CONFIG_CDROM_BOOT=y +CONFIG_CDROM_EMU=y +CONFIG_PCIBIOS=y +CONFIG_APMBIOS=y +CONFIG_PNPBIOS=y +CONFIG_OPTIONROMS=y +CONFIG_OPTIONROMS_DEPLOYED=y +CONFIG_PMM=y +CONFIG_BOOT=y +CONFIG_KEYBOARD=y +CONFIG_KBD_CALL_INT15_4F=y +CONFIG_MOUSE=y +CONFIG_S3_RESUME=y +# CONFIG_DISABLE_A20 is not set + +# +# BIOS Tables +# +CONFIG_PIRTABLE=y +CONFIG_MPTABLE=y +CONFIG_SMBIOS=y +CONFIG_ACPI=y + +# +# Debugging +# +CONFIG_DEBUG_LEVEL=1 +# CONFIG_DEBUG_SERIAL is not set diff --git a/bios/seabios/COPYING b/bios/seabios/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/bios/seabios/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/bios/seabios/COPYING.LESSER b/bios/seabios/COPYING.LESSER new file mode 100644 index 0000000..fc8a5de --- /dev/null +++ b/bios/seabios/COPYING.LESSER @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser 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 +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/bios/seabios/Makefile b/bios/seabios/Makefile new file mode 100644 index 0000000..096b503 --- /dev/null +++ b/bios/seabios/Makefile @@ -0,0 +1,230 @@ +# SeaBIOS build system +# +# Copyright (C) 2008-2010 Kevin O'Connor +# +# This file may be distributed under the terms of the GNU LGPLv3 license. + +# Program version +VERSION=1.6.3-$(shell date +"%Y%m%d_%H%M%S")-$(shell hostname) + +# Output directory +OUT=out/ + +# Source files +SRCBOTH=misc.c stacks.c pmm.c output.c util.c block.c floppy.c ata.c mouse.c \ + kbd.c pci.c serial.c clock.c pic.c cdrom.c ps2port.c smp.c resume.c \ + pnpbios.c pirtable.c vgahooks.c ramdisk.c pcibios.c blockcmd.c \ + usb.c usb-uhci.c usb-ohci.c usb-ehci.c usb-hid.c usb-msc.c \ + virtio-ring.c virtio-pci.c virtio-blk.c apm.c ahci.c +SRC16=$(SRCBOTH) system.c disk.c font.c +SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \ + acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \ + lzmadecode.c bootsplash.c jpeg.c usb-hub.c paravirt.c \ + biostables.c xen.c bmp.c +SRC32SEG=util.c output.c pci.c pcibios.c apm.c stacks.c + +cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \ + /dev/null 2>&1`"; then echo "$(2)"; else echo "$(3)"; fi ;) + +# Default compiler flags +COMMONCFLAGS = -I$(OUT) -Os -MD \ + -Wall -Wno-strict-aliasing -Wold-style-definition \ + $(call cc-option,$(CC),-Wtype-limits,) \ + -m32 -march=i386 -mregparm=3 -mpreferred-stack-boundary=2 \ + -mrtd -minline-all-stringops \ + -freg-struct-return -ffreestanding -fomit-frame-pointer \ + -fno-delete-null-pointer-checks \ + -ffunction-sections -fdata-sections -fno-common +COMMONCFLAGS += $(call cc-option,$(CC),-nopie,) +COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector,) +COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,) + +CFLAGS32FLAT = $(COMMONCFLAGS) -g -DMODE16=0 -DMODESEGMENT=0 +CFLAGSSEG = $(COMMONCFLAGS) -DMODESEGMENT=1 -fno-defer-pop \ + $(call cc-option,$(CC),-fno-jump-tables,-DMANUAL_NO_JUMP_TABLE) \ + $(call cc-option,$(CC),-fno-tree-switch-conversion,) +CFLAGS32SEG = $(CFLAGSSEG) -DMODE16=0 -g +CFLAGS16INC = $(CFLAGSSEG) -DMODE16=1 \ + $(call cc-option,$(CC),--param large-stack-frame=4,-fno-inline) +CFLAGS16 = $(CFLAGS16INC) -g + +all: $(OUT) $(OUT)bios.bin + +# Run with "make V=1" to see the actual compile commands +ifdef V +Q= +else +Q=@ +MAKEFLAGS += --no-print-directory +endif + +OBJCOPY=objcopy +OBJDUMP=objdump +STRIP=strip + +.PHONY : all clean distclean FORCE + +vpath %.c src vgasrc +vpath %.S src vgasrc + +################ Build rules + +# Verify the gcc configuration and test if -fwhole-program works. +TESTGCC:=$(shell CC="$(CC)" LD="$(LD)" tools/test-gcc.sh) +ifeq "$(TESTGCC)" "-1" +$(error "Please upgrade GCC and/or binutils") +endif + +ifndef COMPSTRAT +COMPSTRAT=$(TESTGCC) +endif + +# Do a whole file compile - three methods are supported. +ifeq "$(COMPSTRAT)" "1" +# First method - use -fwhole-program without -combine. +define whole-compile +@echo " Compiling whole program $3" +$(Q)printf '$(foreach i,$2,#include "../$i"\n)' > $3.tmp.c +$(Q)$(CC) $1 -fwhole-program -DWHOLE_PROGRAM -c $3.tmp.c -o $3 +endef +else +ifeq "$(COMPSTRAT)" "2" +# Second menthod - don't use -fwhole-program at all. +define whole-compile +@echo " Compiling whole program $3" +$(Q)printf '$(foreach i,$2,#include "../$i"\n)' > $3.tmp.c +$(Q)$(CC) $1 -c $3.tmp.c -o $3 +endef +else +# Third (and preferred) method - use -fwhole-program with -combine +define whole-compile +@echo " Compiling whole program $3" +$(Q)$(CC) $1 -fwhole-program -DWHOLE_PROGRAM -combine -c $2 -o $3 +endef +endif +endif + +%.strip.o: %.o + @echo " Stripping $@" + $(Q)$(STRIP) $< -o $@ + +$(OUT)%.s: %.c + @echo " Compiling to assembler $@" + $(Q)$(CC) $(CFLAGS16INC) -S -c $< -o $@ + +$(OUT)%.lds: %.lds.S + @echo " Precompiling $@" + $(Q)$(CPP) -P -D__ASSEMBLY__ $< -o $@ + +$(OUT)asm-offsets.s: $(OUT)autoconf.h + +$(OUT)asm-offsets.h: $(OUT)asm-offsets.s + @echo " Generating offset file $@" + $(Q)./tools/gen-offsets.sh $< $@ + + +$(OUT)ccode.16.s: $(OUT)autoconf.h ; $(call whole-compile, $(CFLAGS16) -S, $(addprefix src/, $(SRC16)),$@) + +$(OUT)code32seg.o: $(OUT)autoconf.h ; $(call whole-compile, $(CFLAGS32SEG), $(addprefix src/, $(SRC32SEG)),$@) + +$(OUT)ccode32flat.o: $(OUT)autoconf.h ; $(call whole-compile, $(CFLAGS32FLAT), $(addprefix src/, $(SRC32FLAT)),$@) + +$(OUT)code16.o: romlayout.S $(OUT)ccode.16.s $(OUT)asm-offsets.h + @echo " Compiling (16bit) $@" + $(Q)$(CC) $(CFLAGS16INC) -c -D__ASSEMBLY__ $< -o $@ + +$(OUT)romlayout16.lds: $(OUT)ccode32flat.o $(OUT)code32seg.o $(OUT)code16.o tools/layoutrom.py + @echo " Building ld scripts (version \"$(VERSION)\")" + $(Q)echo 'const char VERSION[] = "$(VERSION)";' > $(OUT)version.c + $(Q)$(CC) $(CFLAGS32FLAT) -c $(OUT)version.c -o $(OUT)version.o + $(Q)$(LD) -melf_i386 -r $(OUT)ccode32flat.o $(OUT)version.o -o $(OUT)code32flat.o + $(Q)$(OBJDUMP) -thr $(OUT)code32flat.o > $(OUT)code32flat.o.objdump + $(Q)$(OBJDUMP) -thr $(OUT)code32seg.o > $(OUT)code32seg.o.objdump + $(Q)$(OBJDUMP) -thr $(OUT)code16.o > $(OUT)code16.o.objdump + $(Q)./tools/layoutrom.py $(OUT)code16.o.objdump $(OUT)code32seg.o.objdump $(OUT)code32flat.o.objdump $(OUT)romlayout16.lds $(OUT)romlayout32seg.lds $(OUT)romlayout32flat.lds + +# These are actually built by tools/layoutrom.py above, but by pulling them +# into an extra rule we prevent make -j from spawning layoutrom.py 4 times. +$(OUT)romlayout32seg.lds $(OUT)romlayout32flat.lds $(OUT)code32flat.o: $(OUT)romlayout16.lds + +$(OUT)rom16.o: $(OUT)code16.o $(OUT)romlayout16.lds + @echo " Linking $@" + $(Q)$(LD) -T $(OUT)romlayout16.lds $< -o $@ + +$(OUT)rom32seg.o: $(OUT)code32seg.o $(OUT)romlayout32seg.lds + @echo " Linking $@" + $(Q)$(LD) -T $(OUT)romlayout32seg.lds $< -o $@ + +$(OUT)rom.o: $(OUT)rom16.strip.o $(OUT)rom32seg.strip.o $(OUT)code32flat.o $(OUT)romlayout32flat.lds + @echo " Linking $@" + $(Q)$(LD) -T $(OUT)romlayout32flat.lds $(OUT)rom16.strip.o $(OUT)rom32seg.strip.o $(OUT)code32flat.o -o $@ + +$(OUT)bios.bin.elf $(OUT)bios.bin: $(OUT)rom.o tools/checkrom.py + @echo " Prepping $@" + $(Q)$(OBJDUMP) -thr $< > $<.objdump + $(Q)$(OBJCOPY) -O binary $< $(OUT)bios.bin.raw + $(Q)./tools/checkrom.py $<.objdump $(OUT)bios.bin.raw $(OUT)bios.bin + $(Q)$(STRIP) -R .comment $< -o $(OUT)bios.bin.elf + + +################ VGA build rules + +# VGA src files +SRCVGA=src/output.c src/util.c vgasrc/vga.c vgasrc/vgafb.c vgasrc/vgaio.c \ + vgasrc/vgatables.c vgasrc/vgafonts.c vgasrc/clext.c + +$(OUT)vgaccode.16.s: $(OUT)autoconf.h ; $(call whole-compile, $(CFLAGS16) -S -Isrc, $(SRCVGA),$@) + +$(OUT)vgalayout16.o: vgaentry.S $(OUT)vgaccode.16.s $(OUT)asm-offsets.h + @echo " Compiling (16bit) $@" + $(Q)$(CC) $(CFLAGS16INC) -c -D__ASSEMBLY__ -Isrc $< -o $@ + +$(OUT)vgarom.o: $(OUT)vgalayout16.o $(OUT)vgalayout.lds + @echo " Linking $@" + $(Q)$(LD) --gc-sections -T $(OUT)vgalayout.lds $(OUT)vgalayout16.o -o $@ + +$(OUT)vgabios.bin.raw: $(OUT)vgarom.o + @echo " Extracting binary $@" + $(Q)$(OBJCOPY) -O binary $< $@ + +$(OUT)vgabios.bin: $(OUT)vgabios.bin.raw tools/buildrom.py + @echo " Finalizing rom $@" + $(Q)./tools/buildrom.py $< $@ + +####### dsdt build rules +src/%.hex: src/%.dsl + @echo "Compiling DSDT" + $(Q)cpp -P $< > $(OUT)$*.dsl.i + $(Q)iasl -tc -p $(OUT)$* $(OUT)$*.dsl.i + $(Q)cp $(OUT)$*.hex $@ + +$(OUT)ccode32flat.o: src/acpi-dsdt.hex + +####### Kconfig rules +export HOSTCC := $(CC) +export CONFIG_SHELL := sh +export KCONFIG_AUTOHEADER := autoconf.h +export KCONFIG_CONFIG := $(CURDIR)/.config + +$(OUT)autoconf.h : $(KCONFIG_CONFIG) + $(Q)$(MAKE) silentoldconfig + +$(KCONFIG_CONFIG): + $(Q)$(MAKE) defconfig + +%onfig: + $(Q)mkdir -p $(OUT)/tools/kconfig/lxdialog + $(Q)mkdir -p $(OUT)/include/config + $(Q)$(MAKE) -C $(OUT) -f $(CURDIR)/tools/kconfig/Makefile srctree=$(CURDIR) src=tools/kconfig obj=tools/kconfig Q=$(Q) Kconfig=$(CURDIR)/src/Kconfig $@ + +####### Generic rules +clean: + $(Q)rm -rf $(OUT) + +distclean: clean + $(Q)rm -f .config .config.old + +$(OUT): + $(Q)mkdir $@ + +-include $(OUT)*.d diff --git a/bios/seabios/README b/bios/seabios/README new file mode 100644 index 0000000..1f40433 --- /dev/null +++ b/bios/seabios/README @@ -0,0 +1,173 @@ +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/bios.bin" contains the processed bios image. + + +Testing of images: + +To test the bios under bochs, one will need to instruct bochs to use +the new bios image. Use the 'romimage' option - for example: + +bochs -q 'floppya: 1_44=myfdimage.img' 'romimage: file=out/bios.bin' + +To test under qemu, one will need to create a directory with all the +bios images and then overwrite the main bios image. For example: + +cp /usr/share/qemu/*.bin mybiosdir/ +cp out/bios.bin mybiosdir/ + +Once this is setup, one can instruct qemu to use the newly created +directory for rom images. For example: + +qemu -L mybiosdir/ -fda myfdimage.img + + +Overview of files: + +The src/ directory contains the bios source code. Several of the +files are compiled twice - once for 16bit mode and once for 32bit +mode. (The build system will remove code that is not needed for a +particular 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/ccode.16.s). +The gcc "-fwhole-program" and "-ffunction-sections -fdata-sections" +options are used to optimize the process so that gcc can efficiently +compile and discard unneeded code. (In the code, one can use the +macros 'VISIBLE16' and 'VISIBLE32FLAT' to instruct a symbol to be +outputted in 16bit and 32bit mode respectively.) + +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 generate valid 16 bit code. + +The post code (post.c) is entered, via the function handle_post(), in +32bit mode. The 16bit post vector (in romlayout.S) transitions the +cpu into 32 bit mode before calling the post.c code. + +In the last step of compilation, the 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 memory at 0xe0000-0xfffff. + + +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 (or one of the helper macros described +below). 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. Any other access requires altering one +of the other segment registers (usually ES) and then accessing the +variable via that segment register. + +There are three low-level ways to access a remote variable: +GET/SET_VAR, GET/SET_FARVAR, and GET/SET_FLATPTR. The first set takes +an explicit segment descriptor (eg, "CS") and offset. The second set +will take a segment id and offset, set ES to the segment id, and then +make the access via the ES segment. The last method is similar to the +second, except it takes a pointer that would be valid in 32-bit flat +mode instead of a segment/offset pair. + +Most BIOS variables are stored in global variables, the "BDA", or +"EBDA" memory areas. Because this is common, three sets of helper +macros (GET/SET_GLOBAL, GET/SET_BDA, and GET/SET_EBDA) are available +to simplify these accesses. + +Global variables defined in the C code can be read in 16bit mode if +the variable declaration is marked with VAR16, VAR16VISIBLE, +VAR16EXPORT, or VAR16FIXED. The GET_GLOBAL macro will then allow read +access to the variable. Global variables are stored in the 0xf000 +segment, and their values are persistent across soft resets. Because +the f-segment is marked read-only during run-time, the 16bit code is +not permitted to change the value of 16bit variables (use of the +SET_GLOBAL macro from 16bit mode will cause a link error). Code +running in 32bit mode can not access variables with VAR16, but can +access variables marked with VAR16VISIBLE, VAR16EXPORT, VAR16FIXED, or +with no marking at all. The 32bit code can use the GET/SET_GLOBAL +macros, but they are not required. + + +GCC 16 bit stack limitations: + +Another limitation of gcc is its use of 32-bit temporaries. Gcc will +allocate 32-bits of space for every variable - even if that variable +is only defined as a 'u8' or 'u16'. If one is not careful, using too +much stack space can break old DOS applications. + +There does not appear to be explicit documentation on the minimum +stack space available for bios calls. However, Freedos has been +observed to call into the bios with less than 150 bytes available. + +Note that the post code and boot code (irq 18/19) do not have a stack +limitation because the entry points for these functions transition the +cpu to 32bit mode and reset the stack to a known state. Only the +general purpose 16-bit service entry points are affected. + +There are some ways to reduce stack usage: making sure functions are +tail-recursive often helps, reducing the number of parameters passed +to functions often helps, sometimes reordering variable declarations +helps, inlining of functions can sometimes help, and passing of packed +structures can also help. It is also possible to transition to/from +an extra stack stored in the EBDA using the stack_hop helper function. + +Some useful stats: the overhead for the entry to a bios handler that +takes a 'struct bregs' is 42 bytes of stack space (6 bytes from +interrupt insn, 32 bytes to store registers, and 4 bytes for call +insn). An entry to an ISR handler without args takes 30 bytes (6 + 20 ++ 4). + + +Debugging the bios: + +The bios will output information messages to a special debug port. +Under qemu, one can view these messages by adding '-chardev +stdio,id=seabios -device isa-debugcon,iobase=0x402,chardev=seabios' to +the qemu command line. Once this is done, one should see status +messages on the console. + +The gdb-server mechanism of qemu is also useful. One can use gdb with +qemu to debug system images. To use this, add '-s -S' to the qemu +command line. For example: + +qemu -L mybiosdir/ -fda myfdimage.img -s -S + +Then, in another session, run gdb with either out/rom16.o (to debug +bios 16bit code) or out/rom32.o (to debug bios 32bit code). For +example: + +gdb out/rom16.o + +Once in gdb, use the command "target remote localhost:1234" to have +gdb connect to qemu. See the qemu documentation for more information +on using gdb and qemu in this mode. Note that gdb seems to get +breakpoints confused when the cpu is in 16-bit real mode. This makes +stepping through the program difficult (though 'step instruction' +still works). Also, one may need to set 16bit break points at both +the cpu address and memory address (eg, break *0x1234 ; break +*0xf1234). diff --git a/bios/seabios/README.palacios b/bios/seabios/README.palacios new file mode 100644 index 0000000..06a4ca6 --- /dev/null +++ b/bios/seabios/README.palacios @@ -0,0 +1 @@ +cp palacios_config .config and then make diff --git a/bios/seabios/TODO b/bios/seabios/TODO new file mode 100644 index 0000000..23f26c0 --- /dev/null +++ b/bios/seabios/TODO @@ -0,0 +1,21 @@ +Review changes committed to coreboot, virtualbox, qemu, kvm, and bochs +cvs tip. + * bochs cvs (20100104): + -- changes synched + * coreboot (r3348): (bochs 20060708) + -- no noteworthy enhancements + * qemu - now uses SeaBIOS + * kvm - now uses SeaBIOS + * virtualbox (r13560): (bochs 20061231) + -- lots of mouse changes, logo, scsi/etherboot hooks, + floppy data rate?, int19 calls post + +The __call16 code does a long jump to the interrupt trampolines - this +is unnecessary. + +Support PCIv3 roms? Add support for PCI "configuration code" +extensions? + +Possibly add option to eliminate tsc based delays on emulators. + +Possibly support sending debug information over EHCI debug port. diff --git a/bios/seabios/palacios_config b/bios/seabios/palacios_config new file mode 100644 index 0000000..992484a --- /dev/null +++ b/bios/seabios/palacios_config @@ -0,0 +1,72 @@ +# +# Automatically generated make config: don't edit +# SeaBIOS Configuration +# Wed Mar 14 18:51:09 2012 +# + +# +# General Features +# +# CONFIG_COREBOOT is not set +# CONFIG_XEN is not set +# CONFIG_THREADS is not set +CONFIG_RELOCATE_INIT=y +CONFIG_BOOTMENU=y +CONFIG_BOOTSPLASH=y +CONFIG_BOOTORDER=y + +# +# Hardware support +# +CONFIG_ATA=y +CONFIG_ATA_DMA=y +CONFIG_ATA_PIO32=y +# CONFIG_AHCI is not set +CONFIG_VIRTIO_BLK=y +CONFIG_FLOPPY=y +CONFIG_PS2PORT=y +CONFIG_USB=y +CONFIG_USB_UHCI=y +CONFIG_USB_OHCI=y +CONFIG_USB_EHCI=y +CONFIG_USB_MSC=y +CONFIG_USB_HUB=y +CONFIG_USB_KEYBOARD=y +CONFIG_USB_MOUSE=y +CONFIG_SERIAL=y +CONFIG_LPT=y +CONFIG_USE_SMM=y +# CONFIG_MTRR_INIT is not set + +# +# BIOS interfaces +# +CONFIG_DRIVES=y +CONFIG_CDROM_BOOT=y +CONFIG_CDROM_EMU=y +CONFIG_PCIBIOS=y +CONFIG_APMBIOS=y +CONFIG_PNPBIOS=y +CONFIG_OPTIONROMS=y +CONFIG_OPTIONROMS_DEPLOYED=y +CONFIG_PMM=y +CONFIG_BOOT=y +CONFIG_KEYBOARD=y +CONFIG_KBD_CALL_INT15_4F=y +CONFIG_MOUSE=y +CONFIG_S3_RESUME=y +# CONFIG_DISABLE_A20 is not set + +# +# BIOS Tables +# +CONFIG_PIRTABLE=y +CONFIG_MPTABLE=y +CONFIG_SMBIOS=y +CONFIG_ACPI=y + +# +# Debugging +# +CONFIG_DEBUG_LEVEL=1 +# CONFIG_DEBUG_SERIAL is not set diff --git a/bios/seabios/palacios_fixes.patch b/bios/seabios/palacios_fixes.patch new file mode 100644 index 0000000..427c4e8 --- /dev/null +++ b/bios/seabios/palacios_fixes.patch @@ -0,0 +1,147 @@ +From 83f115d2f7f26dddcbbffe89aa8a7a97b28a6228 Mon Sep 17 00:00:00 2001 +From: Alexander Kudryavtsev +Date: Mon, 12 Mar 2012 13:07:07 +0400 +Subject: [PATCH] Fixes needed to launch SEABIOS inside Palacios's VM: 1. + Allow to build ACPI tables without PIIX4 PM device 2. + Disable HPET table generation 3. Do not perform PCI setup + since it breaks Palacios 4. Do not initialize AP cores + since it breaks Palacios 5. Fix SRAT generation - do not + cut PCI hole since it is already cut off by Palacios + +--- + src/acpi.c | 44 +++++++++++++++++++++++++++++--------------- + src/pciinit.c | 2 +- + src/smp.c | 5 ++++- + 3 files changed, 34 insertions(+), 17 deletions(-) + +diff --git a/src/acpi.c b/src/acpi.c +index 3d8b7c8..7d50990 100644 +--- a/src/acpi.c ++++ b/src/acpi.c +@@ -262,18 +262,32 @@ build_fadt(struct pci_device *pci) + fadt->dsdt = cpu_to_le32((u32)dsdt); + fadt->model = 1; + fadt->reserved1 = 0; +- int pm_sci_int = pci_config_readb(pci->bdf, PCI_INTERRUPT_LINE); ++ int pm_sci_int; ++ if (pci) ++ pci_config_readb(pci->bdf, PCI_INTERRUPT_LINE); ++ else ++ pm_sci_int = 0; + fadt->sci_int = cpu_to_le16(pm_sci_int); +- fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD); +- fadt->pm1a_evt_blk = cpu_to_le32(PORT_ACPI_PM_BASE); +- fadt->pm1a_cnt_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x04); +- fadt->pm_tmr_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x08); +- fadt->pm1_evt_len = 4; +- fadt->pm1_cnt_len = 2; +- fadt->pm_tmr_len = 4; ++ if (pci) { ++ fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD); ++ fadt->pm1a_evt_blk = cpu_to_le32(PORT_ACPI_PM_BASE); ++ fadt->pm1a_cnt_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x04); ++ fadt->pm_tmr_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x08); ++ fadt->pm1_evt_len = 4; ++ fadt->pm1_cnt_len = 2; ++ fadt->pm_tmr_len = 4; ++ pci_init_device(fadt_init_tbl, pci, fadt); ++ } else { ++ fadt->smi_cmd = 0; ++ fadt->pm1a_evt_blk = 0; ++ fadt->pm1a_cnt_blk = 0; ++ fadt->pm_tmr_blk = 0; ++ fadt->pm1_evt_len = 0; ++ fadt->pm1_cnt_len = 0; ++ fadt->pm_tmr_len = 0; ++ } + fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported + fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported +- pci_init_device(fadt_init_tbl, pci, fadt); + /* WBINVD + PROC_C1 + SLP_BUTTON + FIX_RTC + RTC_S4 */ + fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 5) | (1 << 6) | (1 << 7)); + +@@ -516,6 +530,7 @@ build_srat(void) + if (nb_numa_nodes == 0) + return NULL; + ++ + u64 *numadata = malloc_tmphigh(sizeof(u64) * (MaxCountCPUs + nb_numa_nodes)); + if (!numadata) { + warn_noalloc(); +@@ -577,7 +592,7 @@ build_srat(void) + next_base = mem_base + mem_len; + + /* Cut out the PCI hole */ +- if (mem_base <= RamSize && next_base > RamSize) { ++ /*if (mem_base <= RamSize && next_base > RamSize) { + mem_len -= next_base - RamSize; + if (mem_len > 0) { + acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1); +@@ -587,7 +602,7 @@ build_srat(void) + mem_base = 1ULL << 32; + mem_len = next_base - RamSize; + next_base += (1ULL << 32) - RamSize; +- } ++ }*/ + acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1); + numamem++; + slots++; +@@ -623,9 +638,7 @@ acpi_bios_init(void) + + // This code is hardcoded for PIIX4 Power Management device. + struct pci_device *pci = pci_find_init_device(acpi_find_tbl, NULL); +- if (!pci) +- // Device not found +- return; ++ // If no PIIX4 is found we will not build certain structures and init it. + + // Build ACPI tables + u32 tables[MAX_ACPI_TABLES], tbl_idx = 0; +@@ -640,7 +653,8 @@ acpi_bios_init(void) + ACPI_INIT_TABLE(build_fadt(pci)); + ACPI_INIT_TABLE(build_ssdt()); + ACPI_INIT_TABLE(build_madt()); +- ACPI_INIT_TABLE(build_hpet()); ++ if(pci) ++ ACPI_INIT_TABLE(build_hpet()); + ACPI_INIT_TABLE(build_srat()); + + u16 i, external_tables = qemu_cfg_acpi_additional_tables(); +diff --git a/src/pciinit.c b/src/pciinit.c +index 0d8758e..ef8ccda 100644 +--- a/src/pciinit.c ++++ b/src/pciinit.c +@@ -575,7 +575,7 @@ static int pci_bios_init_root_regions(u32 start, u32 end) + void + pci_setup(void) + { +- if (CONFIG_COREBOOT || usingXen()) { ++ if (1 || CONFIG_COREBOOT || usingXen()) { + // PCI setup already done by coreboot or Xen - just do probe. + pci_probe_devices(); + return; +diff --git a/src/smp.c b/src/smp.c +index 8c077a1..21e7437 100644 +--- a/src/smp.c ++++ b/src/smp.c +@@ -81,7 +81,7 @@ smp_probe(void) + MaxCountCPUs = 1; + return; + } +- ++#if 0 + // Init the counter. + writel(&CountCPUs, 1); + +@@ -121,6 +121,9 @@ smp_probe(void) + + // Restore memory. + *(u64*)BUILD_AP_BOOT_ADDR = old; ++#endif + ++ CountCPUs = inb_cmos(CMOS_BIOS_SMP_COUNT) + 1; // Fix for Palacios + + MaxCountCPUs = qemu_cfg_get_max_cpus(); + if (!MaxCountCPUs || MaxCountCPUs < CountCPUs) +-- +1.7.5.4 diff --git a/bios/seabios/src/Kconfig b/bios/seabios/src/Kconfig new file mode 100644 index 0000000..338f51a --- /dev/null +++ b/bios/seabios/src/Kconfig @@ -0,0 +1,349 @@ +# Kconfig SeaBIOS configuration + +mainmenu "SeaBIOS Configuration" + +menu "General Features" + + config COREBOOT + bool "Build for coreboot" + default n + help + Configure as a coreboot payload. + + config XEN + depends on !COREBOOT + bool "Build for Xen HVM" + default n + help + Configure to be used by xen hvmloader, for a HVM guest. + + config THREADS + bool "Parallelize hardware init" + default y + help + Support running hardware initialization in parallel. + config THREAD_OPTIONROMS + depends on THREADS + bool "Hardware init during option ROM execution" + default n + help + Allow hardware init to run in parallel with optionrom execution. + + This can reduce boot time, but can cause some timing + variations during option ROM code execution. It is not + known if all option ROMs will behave properly with this + option. + + config RELOCATE_INIT + bool "Copy init code to high memory" + default y + help + Support relocating the one time initialization code to high memory. + + config BOOTMENU + depends on BOOT + bool "Bootmenu" + default y + help + Support an interactive boot menu at end of post. + config BOOTSPLASH + depends on BOOTMENU + bool "Graphical boot splash screen" + default y + help + Support showing a graphical boot splash screen. + config BOOTORDER + depends on BOOT + bool "Boot ordering" + default y + help + Support controlling of the boot order via the fw_cfg/CBFS + "bootorder" file. + + config COREBOOT_FLASH + depends on COREBOOT + bool "coreboot CBFS support" + default y + help + Support searching coreboot flash format. + config LZMA + depends on COREBOOT_FLASH + bool "CBFS lzma support" + default y + help + Support CBFS files compressed using the lzma decompression + algorighm. + config FLASH_FLOPPY + depends on COREBOOT_FLASH + bool "Floppy images in CBFS" + default y + help + Support floppy images in coreboot flash. + +endmenu + +menu "Hardware support" + config ATA + depends on DRIVES + bool "ATA controllers" + default y + help + Support for IDE disk code. + config ATA_DMA + depends on ATA + bool "ATA DMA" + default n + help + Detect and try to use ATA bus mastering DMA controllers. + config ATA_PIO32 + depends on ATA + bool "ATA 32bit PIO" + default n + help + Use 32bit PIO accesses on ATA (minor optimization on PCI transfers). + config AHCI + depends on DRIVES + bool "AHCI controllers" + default y + help + Support for AHCI disk code. + config VIRTIO_BLK + depends on DRIVES && !COREBOOT + bool "VirtIO controllers" + default y + help + Support boot from virtio storage. + config FLOPPY + depends on DRIVES + bool "Floppy controller" + default y + help + Support floppy drive access. + + config PS2PORT + depends on KEYBOARD || MOUSE + bool "PS/2 port" + default y + help + Support PS2 ports (keyboard and mouse). + + config USB + bool "USB" + default y + help + Support USB devices. + config USB_UHCI + depends on USB + bool "USB UHCI controllers" + default y + help + Support USB UHCI controllers. + config USB_OHCI + depends on USB + bool "USB OHCI controllers" + default y + help + Support USB OHCI controllers. + config USB_EHCI + depends on USB + bool "USB EHCI controllers" + default y + help + Support USB EHCI controllers. + config USB_MSC + depends on USB && DRIVES + bool "USB drives" + default y + help + Support USB disks. + config USB_HUB + depends on USB + bool "USB hubs" + default y + help + Support USB hubs. + config USB_KEYBOARD + depends on USB && KEYBOARD + bool "USB keyboards" + default y + help + Support USB keyboards. + config USB_MOUSE + depends on USB && MOUSE + bool "USB mice" + default y + help + Support USB mice. + + config SERIAL + bool "Serial port" + default y + help + Support serial ports. This also enables int 14 serial port calls. + config LPT + bool "Parallel port" + default y + help + Support parallel ports. This also enables int 17 parallel port calls. + + config USE_SMM + depends on !COREBOOT + bool "System Management Mode (SMM)" + default y + help + Support System Management Mode (on emulators). + config MTRR_INIT + depends on !COREBOOT + bool "Initialize MTRRs" + default y + help + Initialize the Memory Type Range Registers (on emulators). +endmenu + +menu "BIOS interfaces" + config DRIVES + bool "Drive interface" + default y + help + Support int13 disk/floppy drive functions. + + config CDROM_BOOT + depends on DRIVES + bool "DVD/CDROM booting" + default y + help + Support for booting from a CD. (El Torito spec support.) + config CDROM_EMU + depends on CDROM_BOOT + bool "DVD/CDROM boot drive emulation" + default y + help + Support bootable CDROMs that emulate a floppy/harddrive. + + config PCIBIOS + bool "PCIBIOS interface" + default y + help + Support int 1a/b1 PCI BIOS calls. + config APMBIOS + bool "APM interface" + default y + help + Support int 15/53 APM BIOS calls. + config PNPBIOS + bool "PnP BIOS interface" + default y + help + Support PnP BIOS entry point. + config OPTIONROMS + bool "Option ROMS" + default y + help + Support finding and running option roms during POST. + config OPTIONROMS_DEPLOYED + depends on OPTIONROMS + bool "Option roms are already at 0xc0000-0xf0000" + default n + help + Select this if option ROMs are already copied to + 0xc0000-0xf0000. This must only be selected when using + Bochs or QEMU versions older than 0.12. + config PMM + depends on OPTIONROMS + bool "PMM interface" + default y + help + Support Post Memory Manager (PMM) entry point. + config BOOT + bool "Boot interface" + default y + help + Support int 19/18 system bootup support. + config KEYBOARD + bool "Keyboard interface" + default y + help + Support int 16 keyboard calls. + config KBD_CALL_INT15_4F + depends on KEYBOARD + bool "Keyboard hook interface" + default y + help + Support calling int155f on each keyboard event. + config MOUSE + bool "Mouse interface" + default y + help + Support for int15c2 mouse calls. + + config S3_RESUME + bool "S3 resume" + default y + help + Support S3 resume handler. + + config VGAHOOKS + depends on COREBOOT + bool "Hardware specific VGA helpers" + default y + help + Support int 155f BIOS callbacks specific to some Intel and + VIA on-board vga devices. + + config DISABLE_A20 + bool "Disable A20" + default n + help + Disable A20 on 16bit boot. +endmenu + +menu "BIOS Tables" + config PIRTABLE + depends on !COREBOOT + bool "PIR table" + default y + help + Support generation of a PIR table in 0xf000 segment. + config MPTABLE + depends on !COREBOOT + bool "MPTable" + default y + help + Support generation of MPTable. + config SMBIOS + bool "SMBIOS" + default y + help + Support generation of SM BIOS tables. This is also + sometimes called DMI. + config ACPI + depends on !COREBOOT + bool "ACPI" + default y + help + Support generation of ACPI tables. +endmenu + +menu "Debugging" + config DEBUG_LEVEL + int "Debug level" + default 1 + help + Control how verbose debug output is. The higher the + number, the more verbose SeaBIOS will be. + + Set to zero to disable debugging. + + config DEBUG_SERIAL + depends on DEBUG_LEVEL != 0 + bool "Serial port debugging" + default n + help + Send debugging information to serial port. + config DEBUG_SERIAL_PORT + depends on DEBUG_SERIAL + hex "Serial port base address" + default 0x3f8 + help + Base port for serial - generally 0x3f8, 0x2f8, 0x3e8, or 0x2e8. +endmenu diff --git a/bios/seabios/src/acpi-dsdt.dsl b/bios/seabios/src/acpi-dsdt.dsl new file mode 100644 index 0000000..08412e2 --- /dev/null +++ b/bios/seabios/src/acpi-dsdt.dsl @@ -0,0 +1,934 @@ +/* + * Bochs/QEMU ACPI DSDT ASL definition + * + * Copyright (c) 2006 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +DefinitionBlock ( + "acpi-dsdt.aml", // Output Filename + "DSDT", // Signature + 0x01, // DSDT Compliance Revision + "BXPC", // OEMID + "BXDSDT", // TABLE ID + 0x1 // OEM Revision + ) +{ + Scope (\) + { + /* Debug Output */ + OperationRegion (DBG, SystemIO, 0x0402, 0x01) + Field (DBG, ByteAcc, NoLock, Preserve) + { + DBGB, 8, + } + + /* Debug method - use this method to send output to the QEMU + * BIOS debug port. This method handles strings, integers, + * and buffers. For example: DBUG("abc") DBUG(0x123) */ + Method(DBUG, 1) { + ToHexString(Arg0, Local0) + ToBuffer(Local0, Local0) + Subtract(SizeOf(Local0), 1, Local1) + Store(Zero, Local2) + While (LLess(Local2, Local1)) { + Store(DerefOf(Index(Local0, Local2)), DBGB) + Increment(Local2) + } + Store(0x0A, DBGB) + } + } + + /* PCI Bus definition */ + Scope(\_SB) { + Device(PCI0) { + Name (_HID, EisaId ("PNP0A03")) + Name (_ADR, 0x00) + Name (_UID, 1) + Name(_PRT, Package() { + /* PCI IRQ routing table, example from ACPI 2.0a specification, + section 6.2.8.1 */ + /* Note: we provide the same info as the PCI routing + table of the Bochs BIOS */ +#define prt_slot(nr, lnk0, lnk1, lnk2, lnk3) \ + Package() { nr##ffff, 0, lnk0, 0 }, \ + Package() { nr##ffff, 1, lnk1, 0 }, \ + Package() { nr##ffff, 2, lnk2, 0 }, \ + Package() { nr##ffff, 3, lnk3, 0 } + +#define prt_slot0(nr) prt_slot(nr, LNKD, LNKA, LNKB, LNKC) +#define prt_slot1(nr) prt_slot(nr, LNKA, LNKB, LNKC, LNKD) +#define prt_slot2(nr) prt_slot(nr, LNKB, LNKC, LNKD, LNKA) +#define prt_slot3(nr) prt_slot(nr, LNKC, LNKD, LNKA, LNKB) + prt_slot0(0x0000), + /* Device 1 is power mgmt device, and can only use irq 9 */ + Package() { 0x0001ffff, 0, LNKS, 0 }, + Package() { 0x0001ffff, 1, LNKB, 0 }, + Package() { 0x0001ffff, 2, LNKC, 0 }, + Package() { 0x0001ffff, 3, LNKD, 0 }, + prt_slot2(0x0002), + prt_slot3(0x0003), + prt_slot0(0x0004), + prt_slot1(0x0005), + prt_slot2(0x0006), + prt_slot3(0x0007), + prt_slot0(0x0008), + prt_slot1(0x0009), + prt_slot2(0x000a), + prt_slot3(0x000b), + prt_slot0(0x000c), + prt_slot1(0x000d), + prt_slot2(0x000e), + prt_slot3(0x000f), + prt_slot0(0x0010), + prt_slot1(0x0011), + prt_slot2(0x0012), + prt_slot3(0x0013), + prt_slot0(0x0014), + prt_slot1(0x0015), + prt_slot2(0x0016), + prt_slot3(0x0017), + prt_slot0(0x0018), + prt_slot1(0x0019), + prt_slot2(0x001a), + prt_slot3(0x001b), + prt_slot0(0x001c), + prt_slot1(0x001d), + prt_slot2(0x001e), + prt_slot3(0x001f), + }) + + OperationRegion(PCST, SystemIO, 0xae00, 0x08) + Field (PCST, DWordAcc, NoLock, WriteAsZeros) + { + PCIU, 32, + PCID, 32, + } + + OperationRegion(SEJ, SystemIO, 0xae08, 0x04) + Field (SEJ, DWordAcc, NoLock, WriteAsZeros) + { + B0EJ, 32, + } + + OperationRegion(RMVC, SystemIO, 0xae0c, 0x04) + Field(RMVC, DWordAcc, NoLock, WriteAsZeros) + { + PCRM, 32, + } + +#define hotplug_slot(name, nr) \ + Device (S##name) { \ + Name (_ADR, nr##0000) \ + Method (_EJ0,1) { \ + Store(ShiftLeft(1, nr), B0EJ) \ + Return (0x0) \ + } \ + Name (_SUN, name) \ + } + + hotplug_slot(1, 0x0001) + hotplug_slot(2, 0x0002) + hotplug_slot(3, 0x0003) + hotplug_slot(4, 0x0004) + hotplug_slot(5, 0x0005) + hotplug_slot(6, 0x0006) + hotplug_slot(7, 0x0007) + hotplug_slot(8, 0x0008) + hotplug_slot(9, 0x0009) + hotplug_slot(10, 0x000a) + hotplug_slot(11, 0x000b) + hotplug_slot(12, 0x000c) + hotplug_slot(13, 0x000d) + hotplug_slot(14, 0x000e) + hotplug_slot(15, 0x000f) + hotplug_slot(16, 0x0010) + hotplug_slot(17, 0x0011) + hotplug_slot(18, 0x0012) + hotplug_slot(19, 0x0013) + hotplug_slot(20, 0x0014) + hotplug_slot(21, 0x0015) + hotplug_slot(22, 0x0016) + hotplug_slot(23, 0x0017) + hotplug_slot(24, 0x0018) + hotplug_slot(25, 0x0019) + hotplug_slot(26, 0x001a) + hotplug_slot(27, 0x001b) + hotplug_slot(28, 0x001c) + hotplug_slot(29, 0x001d) + hotplug_slot(30, 0x001e) + hotplug_slot(31, 0x001f) + + Name (_CRS, ResourceTemplate () + { + WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode, + 0x0000, // Address Space Granularity + 0x0000, // Address Range Minimum + 0x00FF, // Address Range Maximum + 0x0000, // Address Translation Offset + 0x0100, // Address Length + ,, ) + IO (Decode16, + 0x0CF8, // Address Range Minimum + 0x0CF8, // Address Range Maximum + 0x01, // Address Alignment + 0x08, // Address Length + ) + WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000, // Address Space Granularity + 0x0000, // Address Range Minimum + 0x0CF7, // Address Range Maximum + 0x0000, // Address Translation Offset + 0x0CF8, // Address Length + ,, , TypeStatic) + WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000, // Address Space Granularity + 0x0D00, // Address Range Minimum + 0xFFFF, // Address Range Maximum + 0x0000, // Address Translation Offset + 0xF300, // Address Length + ,, , TypeStatic) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, + 0x00000000, // Address Space Granularity + 0x000A0000, // Address Range Minimum + 0x000BFFFF, // Address Range Maximum + 0x00000000, // Address Translation Offset + 0x00020000, // Address Length + ,, , AddressRangeMemory, TypeStatic) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite, + 0x00000000, // Address Space Granularity + 0xE0000000, // Address Range Minimum + 0xFEBFFFFF, // Address Range Maximum + 0x00000000, // Address Translation Offset + 0x1EC00000, // Address Length + ,, , AddressRangeMemory, TypeStatic) + }) + } + + Device(HPET) { + Name(_HID, EISAID("PNP0103")) + Name(_UID, 0) + Method (_STA, 0, NotSerialized) { + Return(0x0F) + } + Name(_CRS, ResourceTemplate() { + DWordMemory( + ResourceConsumer, PosDecode, MinFixed, MaxFixed, + NonCacheable, ReadWrite, + 0x00000000, + 0xFED00000, + 0xFED003FF, + 0x00000000, + 0x00000400 /* 1K memory: FED00000 - FED003FF */ + ) + }) + } + } + + Scope(\_SB.PCI0) { + Device (VGA) { + Name (_ADR, 0x00020000) + OperationRegion(PCIC, PCI_Config, Zero, 0x4) + Field(PCIC, DWordAcc, NoLock, Preserve) { + VEND, 32 + } + Method (_S1D, 0, NotSerialized) + { + Return (0x00) + } + Method (_S2D, 0, NotSerialized) + { + Return (0x00) + } + Method (_S3D, 0, NotSerialized) + { + If (LEqual(VEND, 0x1001b36)) { + Return (0x03) // QXL + } Else { + Return (0x00) + } + } + Method(_RMV) { Return (0x00) } + } + + /* PIIX3 ISA bridge */ + Device (ISA) { + Name (_ADR, 0x00010000) + Method(_RMV) { Return (0x00) } + + + /* PIIX PCI to ISA irq remapping */ + OperationRegion (P40C, PCI_Config, 0x60, 0x04) + + /* Real-time clock */ + Device (RTC) + { + Name (_HID, EisaId ("PNP0B00")) + Name (_CRS, ResourceTemplate () + { + IO (Decode16, 0x0070, 0x0070, 0x10, 0x02) + IRQNoFlags () {8} + IO (Decode16, 0x0072, 0x0072, 0x02, 0x06) + }) + } + + /* Keyboard seems to be important for WinXP install */ + Device (KBD) + { + Name (_HID, EisaId ("PNP0303")) + Method (_STA, 0, NotSerialized) + { + Return (0x0f) + } + + Method (_CRS, 0, NotSerialized) + { + Name (TMP, ResourceTemplate () + { + IO (Decode16, + 0x0060, // Address Range Minimum + 0x0060, // Address Range Maximum + 0x01, // Address Alignment + 0x01, // Address Length + ) + IO (Decode16, + 0x0064, // Address Range Minimum + 0x0064, // Address Range Maximum + 0x01, // Address Alignment + 0x01, // Address Length + ) + IRQNoFlags () + {1} + }) + Return (TMP) + } + } + + /* PS/2 mouse */ + Device (MOU) + { + Name (_HID, EisaId ("PNP0F13")) + Method (_STA, 0, NotSerialized) + { + Return (0x0f) + } + + Method (_CRS, 0, NotSerialized) + { + Name (TMP, ResourceTemplate () + { + IRQNoFlags () {12} + }) + Return (TMP) + } + } + + /* PS/2 floppy controller */ + Device (FDC0) + { + Name (_HID, EisaId ("PNP0700")) + Method (_STA, 0, NotSerialized) + { + Return (0x0F) + } + Method (_CRS, 0, NotSerialized) + { + Name (BUF0, ResourceTemplate () + { + IO (Decode16, 0x03F2, 0x03F2, 0x00, 0x04) + IO (Decode16, 0x03F7, 0x03F7, 0x00, 0x01) + IRQNoFlags () {6} + DMA (Compatibility, NotBusMaster, Transfer8) {2} + }) + Return (BUF0) + } + } + + /* Parallel port */ + Device (LPT) + { + Name (_HID, EisaId ("PNP0400")) + Method (_STA, 0, NotSerialized) + { + Store (\_SB.PCI0.PX13.DRSA, Local0) + And (Local0, 0x80000000, Local0) + If (LEqual (Local0, 0)) + { + Return (0x00) + } + Else + { + Return (0x0F) + } + } + Method (_CRS, 0, NotSerialized) + { + Name (BUF0, ResourceTemplate () + { + IO (Decode16, 0x0378, 0x0378, 0x08, 0x08) + IRQNoFlags () {7} + }) + Return (BUF0) + } + } + + /* Serial Ports */ + Device (COM1) + { + Name (_HID, EisaId ("PNP0501")) + Name (_UID, 0x01) + Method (_STA, 0, NotSerialized) + { + Store (\_SB.PCI0.PX13.DRSC, Local0) + And (Local0, 0x08000000, Local0) + If (LEqual (Local0, 0)) + { + Return (0x00) + } + Else + { + Return (0x0F) + } + } + Method (_CRS, 0, NotSerialized) + { + Name (BUF0, ResourceTemplate () + { + IO (Decode16, 0x03F8, 0x03F8, 0x00, 0x08) + IRQNoFlags () {4} + }) + Return (BUF0) + } + } + + Device (COM2) + { + Name (_HID, EisaId ("PNP0501")) + Name (_UID, 0x02) + Method (_STA, 0, NotSerialized) + { + Store (\_SB.PCI0.PX13.DRSC, Local0) + And (Local0, 0x80000000, Local0) + If (LEqual (Local0, 0)) + { + Return (0x00) + } + Else + { + Return (0x0F) + } + } + Method (_CRS, 0, NotSerialized) + { + Name (BUF0, ResourceTemplate () + { + IO (Decode16, 0x02F8, 0x02F8, 0x00, 0x08) + IRQNoFlags () {3} + }) + Return (BUF0) + } + } + } + + /* PIIX4 PM */ + Device (PX13) { + Name (_ADR, 0x00010003) + + OperationRegion (P13C, PCI_Config, 0x5c, 0x24) + Field (P13C, DWordAcc, NoLock, Preserve) + { + DRSA, 32, + DRSB, 32, + DRSC, 32, + DRSE, 32, + DRSF, 32, + DRSG, 32, + DRSH, 32, + DRSI, 32, + DRSJ, 32 + } + } + +#define gen_pci_device(name, nr) \ + Device(SL##name) { \ + Name (_ADR, nr##0000) \ + Method (_RMV) { \ + If (And(\_SB.PCI0.PCRM, ShiftLeft(1, nr))) { \ + Return (0x1) \ + } \ + Return (0x0) \ + } \ + Name (_SUN, name) \ + } + + /* VGA (slot 1) and ISA bus (slot 2) defined above */ + gen_pci_device(3, 0x0003) + gen_pci_device(4, 0x0004) + gen_pci_device(5, 0x0005) + gen_pci_device(6, 0x0006) + gen_pci_device(7, 0x0007) + gen_pci_device(8, 0x0008) + gen_pci_device(9, 0x0009) + gen_pci_device(10, 0x000a) + gen_pci_device(11, 0x000b) + gen_pci_device(12, 0x000c) + gen_pci_device(13, 0x000d) + gen_pci_device(14, 0x000e) + gen_pci_device(15, 0x000f) + gen_pci_device(16, 0x0010) + gen_pci_device(17, 0x0011) + gen_pci_device(18, 0x0012) + gen_pci_device(19, 0x0013) + gen_pci_device(20, 0x0014) + gen_pci_device(21, 0x0015) + gen_pci_device(22, 0x0016) + gen_pci_device(23, 0x0017) + gen_pci_device(24, 0x0018) + gen_pci_device(25, 0x0019) + gen_pci_device(26, 0x001a) + gen_pci_device(27, 0x001b) + gen_pci_device(28, 0x001c) + gen_pci_device(29, 0x001d) + gen_pci_device(30, 0x001e) + gen_pci_device(31, 0x001f) + } + + /* PCI IRQs */ + Scope(\_SB) { + Field (\_SB.PCI0.ISA.P40C, ByteAcc, NoLock, Preserve) + { + PRQ0, 8, + PRQ1, 8, + PRQ2, 8, + PRQ3, 8 + } + + Device(LNKA){ + Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link + Name(_UID, 1) + Name(_PRS, ResourceTemplate(){ + Interrupt (, Level, ActiveHigh, Shared) + { 5, 10, 11 } + }) + Method (_STA, 0, NotSerialized) + { + Store (0x0B, Local0) + If (And (0x80, PRQ0, Local1)) + { + Store (0x09, Local0) + } + Return (Local0) + } + Method (_DIS, 0, NotSerialized) + { + Or (PRQ0, 0x80, PRQ0) + } + Method (_CRS, 0, NotSerialized) + { + Name (PRR0, ResourceTemplate () + { + Interrupt (, Level, ActiveHigh, Shared) + {1} + }) + CreateDWordField (PRR0, 0x05, TMP) + Store (PRQ0, Local0) + If (LLess (Local0, 0x80)) + { + Store (Local0, TMP) + } + Else + { + Store (Zero, TMP) + } + Return (PRR0) + } + Method (_SRS, 1, NotSerialized) + { + CreateDWordField (Arg0, 0x05, TMP) + Store (TMP, PRQ0) + } + } + Device(LNKB){ + Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link + Name(_UID, 2) + Name(_PRS, ResourceTemplate(){ + Interrupt (, Level, ActiveHigh, Shared) + { 5, 10, 11 } + }) + Method (_STA, 0, NotSerialized) + { + Store (0x0B, Local0) + If (And (0x80, PRQ1, Local1)) + { + Store (0x09, Local0) + } + Return (Local0) + } + Method (_DIS, 0, NotSerialized) + { + Or (PRQ1, 0x80, PRQ1) + } + Method (_CRS, 0, NotSerialized) + { + Name (PRR0, ResourceTemplate () + { + Interrupt (, Level, ActiveHigh, Shared) + {1} + }) + CreateDWordField (PRR0, 0x05, TMP) + Store (PRQ1, Local0) + If (LLess (Local0, 0x80)) + { + Store (Local0, TMP) + } + Else + { + Store (Zero, TMP) + } + Return (PRR0) + } + Method (_SRS, 1, NotSerialized) + { + CreateDWordField (Arg0, 0x05, TMP) + Store (TMP, PRQ1) + } + } + Device(LNKC){ + Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link + Name(_UID, 3) + Name(_PRS, ResourceTemplate(){ + Interrupt (, Level, ActiveHigh, Shared) + { 5, 10, 11 } + }) + Method (_STA, 0, NotSerialized) + { + Store (0x0B, Local0) + If (And (0x80, PRQ2, Local1)) + { + Store (0x09, Local0) + } + Return (Local0) + } + Method (_DIS, 0, NotSerialized) + { + Or (PRQ2, 0x80, PRQ2) + } + Method (_CRS, 0, NotSerialized) + { + Name (PRR0, ResourceTemplate () + { + Interrupt (, Level, ActiveHigh, Shared) + {1} + }) + CreateDWordField (PRR0, 0x05, TMP) + Store (PRQ2, Local0) + If (LLess (Local0, 0x80)) + { + Store (Local0, TMP) + } + Else + { + Store (Zero, TMP) + } + Return (PRR0) + } + Method (_SRS, 1, NotSerialized) + { + CreateDWordField (Arg0, 0x05, TMP) + Store (TMP, PRQ2) + } + } + Device(LNKD){ + Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link + Name(_UID, 4) + Name(_PRS, ResourceTemplate(){ + Interrupt (, Level, ActiveHigh, Shared) + { 5, 10, 11 } + }) + Method (_STA, 0, NotSerialized) + { + Store (0x0B, Local0) + If (And (0x80, PRQ3, Local1)) + { + Store (0x09, Local0) + } + Return (Local0) + } + Method (_DIS, 0, NotSerialized) + { + Or (PRQ3, 0x80, PRQ3) + } + Method (_CRS, 0, NotSerialized) + { + Name (PRR0, ResourceTemplate () + { + Interrupt (, Level, ActiveHigh, Shared) + {1} + }) + CreateDWordField (PRR0, 0x05, TMP) + Store (PRQ3, Local0) + If (LLess (Local0, 0x80)) + { + Store (Local0, TMP) + } + Else + { + Store (Zero, TMP) + } + Return (PRR0) + } + Method (_SRS, 1, NotSerialized) + { + CreateDWordField (Arg0, 0x05, TMP) + Store (TMP, PRQ3) + } + } + Device(LNKS){ + Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link + Name(_UID, 5) + Name(_PRS, ResourceTemplate(){ + Interrupt (, Level, ActiveHigh, Shared) + { 9 } + }) + Method (_STA, 0, NotSerialized) + { + Store (0x0B, Local0) + If (And (0x80, PRQ0, Local1)) + { + Store (0x09, Local0) + } + Return (Local0) + } + Method (_DIS, 0, NotSerialized) + { + Or (PRQ0, 0x80, PRQ0) + } + Method (_CRS, 0, NotSerialized) + { + Name (PRR0, ResourceTemplate () + { + Interrupt (, Level, ActiveHigh, Shared) + {9} + }) + CreateDWordField (PRR0, 0x05, TMP) + Store (PRQ0, Local0) + If (LLess (Local0, 0x80)) + { + Store (Local0, TMP) + } + Else + { + Store (Zero, TMP) + } + Return (PRR0) + } + } + } + + /* + * S3 (suspend-to-ram), S4 (suspend-to-disk) and S5 (power-off) type codes: + * must match piix4 emulation. + */ + Name (\_S3, Package (0x04) + { + 0x01, /* PM1a_CNT.SLP_TYP */ + 0x01, /* PM1b_CNT.SLP_TYP */ + Zero, /* reserved */ + Zero /* reserved */ + }) + Name (\_S4, Package (0x04) + { + Zero, /* PM1a_CNT.SLP_TYP */ + Zero, /* PM1b_CNT.SLP_TYP */ + Zero, /* reserved */ + Zero /* reserved */ + }) + Name (\_S5, Package (0x04) + { + Zero, /* PM1a_CNT.SLP_TYP */ + Zero, /* PM1b_CNT.SLP_TYP */ + Zero, /* reserved */ + Zero /* reserved */ + }) + + /* CPU hotplug */ + Scope(\_SB) { + /* Objects filled in by run-time generated SSDT */ + External(NTFY, MethodObj) + External(CPON, PkgObj) + + /* Methods called by run-time generated SSDT Processor objects */ + Method (CPMA, 1, NotSerialized) { + // _MAT method - create an madt apic buffer + // Local0 = CPON flag for this cpu + Store(DerefOf(Index(CPON, Arg0)), Local0) + // Local1 = Buffer (in madt apic form) to return + Store(Buffer(8) {0x00, 0x08, 0x00, 0x00, 0x00, 0, 0, 0}, Local1) + // Update the processor id, lapic id, and enable/disable status + Store(Arg0, Index(Local1, 2)) + Store(Arg0, Index(Local1, 3)) + Store(Local0, Index(Local1, 4)) + Return (Local1) + } + Method (CPST, 1, NotSerialized) { + // _STA method - return ON status of cpu + // Local0 = CPON flag for this cpu + Store(DerefOf(Index(CPON, Arg0)), Local0) + If (Local0) { Return(0xF) } Else { Return(0x0) } + } + Method (CPEJ, 2, NotSerialized) { + // _EJ0 method - eject callback + Sleep(200) + } + + /* CPU hotplug notify method */ + OperationRegion(PRST, SystemIO, 0xaf00, 32) + Field (PRST, ByteAcc, NoLock, Preserve) + { + PRS, 256 + } + Method(PRSC, 0) { + // Local5 = active cpu bitmap + Store (PRS, Local5) + // Local2 = last read byte from bitmap + Store (Zero, Local2) + // Local0 = cpuid iterator + Store (Zero, Local0) + While (LLess(Local0, SizeOf(CPON))) { + // Local1 = CPON flag for this cpu + Store(DerefOf(Index(CPON, Local0)), Local1) + If (And(Local0, 0x07)) { + // Shift down previously read bitmap byte + ShiftRight(Local2, 1, Local2) + } Else { + // Read next byte from cpu bitmap + Store(DerefOf(Index(Local5, ShiftRight(Local0, 3))), Local2) + } + // Local3 = active state for this cpu + Store(And(Local2, 1), Local3) + + If (LNotEqual(Local1, Local3)) { + // State change - update CPON with new state + Store(Local3, Index(CPON, Local0)) + // Do CPU notify + If (LEqual(Local3, 1)) { + NTFY(Local0, 1) + } Else { + NTFY(Local0, 3) + } + } + Increment(Local0) + } + Return(One) + } + } + + Scope (\_GPE) + { + Name(_HID, "ACPI0006") + + Method(_L00) { + Return(0x01) + } + +#define gen_pci_hotplug(nr) \ + If (And(\_SB.PCI0.PCIU, ShiftLeft(1, nr))) { \ + Notify(\_SB.PCI0.S##nr, 1) \ + } \ + If (And(\_SB.PCI0.PCID, ShiftLeft(1, nr))) { \ + Notify(\_SB.PCI0.S##nr, 3) \ + } + + Method(_L01) { + gen_pci_hotplug(1) + gen_pci_hotplug(2) + gen_pci_hotplug(3) + gen_pci_hotplug(4) + gen_pci_hotplug(5) + gen_pci_hotplug(6) + gen_pci_hotplug(7) + gen_pci_hotplug(8) + gen_pci_hotplug(9) + gen_pci_hotplug(10) + gen_pci_hotplug(11) + gen_pci_hotplug(12) + gen_pci_hotplug(13) + gen_pci_hotplug(14) + gen_pci_hotplug(15) + gen_pci_hotplug(16) + gen_pci_hotplug(17) + gen_pci_hotplug(18) + gen_pci_hotplug(19) + gen_pci_hotplug(20) + gen_pci_hotplug(21) + gen_pci_hotplug(22) + gen_pci_hotplug(23) + gen_pci_hotplug(24) + gen_pci_hotplug(25) + gen_pci_hotplug(26) + gen_pci_hotplug(27) + gen_pci_hotplug(28) + gen_pci_hotplug(29) + gen_pci_hotplug(30) + gen_pci_hotplug(31) + + Return (0x01) + + } + Method(_L02) { + // CPU hotplug event + Return(\_SB.PRSC()) + } + Method(_L03) { + Return(0x01) + } + Method(_L04) { + Return(0x01) + } + Method(_L05) { + Return(0x01) + } + Method(_L06) { + Return(0x01) + } + Method(_L07) { + Return(0x01) + } + Method(_L08) { + Return(0x01) + } + Method(_L09) { + Return(0x01) + } + Method(_L0A) { + Return(0x01) + } + Method(_L0B) { + Return(0x01) + } + Method(_L0C) { + Return(0x01) + } + Method(_L0D) { + Return(0x01) + } + Method(_L0E) { + Return(0x01) + } + Method(_L0F) { + Return(0x01) + } + } + +} diff --git a/bios/seabios/src/acpi-dsdt.hex b/bios/seabios/src/acpi-dsdt.hex new file mode 100644 index 0000000..0f3b7cd --- /dev/null +++ b/bios/seabios/src/acpi-dsdt.hex @@ -0,0 +1,1218 @@ +/* + * + * Intel ACPI Component Architecture + * ASL Optimizing Compiler version 20100528 [Feb 9 2011] + * Copyright (c) 2000 - 2010 Intel Corporation + * Supports ACPI Specification Revision 4.0a + * + * Compilation of "out/acpi-dsdt.dsl.i" - Tue Jan 22 14:33:33 2013 + * + * C source code output + * AML code block contains 0x2589 bytes + * + */ +unsigned char AmlCode[] = +{ + 0x44,0x53,0x44,0x54,0x89,0x25,0x00,0x00, /* 00000000 "DSDT.%.." */ + 0x01,0x13,0x42,0x58,0x50,0x43,0x00,0x00, /* 00000008 "..BXPC.." */ + 0x42,0x58,0x44,0x53,0x44,0x54,0x00,0x00, /* 00000010 "BXDSDT.." */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x10,0x49,0x04,0x5C, /* 00000020 "(.. .I.\" */ + 0x00,0x5B,0x80,0x44,0x42,0x47,0x5F,0x01, /* 00000028 ".[.DBG_." */ + 0x0B,0x02,0x04,0x01,0x5B,0x81,0x0B,0x44, /* 00000030 "....[..D" */ + 0x42,0x47,0x5F,0x01,0x44,0x42,0x47,0x42, /* 00000038 "BG_.DBGB" */ + 0x08,0x14,0x2C,0x44,0x42,0x55,0x47,0x01, /* 00000040 "..,DBUG." */ + 0x98,0x68,0x60,0x96,0x60,0x60,0x74,0x87, /* 00000048 ".h`.``t." */ + 0x60,0x01,0x61,0x70,0x00,0x62,0xA2,0x10, /* 00000050 "`.ap.b.." */ + 0x95,0x62,0x61,0x70,0x83,0x88,0x60,0x62, /* 00000058 ".bap..`b" */ + 0x00,0x44,0x42,0x47,0x42,0x75,0x62,0x70, /* 00000060 ".DBGBubp" */ + 0x0A,0x0A,0x44,0x42,0x47,0x42,0x10,0x43, /* 00000068 "..DBGB.C" */ + 0xD8,0x5F,0x53,0x42,0x5F,0x5B,0x82,0x44, /* 00000070 "._SB_[.D" */ + 0xD3,0x50,0x43,0x49,0x30,0x08,0x5F,0x48, /* 00000078 ".PCI0._H" */ + 0x49,0x44,0x0C,0x41,0xD0,0x0A,0x03,0x08, /* 00000080 "ID.A...." */ + 0x5F,0x41,0x44,0x52,0x00,0x08,0x5F,0x55, /* 00000088 "_ADR.._U" */ + 0x49,0x44,0x01,0x08,0x5F,0x50,0x52,0x54, /* 00000090 "ID.._PRT" */ + 0x12,0x4B,0x73,0x80,0x12,0x0B,0x04,0x0B, /* 00000098 ".Ks....." */ + 0xFF,0xFF,0x00,0x4C,0x4E,0x4B,0x44,0x00, /* 000000A0 "...LNKD." */ + 0x12,0x0B,0x04,0x0B,0xFF,0xFF,0x01,0x4C, /* 000000A8 ".......L" */ + 0x4E,0x4B,0x41,0x00,0x12,0x0C,0x04,0x0B, /* 000000B0 "NKA....." */ + 0xFF,0xFF,0x0A,0x02,0x4C,0x4E,0x4B,0x42, /* 000000B8 "....LNKB" */ + 0x00,0x12,0x0C,0x04,0x0B,0xFF,0xFF,0x0A, /* 000000C0 "........" */ + 0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 000000C8 ".LNKC..." */ + 0x04,0x0C,0xFF,0xFF,0x01,0x00,0x00,0x4C, /* 000000D0 ".......L" */ + 0x4E,0x4B,0x53,0x00,0x12,0x0D,0x04,0x0C, /* 000000D8 "NKS....." */ + 0xFF,0xFF,0x01,0x00,0x01,0x4C,0x4E,0x4B, /* 000000E0 ".....LNK" */ + 0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 000000E8 "B......." */ + 0x01,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43, /* 000000F0 "....LNKC" */ + 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x01, /* 000000F8 "........" */ + 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00, /* 00000100 "...LNKD." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x02,0x00, /* 00000108 "........" */ + 0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 00000110 ".LNKB..." */ + 0x04,0x0C,0xFF,0xFF,0x02,0x00,0x01,0x4C, /* 00000118 ".......L" */ + 0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C, /* 00000120 "NKC....." */ + 0xFF,0xFF,0x02,0x00,0x0A,0x02,0x4C,0x4E, /* 00000128 "......LN" */ + 0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000130 "KD......" */ + 0xFF,0x02,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000138 ".....LNK" */ + 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000140 "A......." */ + 0x03,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00, /* 00000148 "...LNKC." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x03,0x00, /* 00000150 "........" */ + 0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E, /* 00000158 ".LNKD..." */ + 0x04,0x0C,0xFF,0xFF,0x03,0x00,0x0A,0x02, /* 00000160 "........" */ + 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04, /* 00000168 "LNKA...." */ + 0x0C,0xFF,0xFF,0x03,0x00,0x0A,0x03,0x4C, /* 00000170 ".......L" */ + 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000178 "NKB....." */ + 0xFF,0xFF,0x04,0x00,0x00,0x4C,0x4E,0x4B, /* 00000180 ".....LNK" */ + 0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000188 "D......." */ + 0x04,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00, /* 00000190 "...LNKA." */ + 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x04,0x00, /* 00000198 "........" */ + 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 000001A0 "..LNKB.." */ + 0x0E,0x04,0x0C,0xFF,0xFF,0x04,0x00,0x0A, /* 000001A8 "........" */ + 0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 000001B0 ".LNKC..." */ + 0x04,0x0C,0xFF,0xFF,0x05,0x00,0x00,0x4C, /* 000001B8 ".......L" */ + 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 000001C0 "NKA....." */ + 0xFF,0xFF,0x05,0x00,0x01,0x4C,0x4E,0x4B, /* 000001C8 ".....LNK" */ + 0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 000001D0 "B......." */ + 0x05,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43, /* 000001D8 "....LNKC" */ + 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x05, /* 000001E0 "........" */ + 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00, /* 000001E8 "...LNKD." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x06,0x00, /* 000001F0 "........" */ + 0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 000001F8 ".LNKB..." */ + 0x04,0x0C,0xFF,0xFF,0x06,0x00,0x01,0x4C, /* 00000200 ".......L" */ + 0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C, /* 00000208 "NKC....." */ + 0xFF,0xFF,0x06,0x00,0x0A,0x02,0x4C,0x4E, /* 00000210 "......LN" */ + 0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000218 "KD......" */ + 0xFF,0x06,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000220 ".....LNK" */ + 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000228 "A......." */ + 0x07,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00, /* 00000230 "...LNKC." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x07,0x00, /* 00000238 "........" */ + 0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E, /* 00000240 ".LNKD..." */ + 0x04,0x0C,0xFF,0xFF,0x07,0x00,0x0A,0x02, /* 00000248 "........" */ + 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04, /* 00000250 "LNKA...." */ + 0x0C,0xFF,0xFF,0x07,0x00,0x0A,0x03,0x4C, /* 00000258 ".......L" */ + 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000260 "NKB....." */ + 0xFF,0xFF,0x08,0x00,0x00,0x4C,0x4E,0x4B, /* 00000268 ".....LNK" */ + 0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000270 "D......." */ + 0x08,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00, /* 00000278 "...LNKA." */ + 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x08,0x00, /* 00000280 "........" */ + 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 00000288 "..LNKB.." */ + 0x0E,0x04,0x0C,0xFF,0xFF,0x08,0x00,0x0A, /* 00000290 "........" */ + 0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000298 ".LNKC..." */ + 0x04,0x0C,0xFF,0xFF,0x09,0x00,0x00,0x4C, /* 000002A0 ".......L" */ + 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 000002A8 "NKA....." */ + 0xFF,0xFF,0x09,0x00,0x01,0x4C,0x4E,0x4B, /* 000002B0 ".....LNK" */ + 0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 000002B8 "B......." */ + 0x09,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43, /* 000002C0 "....LNKC" */ + 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x09, /* 000002C8 "........" */ + 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00, /* 000002D0 "...LNKD." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0A,0x00, /* 000002D8 "........" */ + 0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 000002E0 ".LNKB..." */ + 0x04,0x0C,0xFF,0xFF,0x0A,0x00,0x01,0x4C, /* 000002E8 ".......L" */ + 0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C, /* 000002F0 "NKC....." */ + 0xFF,0xFF,0x0A,0x00,0x0A,0x02,0x4C,0x4E, /* 000002F8 "......LN" */ + 0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000300 "KD......" */ + 0xFF,0x0A,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000308 ".....LNK" */ + 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000310 "A......." */ + 0x0B,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00, /* 00000318 "...LNKC." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0B,0x00, /* 00000320 "........" */ + 0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E, /* 00000328 ".LNKD..." */ + 0x04,0x0C,0xFF,0xFF,0x0B,0x00,0x0A,0x02, /* 00000330 "........" */ + 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04, /* 00000338 "LNKA...." */ + 0x0C,0xFF,0xFF,0x0B,0x00,0x0A,0x03,0x4C, /* 00000340 ".......L" */ + 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000348 "NKB....." */ + 0xFF,0xFF,0x0C,0x00,0x00,0x4C,0x4E,0x4B, /* 00000350 ".....LNK" */ + 0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000358 "D......." */ + 0x0C,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00, /* 00000360 "...LNKA." */ + 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x0C,0x00, /* 00000368 "........" */ + 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 00000370 "..LNKB.." */ + 0x0E,0x04,0x0C,0xFF,0xFF,0x0C,0x00,0x0A, /* 00000378 "........" */ + 0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000380 ".LNKC..." */ + 0x04,0x0C,0xFF,0xFF,0x0D,0x00,0x00,0x4C, /* 00000388 ".......L" */ + 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 00000390 "NKA....." */ + 0xFF,0xFF,0x0D,0x00,0x01,0x4C,0x4E,0x4B, /* 00000398 ".....LNK" */ + 0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 000003A0 "B......." */ + 0x0D,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43, /* 000003A8 "....LNKC" */ + 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x0D, /* 000003B0 "........" */ + 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00, /* 000003B8 "...LNKD." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0E,0x00, /* 000003C0 "........" */ + 0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 000003C8 ".LNKB..." */ + 0x04,0x0C,0xFF,0xFF,0x0E,0x00,0x01,0x4C, /* 000003D0 ".......L" */ + 0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C, /* 000003D8 "NKC....." */ + 0xFF,0xFF,0x0E,0x00,0x0A,0x02,0x4C,0x4E, /* 000003E0 "......LN" */ + 0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 000003E8 "KD......" */ + 0xFF,0x0E,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 000003F0 ".....LNK" */ + 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000003F8 "A......." */ + 0x0F,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00, /* 00000400 "...LNKC." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0F,0x00, /* 00000408 "........" */ + 0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E, /* 00000410 ".LNKD..." */ + 0x04,0x0C,0xFF,0xFF,0x0F,0x00,0x0A,0x02, /* 00000418 "........" */ + 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04, /* 00000420 "LNKA...." */ + 0x0C,0xFF,0xFF,0x0F,0x00,0x0A,0x03,0x4C, /* 00000428 ".......L" */ + 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000430 "NKB....." */ + 0xFF,0xFF,0x10,0x00,0x00,0x4C,0x4E,0x4B, /* 00000438 ".....LNK" */ + 0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000440 "D......." */ + 0x10,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00, /* 00000448 "...LNKA." */ + 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x10,0x00, /* 00000450 "........" */ + 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 00000458 "..LNKB.." */ + 0x0E,0x04,0x0C,0xFF,0xFF,0x10,0x00,0x0A, /* 00000460 "........" */ + 0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000468 ".LNKC..." */ + 0x04,0x0C,0xFF,0xFF,0x11,0x00,0x00,0x4C, /* 00000470 ".......L" */ + 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 00000478 "NKA....." */ + 0xFF,0xFF,0x11,0x00,0x01,0x4C,0x4E,0x4B, /* 00000480 ".....LNK" */ + 0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000488 "B......." */ + 0x11,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43, /* 00000490 "....LNKC" */ + 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x11, /* 00000498 "........" */ + 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00, /* 000004A0 "...LNKD." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x12,0x00, /* 000004A8 "........" */ + 0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 000004B0 ".LNKB..." */ + 0x04,0x0C,0xFF,0xFF,0x12,0x00,0x01,0x4C, /* 000004B8 ".......L" */ + 0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C, /* 000004C0 "NKC....." */ + 0xFF,0xFF,0x12,0x00,0x0A,0x02,0x4C,0x4E, /* 000004C8 "......LN" */ + 0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 000004D0 "KD......" */ + 0xFF,0x12,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 000004D8 ".....LNK" */ + 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000004E0 "A......." */ + 0x13,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00, /* 000004E8 "...LNKC." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x13,0x00, /* 000004F0 "........" */ + 0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E, /* 000004F8 ".LNKD..." */ + 0x04,0x0C,0xFF,0xFF,0x13,0x00,0x0A,0x02, /* 00000500 "........" */ + 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04, /* 00000508 "LNKA...." */ + 0x0C,0xFF,0xFF,0x13,0x00,0x0A,0x03,0x4C, /* 00000510 ".......L" */ + 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000518 "NKB....." */ + 0xFF,0xFF,0x14,0x00,0x00,0x4C,0x4E,0x4B, /* 00000520 ".....LNK" */ + 0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000528 "D......." */ + 0x14,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00, /* 00000530 "...LNKA." */ + 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x14,0x00, /* 00000538 "........" */ + 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 00000540 "..LNKB.." */ + 0x0E,0x04,0x0C,0xFF,0xFF,0x14,0x00,0x0A, /* 00000548 "........" */ + 0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000550 ".LNKC..." */ + 0x04,0x0C,0xFF,0xFF,0x15,0x00,0x00,0x4C, /* 00000558 ".......L" */ + 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 00000560 "NKA....." */ + 0xFF,0xFF,0x15,0x00,0x01,0x4C,0x4E,0x4B, /* 00000568 ".....LNK" */ + 0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000570 "B......." */ + 0x15,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43, /* 00000578 "....LNKC" */ + 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x15, /* 00000580 "........" */ + 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00, /* 00000588 "...LNKD." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x16,0x00, /* 00000590 "........" */ + 0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 00000598 ".LNKB..." */ + 0x04,0x0C,0xFF,0xFF,0x16,0x00,0x01,0x4C, /* 000005A0 ".......L" */ + 0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C, /* 000005A8 "NKC....." */ + 0xFF,0xFF,0x16,0x00,0x0A,0x02,0x4C,0x4E, /* 000005B0 "......LN" */ + 0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 000005B8 "KD......" */ + 0xFF,0x16,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 000005C0 ".....LNK" */ + 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000005C8 "A......." */ + 0x17,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00, /* 000005D0 "...LNKC." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x17,0x00, /* 000005D8 "........" */ + 0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E, /* 000005E0 ".LNKD..." */ + 0x04,0x0C,0xFF,0xFF,0x17,0x00,0x0A,0x02, /* 000005E8 "........" */ + 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04, /* 000005F0 "LNKA...." */ + 0x0C,0xFF,0xFF,0x17,0x00,0x0A,0x03,0x4C, /* 000005F8 ".......L" */ + 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000600 "NKB....." */ + 0xFF,0xFF,0x18,0x00,0x00,0x4C,0x4E,0x4B, /* 00000608 ".....LNK" */ + 0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000610 "D......." */ + 0x18,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00, /* 00000618 "...LNKA." */ + 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x18,0x00, /* 00000620 "........" */ + 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 00000628 "..LNKB.." */ + 0x0E,0x04,0x0C,0xFF,0xFF,0x18,0x00,0x0A, /* 00000630 "........" */ + 0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000638 ".LNKC..." */ + 0x04,0x0C,0xFF,0xFF,0x19,0x00,0x00,0x4C, /* 00000640 ".......L" */ + 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 00000648 "NKA....." */ + 0xFF,0xFF,0x19,0x00,0x01,0x4C,0x4E,0x4B, /* 00000650 ".....LNK" */ + 0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000658 "B......." */ + 0x19,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43, /* 00000660 "....LNKC" */ + 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x19, /* 00000668 "........" */ + 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00, /* 00000670 "...LNKD." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x1A,0x00, /* 00000678 "........" */ + 0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 00000680 ".LNKB..." */ + 0x04,0x0C,0xFF,0xFF,0x1A,0x00,0x01,0x4C, /* 00000688 ".......L" */ + 0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C, /* 00000690 "NKC....." */ + 0xFF,0xFF,0x1A,0x00,0x0A,0x02,0x4C,0x4E, /* 00000698 "......LN" */ + 0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 000006A0 "KD......" */ + 0xFF,0x1A,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 000006A8 ".....LNK" */ + 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000006B0 "A......." */ + 0x1B,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00, /* 000006B8 "...LNKC." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x1B,0x00, /* 000006C0 "........" */ + 0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E, /* 000006C8 ".LNKD..." */ + 0x04,0x0C,0xFF,0xFF,0x1B,0x00,0x0A,0x02, /* 000006D0 "........" */ + 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04, /* 000006D8 "LNKA...." */ + 0x0C,0xFF,0xFF,0x1B,0x00,0x0A,0x03,0x4C, /* 000006E0 ".......L" */ + 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 000006E8 "NKB....." */ + 0xFF,0xFF,0x1C,0x00,0x00,0x4C,0x4E,0x4B, /* 000006F0 ".....LNK" */ + 0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000006F8 "D......." */ + 0x1C,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00, /* 00000700 "...LNKA." */ + 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x1C,0x00, /* 00000708 "........" */ + 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 00000710 "..LNKB.." */ + 0x0E,0x04,0x0C,0xFF,0xFF,0x1C,0x00,0x0A, /* 00000718 "........" */ + 0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000720 ".LNKC..." */ + 0x04,0x0C,0xFF,0xFF,0x1D,0x00,0x00,0x4C, /* 00000728 ".......L" */ + 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 00000730 "NKA....." */ + 0xFF,0xFF,0x1D,0x00,0x01,0x4C,0x4E,0x4B, /* 00000738 ".....LNK" */ + 0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000740 "B......." */ + 0x1D,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43, /* 00000748 "....LNKC" */ + 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x1D, /* 00000750 "........" */ + 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00, /* 00000758 "...LNKD." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x1E,0x00, /* 00000760 "........" */ + 0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 00000768 ".LNKB..." */ + 0x04,0x0C,0xFF,0xFF,0x1E,0x00,0x01,0x4C, /* 00000770 ".......L" */ + 0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C, /* 00000778 "NKC....." */ + 0xFF,0xFF,0x1E,0x00,0x0A,0x02,0x4C,0x4E, /* 00000780 "......LN" */ + 0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000788 "KD......" */ + 0xFF,0x1E,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000790 ".....LNK" */ + 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000798 "A......." */ + 0x1F,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00, /* 000007A0 "...LNKC." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x1F,0x00, /* 000007A8 "........" */ + 0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E, /* 000007B0 ".LNKD..." */ + 0x04,0x0C,0xFF,0xFF,0x1F,0x00,0x0A,0x02, /* 000007B8 "........" */ + 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04, /* 000007C0 "LNKA...." */ + 0x0C,0xFF,0xFF,0x1F,0x00,0x0A,0x03,0x4C, /* 000007C8 ".......L" */ + 0x4E,0x4B,0x42,0x00,0x5B,0x80,0x50,0x43, /* 000007D0 "NKB.[.PC" */ + 0x53,0x54,0x01,0x0B,0x00,0xAE,0x0A,0x08, /* 000007D8 "ST......" */ + 0x5B,0x81,0x10,0x50,0x43,0x53,0x54,0x43, /* 000007E0 "[..PCSTC" */ + 0x50,0x43,0x49,0x55,0x20,0x50,0x43,0x49, /* 000007E8 "PCIU PCI" */ + 0x44,0x20,0x5B,0x80,0x53,0x45,0x4A,0x5F, /* 000007F0 "D [.SEJ_" */ + 0x01,0x0B,0x08,0xAE,0x0A,0x04,0x5B,0x81, /* 000007F8 "......[." */ + 0x0B,0x53,0x45,0x4A,0x5F,0x43,0x42,0x30, /* 00000800 ".SEJ_CB0" */ + 0x45,0x4A,0x20,0x5B,0x80,0x52,0x4D,0x56, /* 00000808 "EJ [.RMV" */ + 0x43,0x01,0x0B,0x0C,0xAE,0x0A,0x04,0x5B, /* 00000810 "C......[" */ + 0x81,0x0B,0x52,0x4D,0x56,0x43,0x43,0x50, /* 00000818 "..RMVCCP" */ + 0x43,0x52,0x4D,0x20,0x5B,0x82,0x25,0x53, /* 00000820 "CRM [.%S" */ + 0x31,0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52, /* 00000828 "1__._ADR" */ + 0x0C,0x00,0x00,0x01,0x00,0x14,0x0F,0x5F, /* 00000830 "......._" */ + 0x45,0x4A,0x30,0x01,0x70,0x0A,0x02,0x42, /* 00000838 "EJ0.p..B" */ + 0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53, /* 00000840 "0EJ..._S" */ + 0x55,0x4E,0x01,0x5B,0x82,0x26,0x53,0x32, /* 00000848 "UN.[.&S2" */ + 0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C, /* 00000850 "__._ADR." */ + 0x00,0x00,0x02,0x00,0x14,0x0F,0x5F,0x45, /* 00000858 "......_E" */ + 0x4A,0x30,0x01,0x70,0x0A,0x04,0x42,0x30, /* 00000860 "J0.p..B0" */ + 0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55, /* 00000868 "EJ..._SU" */ + 0x4E,0x0A,0x02,0x5B,0x82,0x26,0x53,0x33, /* 00000870 "N..[.&S3" */ + 0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C, /* 00000878 "__._ADR." */ + 0x00,0x00,0x03,0x00,0x14,0x0F,0x5F,0x45, /* 00000880 "......_E" */ + 0x4A,0x30,0x01,0x70,0x0A,0x08,0x42,0x30, /* 00000888 "J0.p..B0" */ + 0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55, /* 00000890 "EJ..._SU" */ + 0x4E,0x0A,0x03,0x5B,0x82,0x26,0x53,0x34, /* 00000898 "N..[.&S4" */ + 0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C, /* 000008A0 "__._ADR." */ + 0x00,0x00,0x04,0x00,0x14,0x0F,0x5F,0x45, /* 000008A8 "......_E" */ + 0x4A,0x30,0x01,0x70,0x0A,0x10,0x42,0x30, /* 000008B0 "J0.p..B0" */ + 0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55, /* 000008B8 "EJ..._SU" */ + 0x4E,0x0A,0x04,0x5B,0x82,0x26,0x53,0x35, /* 000008C0 "N..[.&S5" */ + 0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C, /* 000008C8 "__._ADR." */ + 0x00,0x00,0x05,0x00,0x14,0x0F,0x5F,0x45, /* 000008D0 "......_E" */ + 0x4A,0x30,0x01,0x70,0x0A,0x20,0x42,0x30, /* 000008D8 "J0.p. B0" */ + 0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55, /* 000008E0 "EJ..._SU" */ + 0x4E,0x0A,0x05,0x5B,0x82,0x26,0x53,0x36, /* 000008E8 "N..[.&S6" */ + 0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C, /* 000008F0 "__._ADR." */ + 0x00,0x00,0x06,0x00,0x14,0x0F,0x5F,0x45, /* 000008F8 "......_E" */ + 0x4A,0x30,0x01,0x70,0x0A,0x40,0x42,0x30, /* 00000900 "J0.p.@B0" */ + 0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55, /* 00000908 "EJ..._SU" */ + 0x4E,0x0A,0x06,0x5B,0x82,0x26,0x53,0x37, /* 00000910 "N..[.&S7" */ + 0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C, /* 00000918 "__._ADR." */ + 0x00,0x00,0x07,0x00,0x14,0x0F,0x5F,0x45, /* 00000920 "......_E" */ + 0x4A,0x30,0x01,0x70,0x0A,0x80,0x42,0x30, /* 00000928 "J0.p..B0" */ + 0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55, /* 00000930 "EJ..._SU" */ + 0x4E,0x0A,0x07,0x5B,0x82,0x27,0x53,0x38, /* 00000938 "N..[.'S8" */ + 0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C, /* 00000940 "__._ADR." */ + 0x00,0x00,0x08,0x00,0x14,0x10,0x5F,0x45, /* 00000948 "......_E" */ + 0x4A,0x30,0x01,0x70,0x0B,0x00,0x01,0x42, /* 00000950 "J0.p...B" */ + 0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53, /* 00000958 "0EJ..._S" */ + 0x55,0x4E,0x0A,0x08,0x5B,0x82,0x27,0x53, /* 00000960 "UN..[.'S" */ + 0x39,0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52, /* 00000968 "9__._ADR" */ + 0x0C,0x00,0x00,0x09,0x00,0x14,0x10,0x5F, /* 00000970 "......._" */ + 0x45,0x4A,0x30,0x01,0x70,0x0B,0x00,0x02, /* 00000978 "EJ0.p..." */ + 0x42,0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F, /* 00000980 "B0EJ..._" */ + 0x53,0x55,0x4E,0x0A,0x09,0x5B,0x82,0x27, /* 00000988 "SUN..[.'" */ + 0x53,0x31,0x30,0x5F,0x08,0x5F,0x41,0x44, /* 00000990 "S10_._AD" */ + 0x52,0x0C,0x00,0x00,0x0A,0x00,0x14,0x10, /* 00000998 "R......." */ + 0x5F,0x45,0x4A,0x30,0x01,0x70,0x0B,0x00, /* 000009A0 "_EJ0.p.." */ + 0x04,0x42,0x30,0x45,0x4A,0xA4,0x00,0x08, /* 000009A8 ".B0EJ..." */ + 0x5F,0x53,0x55,0x4E,0x0A,0x0A,0x5B,0x82, /* 000009B0 "_SUN..[." */ + 0x27,0x53,0x31,0x31,0x5F,0x08,0x5F,0x41, /* 000009B8 "'S11_._A" */ + 0x44,0x52,0x0C,0x00,0x00,0x0B,0x00,0x14, /* 000009C0 "DR......" */ + 0x10,0x5F,0x45,0x4A,0x30,0x01,0x70,0x0B, /* 000009C8 "._EJ0.p." */ + 0x00,0x08,0x42,0x30,0x45,0x4A,0xA4,0x00, /* 000009D0 "..B0EJ.." */ + 0x08,0x5F,0x53,0x55,0x4E,0x0A,0x0B,0x5B, /* 000009D8 "._SUN..[" */ + 0x82,0x27,0x53,0x31,0x32,0x5F,0x08,0x5F, /* 000009E0 ".'S12_._" */ + 0x41,0x44,0x52,0x0C,0x00,0x00,0x0C,0x00, /* 000009E8 "ADR....." */ + 0x14,0x10,0x5F,0x45,0x4A,0x30,0x01,0x70, /* 000009F0 ".._EJ0.p" */ + 0x0B,0x00,0x10,0x42,0x30,0x45,0x4A,0xA4, /* 000009F8 "...B0EJ." */ + 0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,0x0C, /* 00000A00 ".._SUN.." */ + 0x5B,0x82,0x27,0x53,0x31,0x33,0x5F,0x08, /* 00000A08 "[.'S13_." */ + 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x0D, /* 00000A10 "_ADR...." */ + 0x00,0x14,0x10,0x5F,0x45,0x4A,0x30,0x01, /* 00000A18 "..._EJ0." */ + 0x70,0x0B,0x00,0x20,0x42,0x30,0x45,0x4A, /* 00000A20 "p.. B0EJ" */ + 0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A, /* 00000A28 "..._SUN." */ + 0x0D,0x5B,0x82,0x27,0x53,0x31,0x34,0x5F, /* 00000A30 ".[.'S14_" */ + 0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,0x00, /* 00000A38 "._ADR..." */ + 0x0E,0x00,0x14,0x10,0x5F,0x45,0x4A,0x30, /* 00000A40 "...._EJ0" */ + 0x01,0x70,0x0B,0x00,0x40,0x42,0x30,0x45, /* 00000A48 ".p..@B0E" */ + 0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E, /* 00000A50 "J..._SUN" */ + 0x0A,0x0E,0x5B,0x82,0x27,0x53,0x31,0x35, /* 00000A58 "..[.'S15" */ + 0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00, /* 00000A60 "_._ADR.." */ + 0x00,0x0F,0x00,0x14,0x10,0x5F,0x45,0x4A, /* 00000A68 "....._EJ" */ + 0x30,0x01,0x70,0x0B,0x00,0x80,0x42,0x30, /* 00000A70 "0.p...B0" */ + 0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55, /* 00000A78 "EJ..._SU" */ + 0x4E,0x0A,0x0F,0x5B,0x82,0x29,0x53,0x31, /* 00000A80 "N..[.)S1" */ + 0x36,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C, /* 00000A88 "6_._ADR." */ + 0x00,0x00,0x10,0x00,0x14,0x12,0x5F,0x45, /* 00000A90 "......_E" */ + 0x4A,0x30,0x01,0x70,0x0C,0x00,0x00,0x01, /* 00000A98 "J0.p...." */ + 0x00,0x42,0x30,0x45,0x4A,0xA4,0x00,0x08, /* 00000AA0 ".B0EJ..." */ + 0x5F,0x53,0x55,0x4E,0x0A,0x10,0x5B,0x82, /* 00000AA8 "_SUN..[." */ + 0x29,0x53,0x31,0x37,0x5F,0x08,0x5F,0x41, /* 00000AB0 ")S17_._A" */ + 0x44,0x52,0x0C,0x00,0x00,0x11,0x00,0x14, /* 00000AB8 "DR......" */ + 0x12,0x5F,0x45,0x4A,0x30,0x01,0x70,0x0C, /* 00000AC0 "._EJ0.p." */ + 0x00,0x00,0x02,0x00,0x42,0x30,0x45,0x4A, /* 00000AC8 "....B0EJ" */ + 0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A, /* 00000AD0 "..._SUN." */ + 0x11,0x5B,0x82,0x29,0x53,0x31,0x38,0x5F, /* 00000AD8 ".[.)S18_" */ + 0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,0x00, /* 00000AE0 "._ADR..." */ + 0x12,0x00,0x14,0x12,0x5F,0x45,0x4A,0x30, /* 00000AE8 "...._EJ0" */ + 0x01,0x70,0x0C,0x00,0x00,0x04,0x00,0x42, /* 00000AF0 ".p.....B" */ + 0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53, /* 00000AF8 "0EJ..._S" */ + 0x55,0x4E,0x0A,0x12,0x5B,0x82,0x29,0x53, /* 00000B00 "UN..[.)S" */ + 0x31,0x39,0x5F,0x08,0x5F,0x41,0x44,0x52, /* 00000B08 "19_._ADR" */ + 0x0C,0x00,0x00,0x13,0x00,0x14,0x12,0x5F, /* 00000B10 "......._" */ + 0x45,0x4A,0x30,0x01,0x70,0x0C,0x00,0x00, /* 00000B18 "EJ0.p..." */ + 0x08,0x00,0x42,0x30,0x45,0x4A,0xA4,0x00, /* 00000B20 "..B0EJ.." */ + 0x08,0x5F,0x53,0x55,0x4E,0x0A,0x13,0x5B, /* 00000B28 "._SUN..[" */ + 0x82,0x29,0x53,0x32,0x30,0x5F,0x08,0x5F, /* 00000B30 ".)S20_._" */ + 0x41,0x44,0x52,0x0C,0x00,0x00,0x14,0x00, /* 00000B38 "ADR....." */ + 0x14,0x12,0x5F,0x45,0x4A,0x30,0x01,0x70, /* 00000B40 ".._EJ0.p" */ + 0x0C,0x00,0x00,0x10,0x00,0x42,0x30,0x45, /* 00000B48 ".....B0E" */ + 0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E, /* 00000B50 "J..._SUN" */ + 0x0A,0x14,0x5B,0x82,0x29,0x53,0x32,0x31, /* 00000B58 "..[.)S21" */ + 0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00, /* 00000B60 "_._ADR.." */ + 0x00,0x15,0x00,0x14,0x12,0x5F,0x45,0x4A, /* 00000B68 "....._EJ" */ + 0x30,0x01,0x70,0x0C,0x00,0x00,0x20,0x00, /* 00000B70 "0.p... ." */ + 0x42,0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F, /* 00000B78 "B0EJ..._" */ + 0x53,0x55,0x4E,0x0A,0x15,0x5B,0x82,0x29, /* 00000B80 "SUN..[.)" */ + 0x53,0x32,0x32,0x5F,0x08,0x5F,0x41,0x44, /* 00000B88 "S22_._AD" */ + 0x52,0x0C,0x00,0x00,0x16,0x00,0x14,0x12, /* 00000B90 "R......." */ + 0x5F,0x45,0x4A,0x30,0x01,0x70,0x0C,0x00, /* 00000B98 "_EJ0.p.." */ + 0x00,0x40,0x00,0x42,0x30,0x45,0x4A,0xA4, /* 00000BA0 ".@.B0EJ." */ + 0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,0x16, /* 00000BA8 ".._SUN.." */ + 0x5B,0x82,0x29,0x53,0x32,0x33,0x5F,0x08, /* 00000BB0 "[.)S23_." */ + 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x17, /* 00000BB8 "_ADR...." */ + 0x00,0x14,0x12,0x5F,0x45,0x4A,0x30,0x01, /* 00000BC0 "..._EJ0." */ + 0x70,0x0C,0x00,0x00,0x80,0x00,0x42,0x30, /* 00000BC8 "p.....B0" */ + 0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55, /* 00000BD0 "EJ..._SU" */ + 0x4E,0x0A,0x17,0x5B,0x82,0x29,0x53,0x32, /* 00000BD8 "N..[.)S2" */ + 0x34,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C, /* 00000BE0 "4_._ADR." */ + 0x00,0x00,0x18,0x00,0x14,0x12,0x5F,0x45, /* 00000BE8 "......_E" */ + 0x4A,0x30,0x01,0x70,0x0C,0x00,0x00,0x00, /* 00000BF0 "J0.p...." */ + 0x01,0x42,0x30,0x45,0x4A,0xA4,0x00,0x08, /* 00000BF8 ".B0EJ..." */ + 0x5F,0x53,0x55,0x4E,0x0A,0x18,0x5B,0x82, /* 00000C00 "_SUN..[." */ + 0x29,0x53,0x32,0x35,0x5F,0x08,0x5F,0x41, /* 00000C08 ")S25_._A" */ + 0x44,0x52,0x0C,0x00,0x00,0x19,0x00,0x14, /* 00000C10 "DR......" */ + 0x12,0x5F,0x45,0x4A,0x30,0x01,0x70,0x0C, /* 00000C18 "._EJ0.p." */ + 0x00,0x00,0x00,0x02,0x42,0x30,0x45,0x4A, /* 00000C20 "....B0EJ" */ + 0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A, /* 00000C28 "..._SUN." */ + 0x19,0x5B,0x82,0x29,0x53,0x32,0x36,0x5F, /* 00000C30 ".[.)S26_" */ + 0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,0x00, /* 00000C38 "._ADR..." */ + 0x1A,0x00,0x14,0x12,0x5F,0x45,0x4A,0x30, /* 00000C40 "...._EJ0" */ + 0x01,0x70,0x0C,0x00,0x00,0x00,0x04,0x42, /* 00000C48 ".p.....B" */ + 0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53, /* 00000C50 "0EJ..._S" */ + 0x55,0x4E,0x0A,0x1A,0x5B,0x82,0x29,0x53, /* 00000C58 "UN..[.)S" */ + 0x32,0x37,0x5F,0x08,0x5F,0x41,0x44,0x52, /* 00000C60 "27_._ADR" */ + 0x0C,0x00,0x00,0x1B,0x00,0x14,0x12,0x5F, /* 00000C68 "......._" */ + 0x45,0x4A,0x30,0x01,0x70,0x0C,0x00,0x00, /* 00000C70 "EJ0.p..." */ + 0x00,0x08,0x42,0x30,0x45,0x4A,0xA4,0x00, /* 00000C78 "..B0EJ.." */ + 0x08,0x5F,0x53,0x55,0x4E,0x0A,0x1B,0x5B, /* 00000C80 "._SUN..[" */ + 0x82,0x29,0x53,0x32,0x38,0x5F,0x08,0x5F, /* 00000C88 ".)S28_._" */ + 0x41,0x44,0x52,0x0C,0x00,0x00,0x1C,0x00, /* 00000C90 "ADR....." */ + 0x14,0x12,0x5F,0x45,0x4A,0x30,0x01,0x70, /* 00000C98 ".._EJ0.p" */ + 0x0C,0x00,0x00,0x00,0x10,0x42,0x30,0x45, /* 00000CA0 ".....B0E" */ + 0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E, /* 00000CA8 "J..._SUN" */ + 0x0A,0x1C,0x5B,0x82,0x29,0x53,0x32,0x39, /* 00000CB0 "..[.)S29" */ + 0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00, /* 00000CB8 "_._ADR.." */ + 0x00,0x1D,0x00,0x14,0x12,0x5F,0x45,0x4A, /* 00000CC0 "....._EJ" */ + 0x30,0x01,0x70,0x0C,0x00,0x00,0x00,0x20, /* 00000CC8 "0.p.... " */ + 0x42,0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F, /* 00000CD0 "B0EJ..._" */ + 0x53,0x55,0x4E,0x0A,0x1D,0x5B,0x82,0x29, /* 00000CD8 "SUN..[.)" */ + 0x53,0x33,0x30,0x5F,0x08,0x5F,0x41,0x44, /* 00000CE0 "S30_._AD" */ + 0x52,0x0C,0x00,0x00,0x1E,0x00,0x14,0x12, /* 00000CE8 "R......." */ + 0x5F,0x45,0x4A,0x30,0x01,0x70,0x0C,0x00, /* 00000CF0 "_EJ0.p.." */ + 0x00,0x00,0x40,0x42,0x30,0x45,0x4A,0xA4, /* 00000CF8 "..@B0EJ." */ + 0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,0x1E, /* 00000D00 ".._SUN.." */ + 0x5B,0x82,0x29,0x53,0x33,0x31,0x5F,0x08, /* 00000D08 "[.)S31_." */ + 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x1F, /* 00000D10 "_ADR...." */ + 0x00,0x14,0x12,0x5F,0x45,0x4A,0x30,0x01, /* 00000D18 "..._EJ0." */ + 0x70,0x0C,0x00,0x00,0x00,0x80,0x42,0x30, /* 00000D20 "p.....B0" */ + 0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55, /* 00000D28 "EJ..._SU" */ + 0x4E,0x0A,0x1F,0x08,0x5F,0x43,0x52,0x53, /* 00000D30 "N..._CRS" */ + 0x11,0x42,0x07,0x0A,0x6E,0x88,0x0D,0x00, /* 00000D38 ".B..n..." */ + 0x02,0x0C,0x00,0x00,0x00,0x00,0x00,0xFF, /* 00000D40 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x47,0x01,0xF8, /* 00000D48 ".....G.." */ + 0x0C,0xF8,0x0C,0x01,0x08,0x88,0x0D,0x00, /* 00000D50 "........" */ + 0x01,0x0C,0x03,0x00,0x00,0x00,0x00,0xF7, /* 00000D58 "........" */ + 0x0C,0x00,0x00,0xF8,0x0C,0x88,0x0D,0x00, /* 00000D60 "........" */ + 0x01,0x0C,0x03,0x00,0x00,0x00,0x0D,0xFF, /* 00000D68 "........" */ + 0xFF,0x00,0x00,0x00,0xF3,0x87,0x17,0x00, /* 00000D70 "........" */ + 0x00,0x0C,0x03,0x00,0x00,0x00,0x00,0x00, /* 00000D78 "........" */ + 0x00,0x0A,0x00,0xFF,0xFF,0x0B,0x00,0x00, /* 00000D80 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x87, /* 00000D88 "........" */ + 0x17,0x00,0x00,0x0C,0x01,0x00,0x00,0x00, /* 00000D90 "........" */ + 0x00,0x00,0x00,0x00,0xE0,0xFF,0xFF,0xBF, /* 00000D98 "........" */ + 0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0xC0, /* 00000DA0 "........" */ + 0x1E,0x79,0x00,0x5B,0x82,0x45,0x04,0x48, /* 00000DA8 ".y.[.E.H" */ + 0x50,0x45,0x54,0x08,0x5F,0x48,0x49,0x44, /* 00000DB0 "PET._HID" */ + 0x0C,0x41,0xD0,0x01,0x03,0x08,0x5F,0x55, /* 00000DB8 ".A...._U" */ + 0x49,0x44,0x00,0x14,0x09,0x5F,0x53,0x54, /* 00000DC0 "ID..._ST" */ + 0x41,0x00,0xA4,0x0A,0x0F,0x08,0x5F,0x43, /* 00000DC8 "A....._C" */ + 0x52,0x53,0x11,0x1F,0x0A,0x1C,0x87,0x17, /* 00000DD0 "RS......" */ + 0x00,0x00,0x0D,0x01,0x00,0x00,0x00,0x00, /* 00000DD8 "........" */ + 0x00,0x00,0xD0,0xFE,0xFF,0x03,0xD0,0xFE, /* 00000DE0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00, /* 00000DE8 "........" */ + 0x79,0x00,0x10,0x49,0x84,0x2E,0x5F,0x53, /* 00000DF0 "y..I.._S" */ + 0x42,0x5F,0x50,0x43,0x49,0x30,0x5B,0x82, /* 00000DF8 "B_PCI0[." */ + 0x4C,0x05,0x56,0x47,0x41,0x5F,0x08,0x5F, /* 00000E00 "L.VGA_._" */ + 0x41,0x44,0x52,0x0C,0x00,0x00,0x02,0x00, /* 00000E08 "ADR....." */ + 0x5B,0x80,0x50,0x43,0x49,0x43,0x02,0x00, /* 00000E10 "[.PCIC.." */ + 0x0A,0x04,0x5B,0x81,0x0B,0x50,0x43,0x49, /* 00000E18 "..[..PCI" */ + 0x43,0x03,0x56,0x45,0x4E,0x44,0x20,0x14, /* 00000E20 "C.VEND ." */ + 0x08,0x5F,0x53,0x31,0x44,0x00,0xA4,0x00, /* 00000E28 "._S1D..." */ + 0x14,0x08,0x5F,0x53,0x32,0x44,0x00,0xA4, /* 00000E30 ".._S2D.." */ + 0x00,0x14,0x19,0x5F,0x53,0x33,0x44,0x00, /* 00000E38 "..._S3D." */ + 0xA0,0x0E,0x93,0x56,0x45,0x4E,0x44,0x0C, /* 00000E40 "...VEND." */ + 0x36,0x1B,0x00,0x01,0xA4,0x0A,0x03,0xA1, /* 00000E48 "6......." */ + 0x03,0xA4,0x00,0x14,0x08,0x5F,0x52,0x4D, /* 00000E50 "....._RM" */ + 0x56,0x00,0xA4,0x00,0x5B,0x82,0x4B,0x23, /* 00000E58 "V...[.K#" */ + 0x49,0x53,0x41,0x5F,0x08,0x5F,0x41,0x44, /* 00000E60 "ISA_._AD" */ + 0x52,0x0C,0x00,0x00,0x01,0x00,0x14,0x08, /* 00000E68 "R......." */ + 0x5F,0x52,0x4D,0x56,0x00,0xA4,0x00,0x5B, /* 00000E70 "_RMV...[" */ + 0x80,0x50,0x34,0x30,0x43,0x02,0x0A,0x60, /* 00000E78 ".P40C..`" */ + 0x0A,0x04,0x5B,0x82,0x2D,0x52,0x54,0x43, /* 00000E80 "..[.-RTC" */ + 0x5F,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000E88 "_._HID.A" */ + 0xD0,0x0B,0x00,0x08,0x5F,0x43,0x52,0x53, /* 00000E90 "...._CRS" */ + 0x11,0x18,0x0A,0x15,0x47,0x01,0x70,0x00, /* 00000E98 "....G.p." */ + 0x70,0x00,0x10,0x02,0x22,0x00,0x01,0x47, /* 00000EA0 "p..."..G" */ + 0x01,0x72,0x00,0x72,0x00,0x02,0x06,0x79, /* 00000EA8 ".r.r...y" */ + 0x00,0x5B,0x82,0x44,0x04,0x4B,0x42,0x44, /* 00000EB0 ".[.D.KBD" */ + 0x5F,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000EB8 "_._HID.A" */ + 0xD0,0x03,0x03,0x14,0x09,0x5F,0x53,0x54, /* 00000EC0 "....._ST" */ + 0x41,0x00,0xA4,0x0A,0x0F,0x14,0x29,0x5F, /* 00000EC8 "A.....)_" */ + 0x43,0x52,0x53,0x00,0x08,0x54,0x4D,0x50, /* 00000ED0 "CRS..TMP" */ + 0x5F,0x11,0x18,0x0A,0x15,0x47,0x01,0x60, /* 00000ED8 "_....G.`" */ + 0x00,0x60,0x00,0x01,0x01,0x47,0x01,0x64, /* 00000EE0 ".`...G.d" */ + 0x00,0x64,0x00,0x01,0x01,0x22,0x02,0x00, /* 00000EE8 ".d...".." */ + 0x79,0x00,0xA4,0x54,0x4D,0x50,0x5F,0x5B, /* 00000EF0 "y..TMP_[" */ + 0x82,0x33,0x4D,0x4F,0x55,0x5F,0x08,0x5F, /* 00000EF8 ".3MOU_._" */ + 0x48,0x49,0x44,0x0C,0x41,0xD0,0x0F,0x13, /* 00000F00 "HID.A..." */ + 0x14,0x09,0x5F,0x53,0x54,0x41,0x00,0xA4, /* 00000F08 ".._STA.." */ + 0x0A,0x0F,0x14,0x19,0x5F,0x43,0x52,0x53, /* 00000F10 "...._CRS" */ + 0x00,0x08,0x54,0x4D,0x50,0x5F,0x11,0x08, /* 00000F18 "..TMP_.." */ + 0x0A,0x05,0x22,0x00,0x10,0x79,0x00,0xA4, /* 00000F20 ".."..y.." */ + 0x54,0x4D,0x50,0x5F,0x5B,0x82,0x47,0x04, /* 00000F28 "TMP_[.G." */ + 0x46,0x44,0x43,0x30,0x08,0x5F,0x48,0x49, /* 00000F30 "FDC0._HI" */ + 0x44,0x0C,0x41,0xD0,0x07,0x00,0x14,0x09, /* 00000F38 "D.A....." */ + 0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F, /* 00000F40 "_STA...." */ + 0x14,0x2C,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000F48 ".,_CRS.." */ + 0x42,0x55,0x46,0x30,0x11,0x1B,0x0A,0x18, /* 00000F50 "BUF0...." */ + 0x47,0x01,0xF2,0x03,0xF2,0x03,0x00,0x04, /* 00000F58 "G......." */ + 0x47,0x01,0xF7,0x03,0xF7,0x03,0x00,0x01, /* 00000F60 "G......." */ + 0x22,0x40,0x00,0x2A,0x04,0x00,0x79,0x00, /* 00000F68 ""@.*..y." */ + 0xA4,0x42,0x55,0x46,0x30,0x5B,0x82,0x4B, /* 00000F70 ".BUF0[.K" */ + 0x05,0x4C,0x50,0x54,0x5F,0x08,0x5F,0x48, /* 00000F78 ".LPT_._H" */ + 0x49,0x44,0x0C,0x41,0xD0,0x04,0x00,0x14, /* 00000F80 "ID.A...." */ + 0x28,0x5F,0x53,0x54,0x41,0x00,0x70,0x5E, /* 00000F88 "(_STA.p^" */ + 0x5E,0x5E,0x2E,0x50,0x58,0x31,0x33,0x44, /* 00000F90 "^^.PX13D" */ + 0x52,0x53,0x41,0x60,0x7B,0x60,0x0C,0x00, /* 00000F98 "RSA`{`.." */ + 0x00,0x00,0x80,0x60,0xA0,0x06,0x93,0x60, /* 00000FA0 "...`...`" */ + 0x00,0xA4,0x00,0xA1,0x04,0xA4,0x0A,0x0F, /* 00000FA8 "........" */ + 0x14,0x21,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000FB0 ".!_CRS.." */ + 0x42,0x55,0x46,0x30,0x11,0x10,0x0A,0x0D, /* 00000FB8 "BUF0...." */ + 0x47,0x01,0x78,0x03,0x78,0x03,0x08,0x08, /* 00000FC0 "G.x.x..." */ + 0x22,0x80,0x00,0x79,0x00,0xA4,0x42,0x55, /* 00000FC8 ""..y..BU" */ + 0x46,0x30,0x5B,0x82,0x41,0x06,0x43,0x4F, /* 00000FD0 "F0[.A.CO" */ + 0x4D,0x31,0x08,0x5F,0x48,0x49,0x44,0x0C, /* 00000FD8 "M1._HID." */ + 0x41,0xD0,0x05,0x01,0x08,0x5F,0x55,0x49, /* 00000FE0 "A...._UI" */ + 0x44,0x01,0x14,0x28,0x5F,0x53,0x54,0x41, /* 00000FE8 "D..(_STA" */ + 0x00,0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58, /* 00000FF0 ".p^^^.PX" */ + 0x31,0x33,0x44,0x52,0x53,0x43,0x60,0x7B, /* 00000FF8 "13DRSC`{" */ + 0x60,0x0C,0x00,0x00,0x00,0x08,0x60,0xA0, /* 00001000 "`.....`." */ + 0x06,0x93,0x60,0x00,0xA4,0x00,0xA1,0x04, /* 00001008 "..`....." */ + 0xA4,0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52, /* 00001010 "....!_CR" */ + 0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00001018 "S..BUF0." */ + 0x10,0x0A,0x0D,0x47,0x01,0xF8,0x03,0xF8, /* 00001020 "...G...." */ + 0x03,0x00,0x08,0x22,0x10,0x00,0x79,0x00, /* 00001028 "..."..y." */ + 0xA4,0x42,0x55,0x46,0x30,0x5B,0x82,0x42, /* 00001030 ".BUF0[.B" */ + 0x06,0x43,0x4F,0x4D,0x32,0x08,0x5F,0x48, /* 00001038 ".COM2._H" */ + 0x49,0x44,0x0C,0x41,0xD0,0x05,0x01,0x08, /* 00001040 "ID.A...." */ + 0x5F,0x55,0x49,0x44,0x0A,0x02,0x14,0x28, /* 00001048 "_UID...(" */ + 0x5F,0x53,0x54,0x41,0x00,0x70,0x5E,0x5E, /* 00001050 "_STA.p^^" */ + 0x5E,0x2E,0x50,0x58,0x31,0x33,0x44,0x52, /* 00001058 "^.PX13DR" */ + 0x53,0x43,0x60,0x7B,0x60,0x0C,0x00,0x00, /* 00001060 "SC`{`..." */ + 0x00,0x80,0x60,0xA0,0x06,0x93,0x60,0x00, /* 00001068 "..`...`." */ + 0xA4,0x00,0xA1,0x04,0xA4,0x0A,0x0F,0x14, /* 00001070 "........" */ + 0x21,0x5F,0x43,0x52,0x53,0x00,0x08,0x42, /* 00001078 "!_CRS..B" */ + 0x55,0x46,0x30,0x11,0x10,0x0A,0x0D,0x47, /* 00001080 "UF0....G" */ + 0x01,0xF8,0x02,0xF8,0x02,0x00,0x08,0x22, /* 00001088 "......."" */ + 0x08,0x00,0x79,0x00,0xA4,0x42,0x55,0x46, /* 00001090 "..y..BUF" */ + 0x30,0x5B,0x82,0x40,0x05,0x50,0x58,0x31, /* 00001098 "0[.@.PX1" */ + 0x33,0x08,0x5F,0x41,0x44,0x52,0x0C,0x03, /* 000010A0 "3._ADR.." */ + 0x00,0x01,0x00,0x5B,0x80,0x50,0x31,0x33, /* 000010A8 "...[.P13" */ + 0x43,0x02,0x0A,0x5C,0x0A,0x24,0x5B,0x81, /* 000010B0 "C..\.$[." */ + 0x33,0x50,0x31,0x33,0x43,0x03,0x44,0x52, /* 000010B8 "3P13C.DR" */ + 0x53,0x41,0x20,0x44,0x52,0x53,0x42,0x20, /* 000010C0 "SA DRSB " */ + 0x44,0x52,0x53,0x43,0x20,0x44,0x52,0x53, /* 000010C8 "DRSC DRS" */ + 0x45,0x20,0x44,0x52,0x53,0x46,0x20,0x44, /* 000010D0 "E DRSF D" */ + 0x52,0x53,0x47,0x20,0x44,0x52,0x53,0x48, /* 000010D8 "RSG DRSH" */ + 0x20,0x44,0x52,0x53,0x49,0x20,0x44,0x52, /* 000010E0 " DRSI DR" */ + 0x53,0x4A,0x20,0x5B,0x82,0x2B,0x53,0x4C, /* 000010E8 "SJ [.+SL" */ + 0x33,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C, /* 000010F0 "3_._ADR." */ + 0x00,0x00,0x03,0x00,0x14,0x14,0x5F,0x52, /* 000010F8 "......_R" */ + 0x4D,0x56,0x00,0xA0,0x0B,0x7B,0x50,0x43, /* 00001100 "MV...{PC" */ + 0x52,0x4D,0x0A,0x08,0x00,0xA4,0x01,0xA4, /* 00001108 "RM......" */ + 0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,0x03, /* 00001110 ".._SUN.." */ + 0x5B,0x82,0x2B,0x53,0x4C,0x34,0x5F,0x08, /* 00001118 "[.+SL4_." */ + 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x04, /* 00001120 "_ADR...." */ + 0x00,0x14,0x14,0x5F,0x52,0x4D,0x56,0x00, /* 00001128 "..._RMV." */ + 0xA0,0x0B,0x7B,0x50,0x43,0x52,0x4D,0x0A, /* 00001130 "..{PCRM." */ + 0x10,0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F, /* 00001138 "......._" */ + 0x53,0x55,0x4E,0x0A,0x04,0x5B,0x82,0x2B, /* 00001140 "SUN..[.+" */ + 0x53,0x4C,0x35,0x5F,0x08,0x5F,0x41,0x44, /* 00001148 "SL5_._AD" */ + 0x52,0x0C,0x00,0x00,0x05,0x00,0x14,0x14, /* 00001150 "R......." */ + 0x5F,0x52,0x4D,0x56,0x00,0xA0,0x0B,0x7B, /* 00001158 "_RMV...{" */ + 0x50,0x43,0x52,0x4D,0x0A,0x20,0x00,0xA4, /* 00001160 "PCRM. .." */ + 0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E, /* 00001168 "...._SUN" */ + 0x0A,0x05,0x5B,0x82,0x2B,0x53,0x4C,0x36, /* 00001170 "..[.+SL6" */ + 0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00, /* 00001178 "_._ADR.." */ + 0x00,0x06,0x00,0x14,0x14,0x5F,0x52,0x4D, /* 00001180 "....._RM" */ + 0x56,0x00,0xA0,0x0B,0x7B,0x50,0x43,0x52, /* 00001188 "V...{PCR" */ + 0x4D,0x0A,0x40,0x00,0xA4,0x01,0xA4,0x00, /* 00001190 "M.@....." */ + 0x08,0x5F,0x53,0x55,0x4E,0x0A,0x06,0x5B, /* 00001198 "._SUN..[" */ + 0x82,0x2B,0x53,0x4C,0x37,0x5F,0x08,0x5F, /* 000011A0 ".+SL7_._" */ + 0x41,0x44,0x52,0x0C,0x00,0x00,0x07,0x00, /* 000011A8 "ADR....." */ + 0x14,0x14,0x5F,0x52,0x4D,0x56,0x00,0xA0, /* 000011B0 ".._RMV.." */ + 0x0B,0x7B,0x50,0x43,0x52,0x4D,0x0A,0x80, /* 000011B8 ".{PCRM.." */ + 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 000011C0 "......_S" */ + 0x55,0x4E,0x0A,0x07,0x5B,0x82,0x2C,0x53, /* 000011C8 "UN..[.,S" */ + 0x4C,0x38,0x5F,0x08,0x5F,0x41,0x44,0x52, /* 000011D0 "L8_._ADR" */ + 0x0C,0x00,0x00,0x08,0x00,0x14,0x15,0x5F, /* 000011D8 "......._" */ + 0x52,0x4D,0x56,0x00,0xA0,0x0C,0x7B,0x50, /* 000011E0 "RMV...{P" */ + 0x43,0x52,0x4D,0x0B,0x00,0x01,0x00,0xA4, /* 000011E8 "CRM....." */ + 0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E, /* 000011F0 "...._SUN" */ + 0x0A,0x08,0x5B,0x82,0x2C,0x53,0x4C,0x39, /* 000011F8 "..[.,SL9" */ + 0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00, /* 00001200 "_._ADR.." */ + 0x00,0x09,0x00,0x14,0x15,0x5F,0x52,0x4D, /* 00001208 "....._RM" */ + 0x56,0x00,0xA0,0x0C,0x7B,0x50,0x43,0x52, /* 00001210 "V...{PCR" */ + 0x4D,0x0B,0x00,0x02,0x00,0xA4,0x01,0xA4, /* 00001218 "M......." */ + 0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,0x09, /* 00001220 ".._SUN.." */ + 0x5B,0x82,0x2C,0x53,0x4C,0x31,0x30,0x08, /* 00001228 "[.,SL10." */ + 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x0A, /* 00001230 "_ADR...." */ + 0x00,0x14,0x15,0x5F,0x52,0x4D,0x56,0x00, /* 00001238 "..._RMV." */ + 0xA0,0x0C,0x7B,0x50,0x43,0x52,0x4D,0x0B, /* 00001240 "..{PCRM." */ + 0x00,0x04,0x00,0xA4,0x01,0xA4,0x00,0x08, /* 00001248 "........" */ + 0x5F,0x53,0x55,0x4E,0x0A,0x0A,0x5B,0x82, /* 00001250 "_SUN..[." */ + 0x2C,0x53,0x4C,0x31,0x31,0x08,0x5F,0x41, /* 00001258 ",SL11._A" */ + 0x44,0x52,0x0C,0x00,0x00,0x0B,0x00,0x14, /* 00001260 "DR......" */ + 0x15,0x5F,0x52,0x4D,0x56,0x00,0xA0,0x0C, /* 00001268 "._RMV..." */ + 0x7B,0x50,0x43,0x52,0x4D,0x0B,0x00,0x08, /* 00001270 "{PCRM..." */ + 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001278 "......_S" */ + 0x55,0x4E,0x0A,0x0B,0x5B,0x82,0x2C,0x53, /* 00001280 "UN..[.,S" */ + 0x4C,0x31,0x32,0x08,0x5F,0x41,0x44,0x52, /* 00001288 "L12._ADR" */ + 0x0C,0x00,0x00,0x0C,0x00,0x14,0x15,0x5F, /* 00001290 "......._" */ + 0x52,0x4D,0x56,0x00,0xA0,0x0C,0x7B,0x50, /* 00001298 "RMV...{P" */ + 0x43,0x52,0x4D,0x0B,0x00,0x10,0x00,0xA4, /* 000012A0 "CRM....." */ + 0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E, /* 000012A8 "...._SUN" */ + 0x0A,0x0C,0x5B,0x82,0x2C,0x53,0x4C,0x31, /* 000012B0 "..[.,SL1" */ + 0x33,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00, /* 000012B8 "3._ADR.." */ + 0x00,0x0D,0x00,0x14,0x15,0x5F,0x52,0x4D, /* 000012C0 "....._RM" */ + 0x56,0x00,0xA0,0x0C,0x7B,0x50,0x43,0x52, /* 000012C8 "V...{PCR" */ + 0x4D,0x0B,0x00,0x20,0x00,0xA4,0x01,0xA4, /* 000012D0 "M.. ...." */ + 0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,0x0D, /* 000012D8 ".._SUN.." */ + 0x5B,0x82,0x2C,0x53,0x4C,0x31,0x34,0x08, /* 000012E0 "[.,SL14." */ + 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x0E, /* 000012E8 "_ADR...." */ + 0x00,0x14,0x15,0x5F,0x52,0x4D,0x56,0x00, /* 000012F0 "..._RMV." */ + 0xA0,0x0C,0x7B,0x50,0x43,0x52,0x4D,0x0B, /* 000012F8 "..{PCRM." */ + 0x00,0x40,0x00,0xA4,0x01,0xA4,0x00,0x08, /* 00001300 ".@......" */ + 0x5F,0x53,0x55,0x4E,0x0A,0x0E,0x5B,0x82, /* 00001308 "_SUN..[." */ + 0x2C,0x53,0x4C,0x31,0x35,0x08,0x5F,0x41, /* 00001310 ",SL15._A" */ + 0x44,0x52,0x0C,0x00,0x00,0x0F,0x00,0x14, /* 00001318 "DR......" */ + 0x15,0x5F,0x52,0x4D,0x56,0x00,0xA0,0x0C, /* 00001320 "._RMV..." */ + 0x7B,0x50,0x43,0x52,0x4D,0x0B,0x00,0x80, /* 00001328 "{PCRM..." */ + 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001330 "......_S" */ + 0x55,0x4E,0x0A,0x0F,0x5B,0x82,0x2E,0x53, /* 00001338 "UN..[..S" */ + 0x4C,0x31,0x36,0x08,0x5F,0x41,0x44,0x52, /* 00001340 "L16._ADR" */ + 0x0C,0x00,0x00,0x10,0x00,0x14,0x17,0x5F, /* 00001348 "......._" */ + 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 00001350 "RMV...{P" */ + 0x43,0x52,0x4D,0x0C,0x00,0x00,0x01,0x00, /* 00001358 "CRM....." */ + 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001360 "......_S" */ + 0x55,0x4E,0x0A,0x10,0x5B,0x82,0x2E,0x53, /* 00001368 "UN..[..S" */ + 0x4C,0x31,0x37,0x08,0x5F,0x41,0x44,0x52, /* 00001370 "L17._ADR" */ + 0x0C,0x00,0x00,0x11,0x00,0x14,0x17,0x5F, /* 00001378 "......._" */ + 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 00001380 "RMV...{P" */ + 0x43,0x52,0x4D,0x0C,0x00,0x00,0x02,0x00, /* 00001388 "CRM....." */ + 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001390 "......_S" */ + 0x55,0x4E,0x0A,0x11,0x5B,0x82,0x2E,0x53, /* 00001398 "UN..[..S" */ + 0x4C,0x31,0x38,0x08,0x5F,0x41,0x44,0x52, /* 000013A0 "L18._ADR" */ + 0x0C,0x00,0x00,0x12,0x00,0x14,0x17,0x5F, /* 000013A8 "......._" */ + 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 000013B0 "RMV...{P" */ + 0x43,0x52,0x4D,0x0C,0x00,0x00,0x04,0x00, /* 000013B8 "CRM....." */ + 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 000013C0 "......_S" */ + 0x55,0x4E,0x0A,0x12,0x5B,0x82,0x2E,0x53, /* 000013C8 "UN..[..S" */ + 0x4C,0x31,0x39,0x08,0x5F,0x41,0x44,0x52, /* 000013D0 "L19._ADR" */ + 0x0C,0x00,0x00,0x13,0x00,0x14,0x17,0x5F, /* 000013D8 "......._" */ + 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 000013E0 "RMV...{P" */ + 0x43,0x52,0x4D,0x0C,0x00,0x00,0x08,0x00, /* 000013E8 "CRM....." */ + 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 000013F0 "......_S" */ + 0x55,0x4E,0x0A,0x13,0x5B,0x82,0x2E,0x53, /* 000013F8 "UN..[..S" */ + 0x4C,0x32,0x30,0x08,0x5F,0x41,0x44,0x52, /* 00001400 "L20._ADR" */ + 0x0C,0x00,0x00,0x14,0x00,0x14,0x17,0x5F, /* 00001408 "......._" */ + 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 00001410 "RMV...{P" */ + 0x43,0x52,0x4D,0x0C,0x00,0x00,0x10,0x00, /* 00001418 "CRM....." */ + 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001420 "......_S" */ + 0x55,0x4E,0x0A,0x14,0x5B,0x82,0x2E,0x53, /* 00001428 "UN..[..S" */ + 0x4C,0x32,0x31,0x08,0x5F,0x41,0x44,0x52, /* 00001430 "L21._ADR" */ + 0x0C,0x00,0x00,0x15,0x00,0x14,0x17,0x5F, /* 00001438 "......._" */ + 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 00001440 "RMV...{P" */ + 0x43,0x52,0x4D,0x0C,0x00,0x00,0x20,0x00, /* 00001448 "CRM... ." */ + 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001450 "......_S" */ + 0x55,0x4E,0x0A,0x15,0x5B,0x82,0x2E,0x53, /* 00001458 "UN..[..S" */ + 0x4C,0x32,0x32,0x08,0x5F,0x41,0x44,0x52, /* 00001460 "L22._ADR" */ + 0x0C,0x00,0x00,0x16,0x00,0x14,0x17,0x5F, /* 00001468 "......._" */ + 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 00001470 "RMV...{P" */ + 0x43,0x52,0x4D,0x0C,0x00,0x00,0x40,0x00, /* 00001478 "CRM...@." */ + 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001480 "......_S" */ + 0x55,0x4E,0x0A,0x16,0x5B,0x82,0x2E,0x53, /* 00001488 "UN..[..S" */ + 0x4C,0x32,0x33,0x08,0x5F,0x41,0x44,0x52, /* 00001490 "L23._ADR" */ + 0x0C,0x00,0x00,0x17,0x00,0x14,0x17,0x5F, /* 00001498 "......._" */ + 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 000014A0 "RMV...{P" */ + 0x43,0x52,0x4D,0x0C,0x00,0x00,0x80,0x00, /* 000014A8 "CRM....." */ + 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 000014B0 "......_S" */ + 0x55,0x4E,0x0A,0x17,0x5B,0x82,0x2E,0x53, /* 000014B8 "UN..[..S" */ + 0x4C,0x32,0x34,0x08,0x5F,0x41,0x44,0x52, /* 000014C0 "L24._ADR" */ + 0x0C,0x00,0x00,0x18,0x00,0x14,0x17,0x5F, /* 000014C8 "......._" */ + 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 000014D0 "RMV...{P" */ + 0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x01, /* 000014D8 "CRM....." */ + 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 000014E0 "......_S" */ + 0x55,0x4E,0x0A,0x18,0x5B,0x82,0x2E,0x53, /* 000014E8 "UN..[..S" */ + 0x4C,0x32,0x35,0x08,0x5F,0x41,0x44,0x52, /* 000014F0 "L25._ADR" */ + 0x0C,0x00,0x00,0x19,0x00,0x14,0x17,0x5F, /* 000014F8 "......._" */ + 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 00001500 "RMV...{P" */ + 0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x02, /* 00001508 "CRM....." */ + 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001510 "......_S" */ + 0x55,0x4E,0x0A,0x19,0x5B,0x82,0x2E,0x53, /* 00001518 "UN..[..S" */ + 0x4C,0x32,0x36,0x08,0x5F,0x41,0x44,0x52, /* 00001520 "L26._ADR" */ + 0x0C,0x00,0x00,0x1A,0x00,0x14,0x17,0x5F, /* 00001528 "......._" */ + 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 00001530 "RMV...{P" */ + 0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x04, /* 00001538 "CRM....." */ + 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001540 "......_S" */ + 0x55,0x4E,0x0A,0x1A,0x5B,0x82,0x2E,0x53, /* 00001548 "UN..[..S" */ + 0x4C,0x32,0x37,0x08,0x5F,0x41,0x44,0x52, /* 00001550 "L27._ADR" */ + 0x0C,0x00,0x00,0x1B,0x00,0x14,0x17,0x5F, /* 00001558 "......._" */ + 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 00001560 "RMV...{P" */ + 0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x08, /* 00001568 "CRM....." */ + 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001570 "......_S" */ + 0x55,0x4E,0x0A,0x1B,0x5B,0x82,0x2E,0x53, /* 00001578 "UN..[..S" */ + 0x4C,0x32,0x38,0x08,0x5F,0x41,0x44,0x52, /* 00001580 "L28._ADR" */ + 0x0C,0x00,0x00,0x1C,0x00,0x14,0x17,0x5F, /* 00001588 "......._" */ + 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 00001590 "RMV...{P" */ + 0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x10, /* 00001598 "CRM....." */ + 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 000015A0 "......_S" */ + 0x55,0x4E,0x0A,0x1C,0x5B,0x82,0x2E,0x53, /* 000015A8 "UN..[..S" */ + 0x4C,0x32,0x39,0x08,0x5F,0x41,0x44,0x52, /* 000015B0 "L29._ADR" */ + 0x0C,0x00,0x00,0x1D,0x00,0x14,0x17,0x5F, /* 000015B8 "......._" */ + 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 000015C0 "RMV...{P" */ + 0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x20, /* 000015C8 "CRM.... " */ + 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 000015D0 "......_S" */ + 0x55,0x4E,0x0A,0x1D,0x5B,0x82,0x2E,0x53, /* 000015D8 "UN..[..S" */ + 0x4C,0x33,0x30,0x08,0x5F,0x41,0x44,0x52, /* 000015E0 "L30._ADR" */ + 0x0C,0x00,0x00,0x1E,0x00,0x14,0x17,0x5F, /* 000015E8 "......._" */ + 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 000015F0 "RMV...{P" */ + 0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x40, /* 000015F8 "CRM....@" */ + 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001600 "......_S" */ + 0x55,0x4E,0x0A,0x1E,0x5B,0x82,0x2E,0x53, /* 00001608 "UN..[..S" */ + 0x4C,0x33,0x31,0x08,0x5F,0x41,0x44,0x52, /* 00001610 "L31._ADR" */ + 0x0C,0x00,0x00,0x1F,0x00,0x14,0x17,0x5F, /* 00001618 "......._" */ + 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 00001620 "RMV...{P" */ + 0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x80, /* 00001628 "CRM....." */ + 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001630 "......_S" */ + 0x55,0x4E,0x0A,0x1F,0x10,0x4B,0x3C,0x5F, /* 00001638 "UN...K<_" */ + 0x53,0x42,0x5F,0x5B,0x81,0x24,0x2F,0x03, /* 00001640 "SB_[.$/." */ + 0x50,0x43,0x49,0x30,0x49,0x53,0x41,0x5F, /* 00001648 "PCI0ISA_" */ + 0x50,0x34,0x30,0x43,0x01,0x50,0x52,0x51, /* 00001650 "P40C.PRQ" */ + 0x30,0x08,0x50,0x52,0x51,0x31,0x08,0x50, /* 00001658 "0.PRQ1.P" */ + 0x52,0x51,0x32,0x08,0x50,0x52,0x51,0x33, /* 00001660 "RQ2.PRQ3" */ + 0x08,0x5B,0x82,0x4D,0x0B,0x4C,0x4E,0x4B, /* 00001668 ".[.M.LNK" */ + 0x41,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00001670 "A._HID.A" */ + 0xD0,0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44, /* 00001678 "...._UID" */ + 0x01,0x08,0x5F,0x50,0x52,0x53,0x11,0x16, /* 00001680 ".._PRS.." */ + 0x0A,0x13,0x89,0x0E,0x00,0x09,0x03,0x05, /* 00001688 "........" */ + 0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x0B, /* 00001690 "........" */ + 0x00,0x00,0x00,0x79,0x00,0x14,0x1A,0x5F, /* 00001698 "...y..._" */ + 0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 000016A0 "STA.p..`" */ + 0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 000016A8 "..{..PRQ" */ + 0x30,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 000016B0 "0ap..`.`" */ + 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 000016B8 ".._DIS.}" */ + 0x50,0x52,0x51,0x30,0x0A,0x80,0x50,0x52, /* 000016C0 "PRQ0..PR" */ + 0x51,0x30,0x14,0x45,0x04,0x5F,0x43,0x52, /* 000016C8 "Q0.E._CR" */ + 0x53,0x00,0x08,0x50,0x52,0x52,0x30,0x11, /* 000016D0 "S..PRR0." */ + 0x0E,0x0A,0x0B,0x89,0x06,0x00,0x09,0x01, /* 000016D8 "........" */ + 0x01,0x00,0x00,0x00,0x79,0x00,0x8A,0x50, /* 000016E0 "....y..P" */ + 0x52,0x52,0x30,0x0A,0x05,0x54,0x4D,0x50, /* 000016E8 "RR0..TMP" */ + 0x5F,0x70,0x50,0x52,0x51,0x30,0x60,0xA0, /* 000016F0 "_pPRQ0`." */ + 0x0B,0x95,0x60,0x0A,0x80,0x70,0x60,0x54, /* 000016F8 "..`..p`T" */ + 0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 00001700 "MP_..p.T" */ + 0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 00001708 "MP_.PRR0" */ + 0x14,0x17,0x5F,0x53,0x52,0x53,0x01,0x8A, /* 00001710 ".._SRS.." */ + 0x68,0x0A,0x05,0x54,0x4D,0x50,0x5F,0x70, /* 00001718 "h..TMP_p" */ + 0x54,0x4D,0x50,0x5F,0x50,0x52,0x51,0x30, /* 00001720 "TMP_PRQ0" */ + 0x5B,0x82,0x4E,0x0B,0x4C,0x4E,0x4B,0x42, /* 00001728 "[.N.LNKB" */ + 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00001730 "._HID.A." */ + 0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 00001738 "..._UID." */ + 0x02,0x08,0x5F,0x50,0x52,0x53,0x11,0x16, /* 00001740 ".._PRS.." */ + 0x0A,0x13,0x89,0x0E,0x00,0x09,0x03,0x05, /* 00001748 "........" */ + 0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x0B, /* 00001750 "........" */ + 0x00,0x00,0x00,0x79,0x00,0x14,0x1A,0x5F, /* 00001758 "...y..._" */ + 0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 00001760 "STA.p..`" */ + 0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 00001768 "..{..PRQ" */ + 0x31,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 00001770 "1ap..`.`" */ + 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 00001778 ".._DIS.}" */ + 0x50,0x52,0x51,0x31,0x0A,0x80,0x50,0x52, /* 00001780 "PRQ1..PR" */ + 0x51,0x31,0x14,0x45,0x04,0x5F,0x43,0x52, /* 00001788 "Q1.E._CR" */ + 0x53,0x00,0x08,0x50,0x52,0x52,0x30,0x11, /* 00001790 "S..PRR0." */ + 0x0E,0x0A,0x0B,0x89,0x06,0x00,0x09,0x01, /* 00001798 "........" */ + 0x01,0x00,0x00,0x00,0x79,0x00,0x8A,0x50, /* 000017A0 "....y..P" */ + 0x52,0x52,0x30,0x0A,0x05,0x54,0x4D,0x50, /* 000017A8 "RR0..TMP" */ + 0x5F,0x70,0x50,0x52,0x51,0x31,0x60,0xA0, /* 000017B0 "_pPRQ1`." */ + 0x0B,0x95,0x60,0x0A,0x80,0x70,0x60,0x54, /* 000017B8 "..`..p`T" */ + 0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 000017C0 "MP_..p.T" */ + 0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 000017C8 "MP_.PRR0" */ + 0x14,0x17,0x5F,0x53,0x52,0x53,0x01,0x8A, /* 000017D0 ".._SRS.." */ + 0x68,0x0A,0x05,0x54,0x4D,0x50,0x5F,0x70, /* 000017D8 "h..TMP_p" */ + 0x54,0x4D,0x50,0x5F,0x50,0x52,0x51,0x31, /* 000017E0 "TMP_PRQ1" */ + 0x5B,0x82,0x4E,0x0B,0x4C,0x4E,0x4B,0x43, /* 000017E8 "[.N.LNKC" */ + 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000017F0 "._HID.A." */ + 0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 000017F8 "..._UID." */ + 0x03,0x08,0x5F,0x50,0x52,0x53,0x11,0x16, /* 00001800 ".._PRS.." */ + 0x0A,0x13,0x89,0x0E,0x00,0x09,0x03,0x05, /* 00001808 "........" */ + 0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x0B, /* 00001810 "........" */ + 0x00,0x00,0x00,0x79,0x00,0x14,0x1A,0x5F, /* 00001818 "...y..._" */ + 0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 00001820 "STA.p..`" */ + 0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 00001828 "..{..PRQ" */ + 0x32,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 00001830 "2ap..`.`" */ + 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 00001838 ".._DIS.}" */ + 0x50,0x52,0x51,0x32,0x0A,0x80,0x50,0x52, /* 00001840 "PRQ2..PR" */ + 0x51,0x32,0x14,0x45,0x04,0x5F,0x43,0x52, /* 00001848 "Q2.E._CR" */ + 0x53,0x00,0x08,0x50,0x52,0x52,0x30,0x11, /* 00001850 "S..PRR0." */ + 0x0E,0x0A,0x0B,0x89,0x06,0x00,0x09,0x01, /* 00001858 "........" */ + 0x01,0x00,0x00,0x00,0x79,0x00,0x8A,0x50, /* 00001860 "....y..P" */ + 0x52,0x52,0x30,0x0A,0x05,0x54,0x4D,0x50, /* 00001868 "RR0..TMP" */ + 0x5F,0x70,0x50,0x52,0x51,0x32,0x60,0xA0, /* 00001870 "_pPRQ2`." */ + 0x0B,0x95,0x60,0x0A,0x80,0x70,0x60,0x54, /* 00001878 "..`..p`T" */ + 0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 00001880 "MP_..p.T" */ + 0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 00001888 "MP_.PRR0" */ + 0x14,0x17,0x5F,0x53,0x52,0x53,0x01,0x8A, /* 00001890 ".._SRS.." */ + 0x68,0x0A,0x05,0x54,0x4D,0x50,0x5F,0x70, /* 00001898 "h..TMP_p" */ + 0x54,0x4D,0x50,0x5F,0x50,0x52,0x51,0x32, /* 000018A0 "TMP_PRQ2" */ + 0x5B,0x82,0x4E,0x0B,0x4C,0x4E,0x4B,0x44, /* 000018A8 "[.N.LNKD" */ + 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000018B0 "._HID.A." */ + 0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 000018B8 "..._UID." */ + 0x04,0x08,0x5F,0x50,0x52,0x53,0x11,0x16, /* 000018C0 ".._PRS.." */ + 0x0A,0x13,0x89,0x0E,0x00,0x09,0x03,0x05, /* 000018C8 "........" */ + 0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x0B, /* 000018D0 "........" */ + 0x00,0x00,0x00,0x79,0x00,0x14,0x1A,0x5F, /* 000018D8 "...y..._" */ + 0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 000018E0 "STA.p..`" */ + 0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 000018E8 "..{..PRQ" */ + 0x33,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 000018F0 "3ap..`.`" */ + 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 000018F8 ".._DIS.}" */ + 0x50,0x52,0x51,0x33,0x0A,0x80,0x50,0x52, /* 00001900 "PRQ3..PR" */ + 0x51,0x33,0x14,0x45,0x04,0x5F,0x43,0x52, /* 00001908 "Q3.E._CR" */ + 0x53,0x00,0x08,0x50,0x52,0x52,0x30,0x11, /* 00001910 "S..PRR0." */ + 0x0E,0x0A,0x0B,0x89,0x06,0x00,0x09,0x01, /* 00001918 "........" */ + 0x01,0x00,0x00,0x00,0x79,0x00,0x8A,0x50, /* 00001920 "....y..P" */ + 0x52,0x52,0x30,0x0A,0x05,0x54,0x4D,0x50, /* 00001928 "RR0..TMP" */ + 0x5F,0x70,0x50,0x52,0x51,0x33,0x60,0xA0, /* 00001930 "_pPRQ3`." */ + 0x0B,0x95,0x60,0x0A,0x80,0x70,0x60,0x54, /* 00001938 "..`..p`T" */ + 0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 00001940 "MP_..p.T" */ + 0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 00001948 "MP_.PRR0" */ + 0x14,0x17,0x5F,0x53,0x52,0x53,0x01,0x8A, /* 00001950 ".._SRS.." */ + 0x68,0x0A,0x05,0x54,0x4D,0x50,0x5F,0x70, /* 00001958 "h..TMP_p" */ + 0x54,0x4D,0x50,0x5F,0x50,0x52,0x51,0x33, /* 00001960 "TMP_PRQ3" */ + 0x5B,0x82,0x4E,0x09,0x4C,0x4E,0x4B,0x53, /* 00001968 "[.N.LNKS" */ + 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00001970 "._HID.A." */ + 0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 00001978 "..._UID." */ + 0x05,0x08,0x5F,0x50,0x52,0x53,0x11,0x0E, /* 00001980 ".._PRS.." */ + 0x0A,0x0B,0x89,0x06,0x00,0x09,0x01,0x09, /* 00001988 "........" */ + 0x00,0x00,0x00,0x79,0x00,0x14,0x1A,0x5F, /* 00001990 "...y..._" */ + 0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 00001998 "STA.p..`" */ + 0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 000019A0 "..{..PRQ" */ + 0x30,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 000019A8 "0ap..`.`" */ + 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 000019B0 ".._DIS.}" */ + 0x50,0x52,0x51,0x30,0x0A,0x80,0x50,0x52, /* 000019B8 "PRQ0..PR" */ + 0x51,0x30,0x14,0x45,0x04,0x5F,0x43,0x52, /* 000019C0 "Q0.E._CR" */ + 0x53,0x00,0x08,0x50,0x52,0x52,0x30,0x11, /* 000019C8 "S..PRR0." */ + 0x0E,0x0A,0x0B,0x89,0x06,0x00,0x09,0x01, /* 000019D0 "........" */ + 0x09,0x00,0x00,0x00,0x79,0x00,0x8A,0x50, /* 000019D8 "....y..P" */ + 0x52,0x52,0x30,0x0A,0x05,0x54,0x4D,0x50, /* 000019E0 "RR0..TMP" */ + 0x5F,0x70,0x50,0x52,0x51,0x30,0x60,0xA0, /* 000019E8 "_pPRQ0`." */ + 0x0B,0x95,0x60,0x0A,0x80,0x70,0x60,0x54, /* 000019F0 "..`..p`T" */ + 0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 000019F8 "MP_..p.T" */ + 0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 00001A00 "MP_.PRR0" */ + 0x08,0x5F,0x53,0x33,0x5F,0x12,0x06,0x04, /* 00001A08 "._S3_..." */ + 0x01,0x01,0x00,0x00,0x08,0x5F,0x53,0x34, /* 00001A10 "....._S4" */ + 0x5F,0x12,0x06,0x04,0x00,0x00,0x00,0x00, /* 00001A18 "_......." */ + 0x08,0x5F,0x53,0x35,0x5F,0x12,0x06,0x04, /* 00001A20 "._S5_..." */ + 0x00,0x00,0x00,0x00,0x10,0x49,0x0E,0x5F, /* 00001A28 ".....I._" */ + 0x53,0x42,0x5F,0x14,0x35,0x43,0x50,0x4D, /* 00001A30 "SB_.5CPM" */ + 0x41,0x01,0x70,0x83,0x88,0x43,0x50,0x4F, /* 00001A38 "A.p..CPO" */ + 0x4E,0x68,0x00,0x60,0x70,0x11,0x0B,0x0A, /* 00001A40 "Nh.`p..." */ + 0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00, /* 00001A48 "........" */ + 0x00,0x61,0x70,0x68,0x88,0x61,0x0A,0x02, /* 00001A50 ".aph.a.." */ + 0x00,0x70,0x68,0x88,0x61,0x0A,0x03,0x00, /* 00001A58 ".ph.a..." */ + 0x70,0x60,0x88,0x61,0x0A,0x04,0x00,0xA4, /* 00001A60 "p`.a...." */ + 0x61,0x14,0x1A,0x43,0x50,0x53,0x54,0x01, /* 00001A68 "a..CPST." */ + 0x70,0x83,0x88,0x43,0x50,0x4F,0x4E,0x68, /* 00001A70 "p..CPONh" */ + 0x00,0x60,0xA0,0x05,0x60,0xA4,0x0A,0x0F, /* 00001A78 ".`..`..." */ + 0xA1,0x03,0xA4,0x00,0x14,0x0A,0x43,0x50, /* 00001A80 "......CP" */ + 0x45,0x4A,0x02,0x5B,0x22,0x0A,0xC8,0x5B, /* 00001A88 "EJ.["..[" */ + 0x80,0x50,0x52,0x53,0x54,0x01,0x0B,0x00, /* 00001A90 ".PRST..." */ + 0xAF,0x0A,0x20,0x5B,0x81,0x0C,0x50,0x52, /* 00001A98 ".. [..PR" */ + 0x53,0x54,0x01,0x50,0x52,0x53,0x5F,0x40, /* 00001AA0 "ST.PRS_@" */ + 0x10,0x14,0x4C,0x06,0x50,0x52,0x53,0x43, /* 00001AA8 "..L.PRSC" */ + 0x00,0x70,0x50,0x52,0x53,0x5F,0x65,0x70, /* 00001AB0 ".pPRS_ep" */ + 0x00,0x62,0x70,0x00,0x60,0xA2,0x46,0x05, /* 00001AB8 ".bp.`.F." */ + 0x95,0x60,0x87,0x43,0x50,0x4F,0x4E,0x70, /* 00001AC0 ".`.CPONp" */ + 0x83,0x88,0x43,0x50,0x4F,0x4E,0x60,0x00, /* 00001AC8 "..CPON`." */ + 0x61,0xA0,0x0A,0x7B,0x60,0x0A,0x07,0x00, /* 00001AD0 "a..{`..." */ + 0x7A,0x62,0x01,0x62,0xA1,0x0C,0x70,0x83, /* 00001AD8 "zb.b..p." */ + 0x88,0x65,0x7A,0x60,0x0A,0x03,0x00,0x00, /* 00001AE0 ".ez`...." */ + 0x62,0x70,0x7B,0x62,0x01,0x00,0x63,0xA0, /* 00001AE8 "bp{b..c." */ + 0x22,0x92,0x93,0x61,0x63,0x70,0x63,0x88, /* 00001AF0 ""..acpc." */ + 0x43,0x50,0x4F,0x4E,0x60,0x00,0xA0,0x0A, /* 00001AF8 "CPON`..." */ + 0x93,0x63,0x01,0x4E,0x54,0x46,0x59,0x60, /* 00001B00 ".c.NTFY`" */ + 0x01,0xA1,0x08,0x4E,0x54,0x46,0x59,0x60, /* 00001B08 "...NTFY`" */ + 0x0A,0x03,0x75,0x60,0xA4,0x01,0x10,0x42, /* 00001B10 "..u`...B" */ + 0xA7,0x5F,0x47,0x50,0x45,0x08,0x5F,0x48, /* 00001B18 "._GPE._H" */ + 0x49,0x44,0x0D,0x41,0x43,0x50,0x49,0x30, /* 00001B20 "ID.ACPI0" */ + 0x30,0x30,0x36,0x00,0x14,0x08,0x5F,0x4C, /* 00001B28 "006..._L" */ + 0x30,0x30,0x00,0xA4,0x01,0x14,0x4C,0x9C, /* 00001B30 "00....L." */ + 0x5F,0x4C,0x30,0x31,0x00,0xA0,0x25,0x7B, /* 00001B38 "_L01..%{" */ + 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00001B40 "\/._SB_P" */ + 0x43,0x49,0x30,0x50,0x43,0x49,0x55,0x0A, /* 00001B48 "CI0PCIU." */ + 0x02,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53, /* 00001B50 "...\/._S" */ + 0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x31, /* 00001B58 "B_PCI0S1" */ + 0x5F,0x5F,0x01,0xA0,0x26,0x7B,0x5C,0x2F, /* 00001B60 "__..&{\/" */ + 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00001B68 "._SB_PCI" */ + 0x30,0x50,0x43,0x49,0x44,0x0A,0x02,0x00, /* 00001B70 "0PCID..." */ + 0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00001B78 ".\/._SB_" */ + 0x50,0x43,0x49,0x30,0x53,0x31,0x5F,0x5F, /* 00001B80 "PCI0S1__" */ + 0x0A,0x03,0xA0,0x25,0x7B,0x5C,0x2F,0x03, /* 00001B88 "...%{\/." */ + 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00001B90 "_SB_PCI0" */ + 0x50,0x43,0x49,0x55,0x0A,0x04,0x00,0x86, /* 00001B98 "PCIU...." */ + 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00001BA0 "\/._SB_P" */ + 0x43,0x49,0x30,0x53,0x32,0x5F,0x5F,0x01, /* 00001BA8 "CI0S2__." */ + 0xA0,0x26,0x7B,0x5C,0x2F,0x03,0x5F,0x53, /* 00001BB0 ".&{\/._S" */ + 0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43, /* 00001BB8 "B_PCI0PC" */ + 0x49,0x44,0x0A,0x04,0x00,0x86,0x5C,0x2F, /* 00001BC0 "ID....\/" */ + 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00001BC8 "._SB_PCI" */ + 0x30,0x53,0x32,0x5F,0x5F,0x0A,0x03,0xA0, /* 00001BD0 "0S2__..." */ + 0x25,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00001BD8 "%{\/._SB" */ + 0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49, /* 00001BE0 "_PCI0PCI" */ + 0x55,0x0A,0x08,0x00,0x86,0x5C,0x2F,0x03, /* 00001BE8 "U....\/." */ + 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00001BF0 "_SB_PCI0" */ + 0x53,0x33,0x5F,0x5F,0x01,0xA0,0x26,0x7B, /* 00001BF8 "S3__..&{" */ + 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00001C00 "\/._SB_P" */ + 0x43,0x49,0x30,0x50,0x43,0x49,0x44,0x0A, /* 00001C08 "CI0PCID." */ + 0x08,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53, /* 00001C10 "...\/._S" */ + 0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x33, /* 00001C18 "B_PCI0S3" */ + 0x5F,0x5F,0x0A,0x03,0xA0,0x25,0x7B,0x5C, /* 00001C20 "__...%{\" */ + 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00001C28 "/._SB_PC" */ + 0x49,0x30,0x50,0x43,0x49,0x55,0x0A,0x10, /* 00001C30 "I0PCIU.." */ + 0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00001C38 "..\/._SB" */ + 0x5F,0x50,0x43,0x49,0x30,0x53,0x34,0x5F, /* 00001C40 "_PCI0S4_" */ + 0x5F,0x01,0xA0,0x26,0x7B,0x5C,0x2F,0x03, /* 00001C48 "_..&{\/." */ + 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00001C50 "_SB_PCI0" */ + 0x50,0x43,0x49,0x44,0x0A,0x10,0x00,0x86, /* 00001C58 "PCID...." */ + 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00001C60 "\/._SB_P" */ + 0x43,0x49,0x30,0x53,0x34,0x5F,0x5F,0x0A, /* 00001C68 "CI0S4__." */ + 0x03,0xA0,0x25,0x7B,0x5C,0x2F,0x03,0x5F, /* 00001C70 "..%{\/._" */ + 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50, /* 00001C78 "SB_PCI0P" */ + 0x43,0x49,0x55,0x0A,0x20,0x00,0x86,0x5C, /* 00001C80 "CIU. ..\" */ + 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00001C88 "/._SB_PC" */ + 0x49,0x30,0x53,0x35,0x5F,0x5F,0x01,0xA0, /* 00001C90 "I0S5__.." */ + 0x26,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00001C98 "&{\/._SB" */ + 0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49, /* 00001CA0 "_PCI0PCI" */ + 0x44,0x0A,0x20,0x00,0x86,0x5C,0x2F,0x03, /* 00001CA8 "D. ..\/." */ + 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00001CB0 "_SB_PCI0" */ + 0x53,0x35,0x5F,0x5F,0x0A,0x03,0xA0,0x25, /* 00001CB8 "S5__...%" */ + 0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00001CC0 "{\/._SB_" */ + 0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x55, /* 00001CC8 "PCI0PCIU" */ + 0x0A,0x40,0x00,0x86,0x5C,0x2F,0x03,0x5F, /* 00001CD0 ".@..\/._" */ + 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53, /* 00001CD8 "SB_PCI0S" */ + 0x36,0x5F,0x5F,0x01,0xA0,0x26,0x7B,0x5C, /* 00001CE0 "6__..&{\" */ + 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00001CE8 "/._SB_PC" */ + 0x49,0x30,0x50,0x43,0x49,0x44,0x0A,0x40, /* 00001CF0 "I0PCID.@" */ + 0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00001CF8 "..\/._SB" */ + 0x5F,0x50,0x43,0x49,0x30,0x53,0x36,0x5F, /* 00001D00 "_PCI0S6_" */ + 0x5F,0x0A,0x03,0xA0,0x25,0x7B,0x5C,0x2F, /* 00001D08 "_...%{\/" */ + 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00001D10 "._SB_PCI" */ + 0x30,0x50,0x43,0x49,0x55,0x0A,0x80,0x00, /* 00001D18 "0PCIU..." */ + 0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00001D20 ".\/._SB_" */ + 0x50,0x43,0x49,0x30,0x53,0x37,0x5F,0x5F, /* 00001D28 "PCI0S7__" */ + 0x01,0xA0,0x26,0x7B,0x5C,0x2F,0x03,0x5F, /* 00001D30 "..&{\/._" */ + 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50, /* 00001D38 "SB_PCI0P" */ + 0x43,0x49,0x44,0x0A,0x80,0x00,0x86,0x5C, /* 00001D40 "CID....\" */ + 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00001D48 "/._SB_PC" */ + 0x49,0x30,0x53,0x37,0x5F,0x5F,0x0A,0x03, /* 00001D50 "I0S7__.." */ + 0xA0,0x26,0x7B,0x5C,0x2F,0x03,0x5F,0x53, /* 00001D58 ".&{\/._S" */ + 0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43, /* 00001D60 "B_PCI0PC" */ + 0x49,0x55,0x0B,0x00,0x01,0x00,0x86,0x5C, /* 00001D68 "IU.....\" */ + 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00001D70 "/._SB_PC" */ + 0x49,0x30,0x53,0x38,0x5F,0x5F,0x01,0xA0, /* 00001D78 "I0S8__.." */ + 0x27,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00001D80 "'{\/._SB" */ + 0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49, /* 00001D88 "_PCI0PCI" */ + 0x44,0x0B,0x00,0x01,0x00,0x86,0x5C,0x2F, /* 00001D90 "D.....\/" */ + 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00001D98 "._SB_PCI" */ + 0x30,0x53,0x38,0x5F,0x5F,0x0A,0x03,0xA0, /* 00001DA0 "0S8__..." */ + 0x26,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00001DA8 "&{\/._SB" */ + 0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49, /* 00001DB0 "_PCI0PCI" */ + 0x55,0x0B,0x00,0x02,0x00,0x86,0x5C,0x2F, /* 00001DB8 "U.....\/" */ + 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00001DC0 "._SB_PCI" */ + 0x30,0x53,0x39,0x5F,0x5F,0x01,0xA0,0x27, /* 00001DC8 "0S9__..'" */ + 0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00001DD0 "{\/._SB_" */ + 0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x44, /* 00001DD8 "PCI0PCID" */ + 0x0B,0x00,0x02,0x00,0x86,0x5C,0x2F,0x03, /* 00001DE0 ".....\/." */ + 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00001DE8 "_SB_PCI0" */ + 0x53,0x39,0x5F,0x5F,0x0A,0x03,0xA0,0x26, /* 00001DF0 "S9__...&" */ + 0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00001DF8 "{\/._SB_" */ + 0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x55, /* 00001E00 "PCI0PCIU" */ + 0x0B,0x00,0x04,0x00,0x86,0x5C,0x2F,0x03, /* 00001E08 ".....\/." */ + 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00001E10 "_SB_PCI0" */ + 0x53,0x31,0x30,0x5F,0x01,0xA0,0x27,0x7B, /* 00001E18 "S10_..'{" */ + 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00001E20 "\/._SB_P" */ + 0x43,0x49,0x30,0x50,0x43,0x49,0x44,0x0B, /* 00001E28 "CI0PCID." */ + 0x00,0x04,0x00,0x86,0x5C,0x2F,0x03,0x5F, /* 00001E30 "....\/._" */ + 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53, /* 00001E38 "SB_PCI0S" */ + 0x31,0x30,0x5F,0x0A,0x03,0xA0,0x26,0x7B, /* 00001E40 "10_...&{" */ + 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00001E48 "\/._SB_P" */ + 0x43,0x49,0x30,0x50,0x43,0x49,0x55,0x0B, /* 00001E50 "CI0PCIU." */ + 0x00,0x08,0x00,0x86,0x5C,0x2F,0x03,0x5F, /* 00001E58 "....\/._" */ + 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53, /* 00001E60 "SB_PCI0S" */ + 0x31,0x31,0x5F,0x01,0xA0,0x27,0x7B,0x5C, /* 00001E68 "11_..'{\" */ + 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00001E70 "/._SB_PC" */ + 0x49,0x30,0x50,0x43,0x49,0x44,0x0B,0x00, /* 00001E78 "I0PCID.." */ + 0x08,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53, /* 00001E80 "...\/._S" */ + 0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x31, /* 00001E88 "B_PCI0S1" */ + 0x31,0x5F,0x0A,0x03,0xA0,0x26,0x7B,0x5C, /* 00001E90 "1_...&{\" */ + 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00001E98 "/._SB_PC" */ + 0x49,0x30,0x50,0x43,0x49,0x55,0x0B,0x00, /* 00001EA0 "I0PCIU.." */ + 0x10,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53, /* 00001EA8 "...\/._S" */ + 0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x31, /* 00001EB0 "B_PCI0S1" */ + 0x32,0x5F,0x01,0xA0,0x27,0x7B,0x5C,0x2F, /* 00001EB8 "2_..'{\/" */ + 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00001EC0 "._SB_PCI" */ + 0x30,0x50,0x43,0x49,0x44,0x0B,0x00,0x10, /* 00001EC8 "0PCID..." */ + 0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00001ED0 "..\/._SB" */ + 0x5F,0x50,0x43,0x49,0x30,0x53,0x31,0x32, /* 00001ED8 "_PCI0S12" */ + 0x5F,0x0A,0x03,0xA0,0x26,0x7B,0x5C,0x2F, /* 00001EE0 "_...&{\/" */ + 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00001EE8 "._SB_PCI" */ + 0x30,0x50,0x43,0x49,0x55,0x0B,0x00,0x20, /* 00001EF0 "0PCIU.. " */ + 0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00001EF8 "..\/._SB" */ + 0x5F,0x50,0x43,0x49,0x30,0x53,0x31,0x33, /* 00001F00 "_PCI0S13" */ + 0x5F,0x01,0xA0,0x27,0x7B,0x5C,0x2F,0x03, /* 00001F08 "_..'{\/." */ + 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00001F10 "_SB_PCI0" */ + 0x50,0x43,0x49,0x44,0x0B,0x00,0x20,0x00, /* 00001F18 "PCID.. ." */ + 0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00001F20 ".\/._SB_" */ + 0x50,0x43,0x49,0x30,0x53,0x31,0x33,0x5F, /* 00001F28 "PCI0S13_" */ + 0x0A,0x03,0xA0,0x26,0x7B,0x5C,0x2F,0x03, /* 00001F30 "...&{\/." */ + 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00001F38 "_SB_PCI0" */ + 0x50,0x43,0x49,0x55,0x0B,0x00,0x40,0x00, /* 00001F40 "PCIU..@." */ + 0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00001F48 ".\/._SB_" */ + 0x50,0x43,0x49,0x30,0x53,0x31,0x34,0x5F, /* 00001F50 "PCI0S14_" */ + 0x01,0xA0,0x27,0x7B,0x5C,0x2F,0x03,0x5F, /* 00001F58 "..'{\/._" */ + 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50, /* 00001F60 "SB_PCI0P" */ + 0x43,0x49,0x44,0x0B,0x00,0x40,0x00,0x86, /* 00001F68 "CID..@.." */ + 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00001F70 "\/._SB_P" */ + 0x43,0x49,0x30,0x53,0x31,0x34,0x5F,0x0A, /* 00001F78 "CI0S14_." */ + 0x03,0xA0,0x26,0x7B,0x5C,0x2F,0x03,0x5F, /* 00001F80 "..&{\/._" */ + 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50, /* 00001F88 "SB_PCI0P" */ + 0x43,0x49,0x55,0x0B,0x00,0x80,0x00,0x86, /* 00001F90 "CIU....." */ + 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00001F98 "\/._SB_P" */ + 0x43,0x49,0x30,0x53,0x31,0x35,0x5F,0x01, /* 00001FA0 "CI0S15_." */ + 0xA0,0x27,0x7B,0x5C,0x2F,0x03,0x5F,0x53, /* 00001FA8 ".'{\/._S" */ + 0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43, /* 00001FB0 "B_PCI0PC" */ + 0x49,0x44,0x0B,0x00,0x80,0x00,0x86,0x5C, /* 00001FB8 "ID.....\" */ + 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00001FC0 "/._SB_PC" */ + 0x49,0x30,0x53,0x31,0x35,0x5F,0x0A,0x03, /* 00001FC8 "I0S15_.." */ + 0xA0,0x28,0x7B,0x5C,0x2F,0x03,0x5F,0x53, /* 00001FD0 ".({\/._S" */ + 0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43, /* 00001FD8 "B_PCI0PC" */ + 0x49,0x55,0x0C,0x00,0x00,0x01,0x00,0x00, /* 00001FE0 "IU......" */ + 0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00001FE8 ".\/._SB_" */ + 0x50,0x43,0x49,0x30,0x53,0x31,0x36,0x5F, /* 00001FF0 "PCI0S16_" */ + 0x01,0xA0,0x29,0x7B,0x5C,0x2F,0x03,0x5F, /* 00001FF8 "..){\/._" */ + 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50, /* 00002000 "SB_PCI0P" */ + 0x43,0x49,0x44,0x0C,0x00,0x00,0x01,0x00, /* 00002008 "CID....." */ + 0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00002010 "..\/._SB" */ + 0x5F,0x50,0x43,0x49,0x30,0x53,0x31,0x36, /* 00002018 "_PCI0S16" */ + 0x5F,0x0A,0x03,0xA0,0x28,0x7B,0x5C,0x2F, /* 00002020 "_...({\/" */ + 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00002028 "._SB_PCI" */ + 0x30,0x50,0x43,0x49,0x55,0x0C,0x00,0x00, /* 00002030 "0PCIU..." */ + 0x02,0x00,0x00,0x86,0x5C,0x2F,0x03,0x5F, /* 00002038 "....\/._" */ + 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53, /* 00002040 "SB_PCI0S" */ + 0x31,0x37,0x5F,0x01,0xA0,0x29,0x7B,0x5C, /* 00002048 "17_..){\" */ + 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00002050 "/._SB_PC" */ + 0x49,0x30,0x50,0x43,0x49,0x44,0x0C,0x00, /* 00002058 "I0PCID.." */ + 0x00,0x02,0x00,0x00,0x86,0x5C,0x2F,0x03, /* 00002060 ".....\/." */ + 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00002068 "_SB_PCI0" */ + 0x53,0x31,0x37,0x5F,0x0A,0x03,0xA0,0x28, /* 00002070 "S17_...(" */ + 0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00002078 "{\/._SB_" */ + 0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x55, /* 00002080 "PCI0PCIU" */ + 0x0C,0x00,0x00,0x04,0x00,0x00,0x86,0x5C, /* 00002088 ".......\" */ + 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00002090 "/._SB_PC" */ + 0x49,0x30,0x53,0x31,0x38,0x5F,0x01,0xA0, /* 00002098 "I0S18_.." */ + 0x29,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 000020A0 "){\/._SB" */ + 0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49, /* 000020A8 "_PCI0PCI" */ + 0x44,0x0C,0x00,0x00,0x04,0x00,0x00,0x86, /* 000020B0 "D......." */ + 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 000020B8 "\/._SB_P" */ + 0x43,0x49,0x30,0x53,0x31,0x38,0x5F,0x0A, /* 000020C0 "CI0S18_." */ + 0x03,0xA0,0x28,0x7B,0x5C,0x2F,0x03,0x5F, /* 000020C8 "..({\/._" */ + 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50, /* 000020D0 "SB_PCI0P" */ + 0x43,0x49,0x55,0x0C,0x00,0x00,0x08,0x00, /* 000020D8 "CIU....." */ + 0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 000020E0 "..\/._SB" */ + 0x5F,0x50,0x43,0x49,0x30,0x53,0x31,0x39, /* 000020E8 "_PCI0S19" */ + 0x5F,0x01,0xA0,0x29,0x7B,0x5C,0x2F,0x03, /* 000020F0 "_..){\/." */ + 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 000020F8 "_SB_PCI0" */ + 0x50,0x43,0x49,0x44,0x0C,0x00,0x00,0x08, /* 00002100 "PCID...." */ + 0x00,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53, /* 00002108 "...\/._S" */ + 0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x31, /* 00002110 "B_PCI0S1" */ + 0x39,0x5F,0x0A,0x03,0xA0,0x28,0x7B,0x5C, /* 00002118 "9_...({\" */ + 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00002120 "/._SB_PC" */ + 0x49,0x30,0x50,0x43,0x49,0x55,0x0C,0x00, /* 00002128 "I0PCIU.." */ + 0x00,0x10,0x00,0x00,0x86,0x5C,0x2F,0x03, /* 00002130 ".....\/." */ + 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00002138 "_SB_PCI0" */ + 0x53,0x32,0x30,0x5F,0x01,0xA0,0x29,0x7B, /* 00002140 "S20_..){" */ + 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00002148 "\/._SB_P" */ + 0x43,0x49,0x30,0x50,0x43,0x49,0x44,0x0C, /* 00002150 "CI0PCID." */ + 0x00,0x00,0x10,0x00,0x00,0x86,0x5C,0x2F, /* 00002158 "......\/" */ + 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00002160 "._SB_PCI" */ + 0x30,0x53,0x32,0x30,0x5F,0x0A,0x03,0xA0, /* 00002168 "0S20_..." */ + 0x28,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00002170 "({\/._SB" */ + 0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49, /* 00002178 "_PCI0PCI" */ + 0x55,0x0C,0x00,0x00,0x20,0x00,0x00,0x86, /* 00002180 "U... ..." */ + 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00002188 "\/._SB_P" */ + 0x43,0x49,0x30,0x53,0x32,0x31,0x5F,0x01, /* 00002190 "CI0S21_." */ + 0xA0,0x29,0x7B,0x5C,0x2F,0x03,0x5F,0x53, /* 00002198 ".){\/._S" */ + 0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43, /* 000021A0 "B_PCI0PC" */ + 0x49,0x44,0x0C,0x00,0x00,0x20,0x00,0x00, /* 000021A8 "ID... .." */ + 0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 000021B0 ".\/._SB_" */ + 0x50,0x43,0x49,0x30,0x53,0x32,0x31,0x5F, /* 000021B8 "PCI0S21_" */ + 0x0A,0x03,0xA0,0x28,0x7B,0x5C,0x2F,0x03, /* 000021C0 "...({\/." */ + 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 000021C8 "_SB_PCI0" */ + 0x50,0x43,0x49,0x55,0x0C,0x00,0x00,0x40, /* 000021D0 "PCIU...@" */ + 0x00,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53, /* 000021D8 "...\/._S" */ + 0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x32, /* 000021E0 "B_PCI0S2" */ + 0x32,0x5F,0x01,0xA0,0x29,0x7B,0x5C,0x2F, /* 000021E8 "2_..){\/" */ + 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 000021F0 "._SB_PCI" */ + 0x30,0x50,0x43,0x49,0x44,0x0C,0x00,0x00, /* 000021F8 "0PCID..." */ + 0x40,0x00,0x00,0x86,0x5C,0x2F,0x03,0x5F, /* 00002200 "@...\/._" */ + 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53, /* 00002208 "SB_PCI0S" */ + 0x32,0x32,0x5F,0x0A,0x03,0xA0,0x28,0x7B, /* 00002210 "22_...({" */ + 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00002218 "\/._SB_P" */ + 0x43,0x49,0x30,0x50,0x43,0x49,0x55,0x0C, /* 00002220 "CI0PCIU." */ + 0x00,0x00,0x80,0x00,0x00,0x86,0x5C,0x2F, /* 00002228 "......\/" */ + 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00002230 "._SB_PCI" */ + 0x30,0x53,0x32,0x33,0x5F,0x01,0xA0,0x29, /* 00002238 "0S23_..)" */ + 0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00002240 "{\/._SB_" */ + 0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x44, /* 00002248 "PCI0PCID" */ + 0x0C,0x00,0x00,0x80,0x00,0x00,0x86,0x5C, /* 00002250 ".......\" */ + 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00002258 "/._SB_PC" */ + 0x49,0x30,0x53,0x32,0x33,0x5F,0x0A,0x03, /* 00002260 "I0S23_.." */ + 0xA0,0x28,0x7B,0x5C,0x2F,0x03,0x5F,0x53, /* 00002268 ".({\/._S" */ + 0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43, /* 00002270 "B_PCI0PC" */ + 0x49,0x55,0x0C,0x00,0x00,0x00,0x01,0x00, /* 00002278 "IU......" */ + 0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00002280 ".\/._SB_" */ + 0x50,0x43,0x49,0x30,0x53,0x32,0x34,0x5F, /* 00002288 "PCI0S24_" */ + 0x01,0xA0,0x29,0x7B,0x5C,0x2F,0x03,0x5F, /* 00002290 "..){\/._" */ + 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50, /* 00002298 "SB_PCI0P" */ + 0x43,0x49,0x44,0x0C,0x00,0x00,0x00,0x01, /* 000022A0 "CID....." */ + 0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 000022A8 "..\/._SB" */ + 0x5F,0x50,0x43,0x49,0x30,0x53,0x32,0x34, /* 000022B0 "_PCI0S24" */ + 0x5F,0x0A,0x03,0xA0,0x28,0x7B,0x5C,0x2F, /* 000022B8 "_...({\/" */ + 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 000022C0 "._SB_PCI" */ + 0x30,0x50,0x43,0x49,0x55,0x0C,0x00,0x00, /* 000022C8 "0PCIU..." */ + 0x00,0x02,0x00,0x86,0x5C,0x2F,0x03,0x5F, /* 000022D0 "....\/._" */ + 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53, /* 000022D8 "SB_PCI0S" */ + 0x32,0x35,0x5F,0x01,0xA0,0x29,0x7B,0x5C, /* 000022E0 "25_..){\" */ + 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 000022E8 "/._SB_PC" */ + 0x49,0x30,0x50,0x43,0x49,0x44,0x0C,0x00, /* 000022F0 "I0PCID.." */ + 0x00,0x00,0x02,0x00,0x86,0x5C,0x2F,0x03, /* 000022F8 ".....\/." */ + 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00002300 "_SB_PCI0" */ + 0x53,0x32,0x35,0x5F,0x0A,0x03,0xA0,0x28, /* 00002308 "S25_...(" */ + 0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00002310 "{\/._SB_" */ + 0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x55, /* 00002318 "PCI0PCIU" */ + 0x0C,0x00,0x00,0x00,0x04,0x00,0x86,0x5C, /* 00002320 ".......\" */ + 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00002328 "/._SB_PC" */ + 0x49,0x30,0x53,0x32,0x36,0x5F,0x01,0xA0, /* 00002330 "I0S26_.." */ + 0x29,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00002338 "){\/._SB" */ + 0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49, /* 00002340 "_PCI0PCI" */ + 0x44,0x0C,0x00,0x00,0x00,0x04,0x00,0x86, /* 00002348 "D......." */ + 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00002350 "\/._SB_P" */ + 0x43,0x49,0x30,0x53,0x32,0x36,0x5F,0x0A, /* 00002358 "CI0S26_." */ + 0x03,0xA0,0x28,0x7B,0x5C,0x2F,0x03,0x5F, /* 00002360 "..({\/._" */ + 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50, /* 00002368 "SB_PCI0P" */ + 0x43,0x49,0x55,0x0C,0x00,0x00,0x00,0x08, /* 00002370 "CIU....." */ + 0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00002378 "..\/._SB" */ + 0x5F,0x50,0x43,0x49,0x30,0x53,0x32,0x37, /* 00002380 "_PCI0S27" */ + 0x5F,0x01,0xA0,0x29,0x7B,0x5C,0x2F,0x03, /* 00002388 "_..){\/." */ + 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00002390 "_SB_PCI0" */ + 0x50,0x43,0x49,0x44,0x0C,0x00,0x00,0x00, /* 00002398 "PCID...." */ + 0x08,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53, /* 000023A0 "...\/._S" */ + 0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x32, /* 000023A8 "B_PCI0S2" */ + 0x37,0x5F,0x0A,0x03,0xA0,0x28,0x7B,0x5C, /* 000023B0 "7_...({\" */ + 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 000023B8 "/._SB_PC" */ + 0x49,0x30,0x50,0x43,0x49,0x55,0x0C,0x00, /* 000023C0 "I0PCIU.." */ + 0x00,0x00,0x10,0x00,0x86,0x5C,0x2F,0x03, /* 000023C8 ".....\/." */ + 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 000023D0 "_SB_PCI0" */ + 0x53,0x32,0x38,0x5F,0x01,0xA0,0x29,0x7B, /* 000023D8 "S28_..){" */ + 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 000023E0 "\/._SB_P" */ + 0x43,0x49,0x30,0x50,0x43,0x49,0x44,0x0C, /* 000023E8 "CI0PCID." */ + 0x00,0x00,0x00,0x10,0x00,0x86,0x5C,0x2F, /* 000023F0 "......\/" */ + 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 000023F8 "._SB_PCI" */ + 0x30,0x53,0x32,0x38,0x5F,0x0A,0x03,0xA0, /* 00002400 "0S28_..." */ + 0x28,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00002408 "({\/._SB" */ + 0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49, /* 00002410 "_PCI0PCI" */ + 0x55,0x0C,0x00,0x00,0x00,0x20,0x00,0x86, /* 00002418 "U.... .." */ + 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00002420 "\/._SB_P" */ + 0x43,0x49,0x30,0x53,0x32,0x39,0x5F,0x01, /* 00002428 "CI0S29_." */ + 0xA0,0x29,0x7B,0x5C,0x2F,0x03,0x5F,0x53, /* 00002430 ".){\/._S" */ + 0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43, /* 00002438 "B_PCI0PC" */ + 0x49,0x44,0x0C,0x00,0x00,0x00,0x20,0x00, /* 00002440 "ID.... ." */ + 0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00002448 ".\/._SB_" */ + 0x50,0x43,0x49,0x30,0x53,0x32,0x39,0x5F, /* 00002450 "PCI0S29_" */ + 0x0A,0x03,0xA0,0x28,0x7B,0x5C,0x2F,0x03, /* 00002458 "...({\/." */ + 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00002460 "_SB_PCI0" */ + 0x50,0x43,0x49,0x55,0x0C,0x00,0x00,0x00, /* 00002468 "PCIU...." */ + 0x40,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53, /* 00002470 "@..\/._S" */ + 0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x33, /* 00002478 "B_PCI0S3" */ + 0x30,0x5F,0x01,0xA0,0x29,0x7B,0x5C,0x2F, /* 00002480 "0_..){\/" */ + 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00002488 "._SB_PCI" */ + 0x30,0x50,0x43,0x49,0x44,0x0C,0x00,0x00, /* 00002490 "0PCID..." */ + 0x00,0x40,0x00,0x86,0x5C,0x2F,0x03,0x5F, /* 00002498 ".@..\/._" */ + 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53, /* 000024A0 "SB_PCI0S" */ + 0x33,0x30,0x5F,0x0A,0x03,0xA0,0x28,0x7B, /* 000024A8 "30_...({" */ + 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 000024B0 "\/._SB_P" */ + 0x43,0x49,0x30,0x50,0x43,0x49,0x55,0x0C, /* 000024B8 "CI0PCIU." */ + 0x00,0x00,0x00,0x80,0x00,0x86,0x5C,0x2F, /* 000024C0 "......\/" */ + 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 000024C8 "._SB_PCI" */ + 0x30,0x53,0x33,0x31,0x5F,0x01,0xA0,0x29, /* 000024D0 "0S31_..)" */ + 0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 000024D8 "{\/._SB_" */ + 0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x44, /* 000024E0 "PCI0PCID" */ + 0x0C,0x00,0x00,0x00,0x80,0x00,0x86,0x5C, /* 000024E8 ".......\" */ + 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 000024F0 "/._SB_PC" */ + 0x49,0x30,0x53,0x33,0x31,0x5F,0x0A,0x03, /* 000024F8 "I0S31_.." */ + 0xA4,0x01,0x14,0x11,0x5F,0x4C,0x30,0x32, /* 00002500 "...._L02" */ + 0x00,0xA4,0x5C,0x2E,0x5F,0x53,0x42,0x5F, /* 00002508 "..\._SB_" */ + 0x50,0x52,0x53,0x43,0x14,0x08,0x5F,0x4C, /* 00002510 "PRSC.._L" */ + 0x30,0x33,0x00,0xA4,0x01,0x14,0x08,0x5F, /* 00002518 "03....._" */ + 0x4C,0x30,0x34,0x00,0xA4,0x01,0x14,0x08, /* 00002520 "L04....." */ + 0x5F,0x4C,0x30,0x35,0x00,0xA4,0x01,0x14, /* 00002528 "_L05...." */ + 0x08,0x5F,0x4C,0x30,0x36,0x00,0xA4,0x01, /* 00002530 "._L06..." */ + 0x14,0x08,0x5F,0x4C,0x30,0x37,0x00,0xA4, /* 00002538 ".._L07.." */ + 0x01,0x14,0x08,0x5F,0x4C,0x30,0x38,0x00, /* 00002540 "..._L08." */ + 0xA4,0x01,0x14,0x08,0x5F,0x4C,0x30,0x39, /* 00002548 "...._L09" */ + 0x00,0xA4,0x01,0x14,0x08,0x5F,0x4C,0x30, /* 00002550 "....._L0" */ + 0x41,0x00,0xA4,0x01,0x14,0x08,0x5F,0x4C, /* 00002558 "A....._L" */ + 0x30,0x42,0x00,0xA4,0x01,0x14,0x08,0x5F, /* 00002560 "0B....._" */ + 0x4C,0x30,0x43,0x00,0xA4,0x01,0x14,0x08, /* 00002568 "L0C....." */ + 0x5F,0x4C,0x30,0x44,0x00,0xA4,0x01,0x14, /* 00002570 "_L0D...." */ + 0x08,0x5F,0x4C,0x30,0x45,0x00,0xA4,0x01, /* 00002578 "._L0E..." */ + 0x14,0x08,0x5F,0x4C,0x30,0x46,0x00,0xA4, /* 00002580 ".._L0F.." */ + 0x01 /* 00002588 "." */ +}; diff --git a/bios/seabios/src/acpi.c b/bios/seabios/src/acpi.c new file mode 100644 index 0000000..95575a1 --- /dev/null +++ b/bios/seabios/src/acpi.c @@ -0,0 +1,750 @@ +// Support for generating ACPI tables (on emulators) +// +// Copyright (C) 2008-2010 Kevin O'Connor +// Copyright (C) 2006 Fabrice Bellard +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "acpi.h" // struct rsdp_descriptor +#include "util.h" // memcpy +#include "pci.h" // pci_find_init_device +#include "biosvar.h" // GET_EBDA +#include "pci_ids.h" // PCI_VENDOR_ID_INTEL +#include "pci_regs.h" // PCI_INTERRUPT_LINE +#include "paravirt.h" + +/****************************************************/ +/* ACPI tables init */ + +/* Table structure from Linux kernel (the ACPI tables are under the + BSD license) */ + +struct acpi_table_header /* ACPI common table header */ +{ + ACPI_TABLE_HEADER_DEF +} PACKED; + +/* + * ACPI 1.0 Root System Description Table (RSDT) + */ +#define RSDT_SIGNATURE 0x54445352 // RSDT +struct rsdt_descriptor_rev1 +{ + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ + u32 table_offset_entry[0]; /* Array of pointers to other */ + /* ACPI tables */ +} PACKED; + +/* + * ACPI 1.0 Firmware ACPI Control Structure (FACS) + */ +#define FACS_SIGNATURE 0x53434146 // FACS +struct facs_descriptor_rev1 +{ + u32 signature; /* ACPI Signature */ + u32 length; /* Length of structure, in bytes */ + u32 hardware_signature; /* Hardware configuration signature */ + u32 firmware_waking_vector; /* ACPI OS waking vector */ + u32 global_lock; /* Global Lock */ + u32 S4bios_f : 1; /* Indicates if S4BIOS support is present */ + u32 reserved1 : 31; /* Must be 0 */ + u8 resverved3 [40]; /* Reserved - must be zero */ +} PACKED; + + +/* + * MADT values and structures + */ + +/* Values for MADT PCATCompat */ + +#define DUAL_PIC 0 +#define MULTIPLE_APIC 1 + + +/* Master MADT */ + +#define APIC_SIGNATURE 0x43495041 // APIC +struct multiple_apic_table +{ + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ + u32 local_apic_address; /* Physical address of local APIC */ +#if 0 + u32 PCATcompat : 1; /* A one indicates system also has dual 8259s */ + u32 reserved1 : 31; +#else + u32 flags; +#endif +} PACKED; + + +/* Values for Type in APIC sub-headers */ + +#define APIC_PROCESSOR 0 +#define APIC_IO 1 +#define APIC_XRUPT_OVERRIDE 2 +#define APIC_NMI 3 +#define APIC_LOCAL_NMI 4 +#define APIC_ADDRESS_OVERRIDE 5 +#define APIC_IO_SAPIC 6 +#define APIC_LOCAL_SAPIC 7 +#define APIC_XRUPT_SOURCE 8 +#define APIC_RESERVED 9 /* 9 and greater are reserved */ + +/* + * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE) + */ +#define ACPI_SUB_HEADER_DEF /* Common ACPI sub-structure header */\ + u8 type; \ + u8 length; + +/* Sub-structures for MADT */ + +struct madt_processor_apic +{ + ACPI_SUB_HEADER_DEF + u8 processor_id; /* ACPI processor id */ + u8 local_apic_id; /* Processor's local APIC id */ +#if 0 + u32 processor_enabled: 1; /* Processor is usable if set */ + u32 reserved2 : 31; /* Reserved, must be zero */ +#else + u32 flags; +#endif +} PACKED; + +struct madt_io_apic +{ + ACPI_SUB_HEADER_DEF + u8 io_apic_id; /* I/O APIC ID */ + u8 reserved; /* Reserved - must be zero */ + u32 address; /* APIC physical address */ + u32 interrupt; /* Global system interrupt where INTI + * lines start */ +} PACKED; + +/* IRQs 5,9,10,11 */ +#define PCI_ISA_IRQ_MASK 0x0e20 + +struct madt_intsrcovr { + ACPI_SUB_HEADER_DEF + u8 bus; + u8 source; + u32 gsi; + u16 flags; +} PACKED; + +/* + * ACPI 2.0 Generic Address Space definition. + */ +struct acpi_20_generic_address { + u8 address_space_id; + u8 register_bit_width; + u8 register_bit_offset; + u8 reserved; + u64 address; +} PACKED; + +/* + * HPET Description Table + */ +struct acpi_20_hpet { + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ + u32 timer_block_id; + struct acpi_20_generic_address addr; + u8 hpet_number; + u16 min_tick; + u8 page_protect; +} PACKED; + +#define HPET_ID 0x000 +#define HPET_PERIOD 0x004 + +/* + * SRAT (NUMA topology description) table + */ + +#define SRAT_PROCESSOR 0 +#define SRAT_MEMORY 1 + +struct system_resource_affinity_table +{ + ACPI_TABLE_HEADER_DEF + u32 reserved1; + u32 reserved2[2]; +} PACKED; + +struct srat_processor_affinity +{ + ACPI_SUB_HEADER_DEF + u8 proximity_lo; + u8 local_apic_id; + u32 flags; + u8 local_sapic_eid; + u8 proximity_hi[3]; + u32 reserved; +} PACKED; + +struct srat_memory_affinity +{ + ACPI_SUB_HEADER_DEF + u8 proximity[4]; + u16 reserved1; + u32 base_addr_low,base_addr_high; + u32 length_low,length_high; + u32 reserved2; + u32 flags; + u32 reserved3[2]; +} PACKED; + +#include "acpi-dsdt.hex" + +static void +build_header(struct acpi_table_header *h, u32 sig, int len, u8 rev) +{ + h->signature = sig; + h->length = cpu_to_le32(len); + h->revision = rev; + memcpy(h->oem_id, CONFIG_APPNAME6, 6); + memcpy(h->oem_table_id, CONFIG_APPNAME4, 4); + memcpy(h->oem_table_id + 4, (void*)&sig, 4); + h->oem_revision = cpu_to_le32(1); + memcpy(h->asl_compiler_id, CONFIG_APPNAME4, 4); + h->asl_compiler_revision = cpu_to_le32(1); + h->checksum -= checksum(h, len); +} + +#define PIIX4_ACPI_ENABLE 0xf1 +#define PIIX4_ACPI_DISABLE 0xf0 +#define PIIX4_GPE0_BLK 0xafe0 +#define PIIX4_GPE0_BLK_LEN 4 + +static void piix4_fadt_init(struct pci_device *pci, void *arg) +{ + struct fadt_descriptor_rev1 *fadt = arg; + fadt->acpi_enable = PIIX4_ACPI_ENABLE; + fadt->acpi_disable = PIIX4_ACPI_DISABLE; + fadt->gpe0_blk = cpu_to_le32(PIIX4_GPE0_BLK); + fadt->gpe0_blk_len = PIIX4_GPE0_BLK_LEN; +} + +static const struct pci_device_id fadt_init_tbl[] = { + /* PIIX4 Power Management device (for ACPI) */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, + piix4_fadt_init), + + PCI_DEVICE_END +}; + +static void * +build_fadt(struct pci_device *pci) +{ + struct fadt_descriptor_rev1 *fadt = malloc_high(sizeof(*fadt)); + struct facs_descriptor_rev1 *facs = memalign_high(64, sizeof(*facs)); + void *dsdt = malloc_high(sizeof(AmlCode)); + + if (!fadt || !facs || !dsdt) { + warn_noalloc(); + return NULL; + } + + /* FACS */ + memset(facs, 0, sizeof(*facs)); + facs->signature = FACS_SIGNATURE; + facs->length = cpu_to_le32(sizeof(*facs)); + + /* DSDT */ + memcpy(dsdt, AmlCode, sizeof(AmlCode)); + + /* FADT */ + memset(fadt, 0, sizeof(*fadt)); + fadt->firmware_ctrl = cpu_to_le32((u32)facs); + fadt->dsdt = cpu_to_le32((u32)dsdt); + fadt->model = 1; + fadt->reserved1 = 0; + + if (pci) { + int pm_sci_int = pci_config_readb(pci->bdf, PCI_INTERRUPT_LINE); + + fadt->sci_int = cpu_to_le16(pm_sci_int); + fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD); + fadt->pm1a_evt_blk = cpu_to_le32(PORT_ACPI_PM_BASE); + fadt->pm1a_cnt_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x04); + fadt->pm_tmr_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x08); + fadt->pm1_evt_len = 4; + fadt->pm1_cnt_len = 2; + fadt->pm_tmr_len = 4; + + + fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported + fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported + pci_init_device(fadt_init_tbl, pci, fadt); + } else { + + fadt->sci_int = 0; + fadt->smi_cmd = 0; + fadt->pm1a_evt_blk = 0; + fadt->pm1a_cnt_blk = 0; + fadt->pm_tmr_blk = 0; + fadt->pm1_evt_len = 0; + fadt->pm1_cnt_len = 0; + fadt->pm_tmr_len = 0; + + + fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported + fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported + + // No PIIX4 to init + // pci_init_device(fadt_init_tbl, pci, fadt); + + } + + /* WBINVD + PROC_C1 + SLP_BUTTON + FIX_RTC + RTC_S4 */ + fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 5) | (1 << 6) | (1 << 7)); + + build_header((void*)fadt, FACP_SIGNATURE, sizeof(*fadt), 1); + + return fadt; +} + +static void* +build_madt(void) +{ + int madt_size = (sizeof(struct multiple_apic_table) + + sizeof(struct madt_processor_apic) * MaxCountCPUs + + sizeof(struct madt_io_apic) + + sizeof(struct madt_intsrcovr) * 16); + struct multiple_apic_table *madt = malloc_high(madt_size); + if (!madt) { + warn_noalloc(); + return NULL; + } + memset(madt, 0, madt_size); + madt->local_apic_address = cpu_to_le32(BUILD_APIC_ADDR); + madt->flags = cpu_to_le32(1); + struct madt_processor_apic *apic = (void*)&madt[1]; + int i; + for (i=0; itype = APIC_PROCESSOR; + apic->length = sizeof(*apic); + apic->processor_id = i; + apic->local_apic_id = i; + if (i < CountCPUs) + apic->flags = cpu_to_le32(1); + else + apic->flags = cpu_to_le32(0); + apic++; + } + struct madt_io_apic *io_apic = (void*)apic; + io_apic->type = APIC_IO; + io_apic->length = sizeof(*io_apic); + io_apic->io_apic_id = CountCPUs; + io_apic->address = cpu_to_le32(BUILD_IOAPIC_ADDR); + io_apic->interrupt = cpu_to_le32(0); + + struct madt_intsrcovr *intsrcovr = (void*)&io_apic[1]; + if (qemu_cfg_irq0_override()) { + memset(intsrcovr, 0, sizeof(*intsrcovr)); + intsrcovr->type = APIC_XRUPT_OVERRIDE; + intsrcovr->length = sizeof(*intsrcovr); + intsrcovr->source = 0; + intsrcovr->gsi = 2; + intsrcovr->flags = 0; /* conforms to bus specifications */ + intsrcovr++; + } + for (i = 1; i < 16; i++) { + if (!(PCI_ISA_IRQ_MASK & (1 << i))) + /* No need for a INT source override structure. */ + continue; + memset(intsrcovr, 0, sizeof(*intsrcovr)); + intsrcovr->type = APIC_XRUPT_OVERRIDE; + intsrcovr->length = sizeof(*intsrcovr); + intsrcovr->source = i; + intsrcovr->gsi = i; + intsrcovr->flags = 0xd; /* active high, level triggered */ + intsrcovr++; + } + + build_header((void*)madt, APIC_SIGNATURE, (void*)intsrcovr - (void*)madt, 1); + return madt; +} + +// Encode a hex value +static inline char getHex(u32 val) { + val &= 0x0f; + return (val <= 9) ? ('0' + val) : ('A' + val - 10); +} + +// Encode a length in an SSDT. +static u8 * +encodeLen(u8 *ssdt_ptr, int length, int bytes) +{ + switch (bytes) { + default: + case 4: ssdt_ptr[3] = ((length >> 20) & 0xff); + case 3: ssdt_ptr[2] = ((length >> 12) & 0xff); + case 2: ssdt_ptr[1] = ((length >> 4) & 0xff); + ssdt_ptr[0] = (((bytes-1) & 0x3) << 6) | (length & 0x0f); + break; + case 1: ssdt_ptr[0] = length & 0x3f; + } + return ssdt_ptr + bytes; +} + +// AML Processor() object. See src/ssdt-proc.dsl for info. +static unsigned char ssdt_proc[] = { + 0x5b,0x83,0x42,0x05,0x43,0x50,0x41,0x41, + 0xaa,0x10,0xb0,0x00,0x00,0x06,0x08,0x49, + 0x44,0x5f,0x5f,0x0a,0xaa,0x08,0x5f,0x48, + 0x49,0x44,0x0d,0x41,0x43,0x50,0x49,0x30, + 0x30,0x30,0x37,0x00,0x14,0x0f,0x5f,0x4d, + 0x41,0x54,0x00,0xa4,0x43,0x50,0x4d,0x41, + 0x49,0x44,0x5f,0x5f,0x14,0x0f,0x5f,0x53, + 0x54,0x41,0x00,0xa4,0x43,0x50,0x53,0x54, + 0x49,0x44,0x5f,0x5f,0x14,0x0f,0x5f,0x45, + 0x4a,0x30,0x01,0x43,0x50,0x45,0x4a,0x49, + 0x44,0x5f,0x5f,0x68 +}; +#define SD_OFFSET_CPUHEX 6 +#define SD_OFFSET_CPUID1 8 +#define SD_OFFSET_CPUID2 20 + +#define SSDT_SIGNATURE 0x54445353 // SSDT +static void* +build_ssdt(void) +{ + int acpi_cpus = MaxCountCPUs > 0xff ? 0xff : MaxCountCPUs; + // length = ScopeOp + procs + NTYF method + CPON package + int length = ((1+3+4) + + (acpi_cpus * sizeof(ssdt_proc)) + + (1+2+5+(12*acpi_cpus)) + + (6+2+1+(1*acpi_cpus))); + u8 *ssdt = malloc_high(sizeof(struct acpi_table_header) + length); + if (! ssdt) { + warn_noalloc(); + return NULL; + } + u8 *ssdt_ptr = ssdt + sizeof(struct acpi_table_header); + + // build Scope(_SB_) header + *(ssdt_ptr++) = 0x10; // ScopeOp + ssdt_ptr = encodeLen(ssdt_ptr, length-1, 3); + *(ssdt_ptr++) = '_'; + *(ssdt_ptr++) = 'S'; + *(ssdt_ptr++) = 'B'; + *(ssdt_ptr++) = '_'; + + // build Processor object for each processor + int i; + for (i=0; i> 4); + ssdt_ptr[SD_OFFSET_CPUHEX+1] = getHex(i); + ssdt_ptr[SD_OFFSET_CPUID1] = i; + ssdt_ptr[SD_OFFSET_CPUID2] = i; + ssdt_ptr += sizeof(ssdt_proc); + } + + // build "Method(NTFY, 2) {If (LEqual(Arg0, 0x00)) {Notify(CP00, Arg1)} ...}" + *(ssdt_ptr++) = 0x14; // MethodOp + ssdt_ptr = encodeLen(ssdt_ptr, 2+5+(12*acpi_cpus), 2); + *(ssdt_ptr++) = 'N'; + *(ssdt_ptr++) = 'T'; + *(ssdt_ptr++) = 'F'; + *(ssdt_ptr++) = 'Y'; + *(ssdt_ptr++) = 0x02; + for (i=0; i> 4); + *(ssdt_ptr++) = getHex(i); + *(ssdt_ptr++) = 0x69; // Arg1Op + } + + // build "Name(CPON, Package() { One, One, ..., Zero, Zero, ... })" + *(ssdt_ptr++) = 0x08; // NameOp + *(ssdt_ptr++) = 'C'; + *(ssdt_ptr++) = 'P'; + *(ssdt_ptr++) = 'O'; + *(ssdt_ptr++) = 'N'; + *(ssdt_ptr++) = 0x12; // PackageOp + ssdt_ptr = encodeLen(ssdt_ptr, 2+1+(1*acpi_cpus), 2); + *(ssdt_ptr++) = acpi_cpus; + for (i=0; i> 16; + u32 hpet_period = readl(hpet_base + HPET_PERIOD); + + if (hpet_vendor == 0 || hpet_vendor == 0xffff || + hpet_period == 0 || hpet_period > 100000000) + return NULL; + + hpet = malloc_high(sizeof(*hpet)); + if (!hpet) { + warn_noalloc(); + return NULL; + } + + memset(hpet, 0, sizeof(*hpet)); + /* Note timer_block_id value must be kept in sync with value advertised by + * emulated hpet + */ + hpet->timer_block_id = cpu_to_le32(0x8086a201); + hpet->addr.address = cpu_to_le32(BUILD_HPET_ADDRESS); + build_header((void*)hpet, HPET_SIGNATURE, sizeof(*hpet), 1); + + return hpet; +} + +static void +acpi_build_srat_memory(struct srat_memory_affinity *numamem, + u64 base, u64 len, int node, int enabled) +{ + numamem->type = SRAT_MEMORY; + numamem->length = sizeof(*numamem); + memset(numamem->proximity, 0 ,4); + numamem->proximity[0] = node; + numamem->flags = cpu_to_le32(!!enabled); + numamem->base_addr_low = base & 0xFFFFFFFF; + numamem->base_addr_high = base >> 32; + numamem->length_low = len & 0xFFFFFFFF; + numamem->length_high = len >> 32; +} + +#define SRAT_SIGNATURE 0x54415253 // SRAT +static void * +build_srat(void) +{ + int nb_numa_nodes = qemu_cfg_get_numa_nodes(); + + if (nb_numa_nodes == 0) + return NULL; + + u64 *numadata = malloc_tmphigh(sizeof(u64) * (MaxCountCPUs + nb_numa_nodes)); + if (!numadata) { + warn_noalloc(); + return NULL; + } + + qemu_cfg_get_numa_data(numadata, MaxCountCPUs + nb_numa_nodes); + + struct system_resource_affinity_table *srat; + int srat_size = sizeof(*srat) + + sizeof(struct srat_processor_affinity) * MaxCountCPUs + + sizeof(struct srat_memory_affinity) * (nb_numa_nodes + 2); + + srat = malloc_high(srat_size); + if (!srat) { + warn_noalloc(); + free(numadata); + return NULL; + } + + memset(srat, 0, srat_size); + srat->reserved1=1; + struct srat_processor_affinity *core = (void*)(srat + 1); + int i; + u64 curnode; + + for (i = 0; i < MaxCountCPUs; ++i) { + core->type = SRAT_PROCESSOR; + core->length = sizeof(*core); + core->local_apic_id = i; + curnode = *numadata++; + core->proximity_lo = curnode; + memset(core->proximity_hi, 0, 3); + core->local_sapic_eid = 0; + if (i < CountCPUs) + core->flags = cpu_to_le32(1); + else + core->flags = 0; + core++; + } + + + /* the memory map is a bit tricky, it contains at least one hole + * from 640k-1M and possibly another one from 3.5G-4G. + */ + struct srat_memory_affinity *numamem = (void*)core; + int slots = 0; + u64 mem_len, mem_base, next_base = 0; + + acpi_build_srat_memory(numamem, 0, 640*1024, 0, 1); + next_base = 1024 * 1024; + numamem++; + slots++; + for (i = 1; i < nb_numa_nodes + 1; ++i) { + mem_base = next_base; + mem_len = *numadata++; + if (i == 1) + mem_len -= 1024 * 1024; + next_base = mem_base + mem_len; + + /* Cut out the PCI hole */ + if (mem_base <= RamSize && next_base > RamSize) { + mem_len -= next_base - RamSize; + if (mem_len > 0) { + acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1); + numamem++; + slots++; + } + mem_base = 1ULL << 32; + mem_len = next_base - RamSize; + next_base += (1ULL << 32) - RamSize; + } + acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1); + numamem++; + slots++; + } + for (; slots < nb_numa_nodes + 2; slots++) { + acpi_build_srat_memory(numamem, 0, 0, 0, 0); + numamem++; + } + + build_header((void*)srat, SRAT_SIGNATURE, srat_size, 1); + + free(numadata); + return srat; +} + +static const struct pci_device_id acpi_find_tbl[] = { + /* PIIX4 Power Management device. */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL), + + PCI_DEVICE_END, +}; + +struct rsdp_descriptor *RsdpAddr; + +#define MAX_ACPI_TABLES 20 +void +acpi_bios_init(void) +{ + if (! CONFIG_ACPI) + return; + + dprintf(3, "init ACPI tables\n"); + + // This code is hardcoded for PIIX4 Power Management device. + struct pci_device *pci = pci_find_init_device(acpi_find_tbl, NULL); + + /* + if (!pci) { + // Device not found + return; + */ + if (!pci) { + /* JRL: No PIIX4: Disable power management ACPI functions */ + dprintf(1, "No PIIX4 (v3vee): Disabling ACPI power management functions\n"); + } + + + // Build ACPI tables + u32 tables[MAX_ACPI_TABLES], tbl_idx = 0; + +#define ACPI_INIT_TABLE(X) \ + do { \ + tables[tbl_idx] = (u32)(X); \ + if (tables[tbl_idx]) \ + tbl_idx++; \ + } while(0) + + ACPI_INIT_TABLE(build_fadt(pci)); + ACPI_INIT_TABLE(build_ssdt()); + ACPI_INIT_TABLE(build_madt()); + if (pci) { + ACPI_INIT_TABLE(build_hpet()); + } + ACPI_INIT_TABLE(build_srat()); + + u16 i, external_tables = qemu_cfg_acpi_additional_tables(); + + for (i = 0; i < external_tables; i++) { + u16 len = qemu_cfg_next_acpi_table_len(); + void *addr = malloc_high(len); + if (!addr) { + warn_noalloc(); + continue; + } + ACPI_INIT_TABLE(qemu_cfg_next_acpi_table_load(addr, len)); + if (tbl_idx == MAX_ACPI_TABLES) { + warn_noalloc(); + break; + } + } + + // Build final rsdt table + struct rsdt_descriptor_rev1 *rsdt; + size_t rsdt_len = sizeof(*rsdt) + sizeof(u32) * tbl_idx; + rsdt = malloc_high(rsdt_len); + if (!rsdt) { + warn_noalloc(); + return; + } + memset(rsdt, 0, rsdt_len); + memcpy(rsdt->table_offset_entry, tables, sizeof(u32) * tbl_idx); + build_header((void*)rsdt, RSDT_SIGNATURE, rsdt_len, 1); + + // Build rsdp pointer table + struct rsdp_descriptor *rsdp = malloc_fseg(sizeof(*rsdp)); + if (!rsdp) { + warn_noalloc(); + return; + } + memset(rsdp, 0, sizeof(*rsdp)); + rsdp->signature = RSDP_SIGNATURE; + memcpy(rsdp->oem_id, CONFIG_APPNAME6, 6); + rsdp->rsdt_physical_address = cpu_to_le32((u32)rsdt); + rsdp->checksum -= checksum(rsdp, 20); + RsdpAddr = rsdp; + dprintf(1, "ACPI tables: RSDP=%p RSDT=%p\n", rsdp, rsdt); +} + +u32 +find_resume_vector(void) +{ + dprintf(4, "rsdp=%p\n", RsdpAddr); + if (!RsdpAddr || RsdpAddr->signature != RSDP_SIGNATURE) + return 0; + struct rsdt_descriptor_rev1 *rsdt = (void*)RsdpAddr->rsdt_physical_address; + dprintf(4, "rsdt=%p\n", rsdt); + if (!rsdt || rsdt->signature != RSDT_SIGNATURE) + return 0; + void *end = (void*)rsdt + rsdt->length; + int i; + for (i=0; (void*)&rsdt->table_offset_entry[i] < end; i++) { + struct fadt_descriptor_rev1 *fadt = (void*)rsdt->table_offset_entry[i]; + if (!fadt || fadt->signature != FACP_SIGNATURE) + continue; + dprintf(4, "fadt=%p\n", fadt); + struct facs_descriptor_rev1 *facs = (void*)fadt->firmware_ctrl; + dprintf(4, "facs=%p\n", facs); + if (! facs || facs->signature != FACS_SIGNATURE) + return 0; + // Found it. + dprintf(4, "resume addr=%d\n", facs->firmware_waking_vector); + return facs->firmware_waking_vector; + } + return 0; +} diff --git a/bios/seabios/src/acpi.h b/bios/seabios/src/acpi.h new file mode 100644 index 0000000..e01315a --- /dev/null +++ b/bios/seabios/src/acpi.h @@ -0,0 +1,101 @@ +#ifndef __ACPI_H +#define __ACPI_H + +#include "types.h" // u32 + +void acpi_bios_init(void); +u32 find_resume_vector(void); + +#define RSDP_SIGNATURE 0x2052545020445352LL // "RSD PTR " + +struct rsdp_descriptor { /* Root System Descriptor Pointer */ + u64 signature; /* ACPI signature, contains "RSD PTR " */ + u8 checksum; /* To make sum of struct == 0 */ + u8 oem_id [6]; /* OEM identification */ + u8 revision; /* Must be 0 for 1.0, 2 for 2.0 */ + u32 rsdt_physical_address; /* 32-bit physical address of RSDT */ + u32 length; /* XSDT Length in bytes including hdr */ + u64 xsdt_physical_address; /* 64-bit physical address of XSDT */ + u8 extended_checksum; /* Checksum of entire table */ + u8 reserved [3]; /* Reserved field must be 0 */ +}; + +extern struct rsdp_descriptor *RsdpAddr; + +/* Table structure from Linux kernel (the ACPI tables are under the + BSD license) */ + +#define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \ + u32 signature; /* ACPI signature (4 ASCII characters) */ \ + u32 length; /* Length of table, in bytes, including header */ \ + u8 revision; /* ACPI Specification minor version # */ \ + u8 checksum; /* To make sum of entire table == 0 */ \ + u8 oem_id [6]; /* OEM identification */ \ + u8 oem_table_id [8]; /* OEM table identification */ \ + u32 oem_revision; /* OEM revision number */ \ + u8 asl_compiler_id [4]; /* ASL compiler vendor ID */ \ + u32 asl_compiler_revision; /* ASL compiler revision number */ + + +/* + * ACPI 1.0 Fixed ACPI Description Table (FADT) + */ +#define FACP_SIGNATURE 0x50434146 // FACP +struct fadt_descriptor_rev1 +{ + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ + u32 firmware_ctrl; /* Physical address of FACS */ + u32 dsdt; /* Physical address of DSDT */ + u8 model; /* System Interrupt Model */ + u8 reserved1; /* Reserved */ + u16 sci_int; /* System vector of SCI interrupt */ + u32 smi_cmd; /* Port address of SMI command port */ + u8 acpi_enable; /* Value to write to smi_cmd to enable ACPI */ + u8 acpi_disable; /* Value to write to smi_cmd to disable ACPI */ + u8 S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ + u8 reserved2; /* Reserved - must be zero */ + u32 pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */ + u32 pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */ + u32 pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ + u32 pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ + u32 pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ + u32 pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ + u32 gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ + u32 gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ + u8 pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */ + u8 pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */ + u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ + u8 pm_tmr_len; /* Byte Length of ports at pm_tm_blk */ + u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ + u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ + u8 gpe1_base; /* Offset in gpe model where gpe1 events start */ + u8 reserved3; /* Reserved */ + u16 plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ + u16 plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ + u16 flush_size; /* Size of area read to flush caches */ + u16 flush_stride; /* Stride used in flushing caches */ + u8 duty_offset; /* Bit location of duty cycle field in p_cnt reg */ + u8 duty_width; /* Bit width of duty cycle field in p_cnt reg */ + u8 day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ + u8 mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ + u8 century; /* Index to century in RTC CMOS RAM */ + u8 reserved4; /* Reserved */ + u8 reserved4a; /* Reserved */ + u8 reserved4b; /* Reserved */ +#if 0 + u32 wb_invd : 1; /* The wbinvd instruction works properly */ + u32 wb_invd_flush : 1; /* The wbinvd flushes but does not invalidate */ + u32 proc_c1 : 1; /* All processors support C1 state */ + u32 plvl2_up : 1; /* C2 state works on MP system */ + u32 pwr_button : 1; /* Power button is handled as a generic feature */ + u32 sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */ + u32 fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */ + u32 rtcs4 : 1; /* RTC wakeup stat not possible from S4 */ + u32 tmr_val_ext : 1; /* The tmr_val width is 32 bits (0 = 24 bits) */ + u32 reserved5 : 23; /* Reserved - must be zero */ +#else + u32 flags; +#endif +} PACKED; + +#endif // acpi.h diff --git a/bios/seabios/src/ahci.c b/bios/seabios/src/ahci.c new file mode 100644 index 0000000..9b3ce2f --- /dev/null +++ b/bios/seabios/src/ahci.c @@ -0,0 +1,666 @@ +// Low level AHCI disk access +// +// Copyright (C) 2010 Gerd Hoffmann +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "types.h" // u8 +#include "ioport.h" // inb +#include "util.h" // dprintf +#include "biosvar.h" // GET_EBDA +#include "pci.h" // foreachpci +#include "pci_ids.h" // PCI_CLASS_STORAGE_OTHER +#include "pci_regs.h" // PCI_INTERRUPT_LINE +#include "boot.h" // add_bcv_hd +#include "disk.h" // struct ata_s +#include "ata.h" // ATA_CB_STAT +#include "ahci.h" // CDB_CMD_READ_10 +#include "blockcmd.h" // CDB_CMD_READ_10 + +#define AHCI_REQUEST_TIMEOUT 32000 // 32 seconds max for IDE ops +#define AHCI_RESET_TIMEOUT 500 // 500 miliseconds +#define AHCI_LINK_TIMEOUT 10 // 10 miliseconds + +/**************************************************************** + * these bits must run in both 16bit and 32bit modes + ****************************************************************/ + +// prepare sata command fis +static void sata_prep_simple(struct sata_cmd_fis *fis, u8 command) +{ + memset_fl(fis, 0, sizeof(*fis)); + SET_FLATPTR(fis->command, command); +} + +static void sata_prep_readwrite(struct sata_cmd_fis *fis, + struct disk_op_s *op, int iswrite) +{ + u64 lba = op->lba; + u8 command; + + memset_fl(fis, 0, sizeof(*fis)); + + if (op->count >= (1<<8) || lba + op->count >= (1<<28)) { + SET_FLATPTR(fis->sector_count2, op->count >> 8); + SET_FLATPTR(fis->lba_low2, lba >> 24); + SET_FLATPTR(fis->lba_mid2, lba >> 32); + SET_FLATPTR(fis->lba_high2, lba >> 40); + lba &= 0xffffff; + command = (iswrite ? ATA_CMD_WRITE_DMA_EXT + : ATA_CMD_READ_DMA_EXT); + } else { + command = (iswrite ? ATA_CMD_WRITE_DMA + : ATA_CMD_READ_DMA); + } + SET_FLATPTR(fis->feature, 1); /* dma */ + SET_FLATPTR(fis->command, command); + SET_FLATPTR(fis->sector_count, op->count); + SET_FLATPTR(fis->lba_low, lba); + SET_FLATPTR(fis->lba_mid, lba >> 8); + SET_FLATPTR(fis->lba_high, lba >> 16); + SET_FLATPTR(fis->device, ((lba >> 24) & 0xf) | ATA_CB_DH_LBA); +} + +static void sata_prep_atapi(struct sata_cmd_fis *fis, u16 blocksize) +{ + memset_fl(fis, 0, sizeof(*fis)); + SET_FLATPTR(fis->command, ATA_CMD_PACKET); + SET_FLATPTR(fis->feature, 1); /* dma */ + SET_FLATPTR(fis->lba_mid, blocksize); + SET_FLATPTR(fis->lba_high, blocksize >> 8); +} + +// ahci register access helpers +static u32 ahci_ctrl_readl(struct ahci_ctrl_s *ctrl, u32 reg) +{ + u32 addr = GET_GLOBALFLAT(ctrl->iobase) + reg; + return pci_readl(addr); +} + +static void ahci_ctrl_writel(struct ahci_ctrl_s *ctrl, u32 reg, u32 val) +{ + u32 addr = GET_GLOBALFLAT(ctrl->iobase) + reg; + pci_writel(addr, val); +} + +static u32 ahci_port_to_ctrl(u32 pnr, u32 port_reg) +{ + u32 ctrl_reg = 0x100; + ctrl_reg += pnr * 0x80; + ctrl_reg += port_reg; + return ctrl_reg; +} + +static u32 ahci_port_readl(struct ahci_ctrl_s *ctrl, u32 pnr, u32 reg) +{ + u32 ctrl_reg = ahci_port_to_ctrl(pnr, reg); + return ahci_ctrl_readl(ctrl, ctrl_reg); +} + +static void ahci_port_writel(struct ahci_ctrl_s *ctrl, u32 pnr, u32 reg, u32 val) +{ + u32 ctrl_reg = ahci_port_to_ctrl(pnr, reg); + ahci_ctrl_writel(ctrl, ctrl_reg, val); +} + +// submit ahci command + wait for result +static int ahci_command(struct ahci_port_s *port, int iswrite, int isatapi, + void *buffer, u32 bsize) +{ + u32 val, status, success, flags, intbits, error; + struct ahci_ctrl_s *ctrl = GET_GLOBAL(port->ctrl); + struct ahci_cmd_s *cmd = GET_GLOBAL(port->cmd); + struct ahci_fis_s *fis = GET_GLOBAL(port->fis); + struct ahci_list_s *list = GET_GLOBAL(port->list); + u32 pnr = GET_GLOBAL(port->pnr); + u64 end; + + SET_FLATPTR(cmd->fis.reg, 0x27); + SET_FLATPTR(cmd->fis.pmp_type, (1 << 7)); /* cmd fis */ + SET_FLATPTR(cmd->prdt[0].base, ((u32)buffer)); + SET_FLATPTR(cmd->prdt[0].baseu, 0); + SET_FLATPTR(cmd->prdt[0].flags, bsize-1); + + flags = ((1 << 16) | /* one prd entry */ + (iswrite ? (1 << 6) : 0) | + (isatapi ? (1 << 5) : 0) | + (5 << 0)); /* fis length (dwords) */ + SET_FLATPTR(list[0].flags, flags); + SET_FLATPTR(list[0].bytes, 0); + SET_FLATPTR(list[0].base, ((u32)(cmd))); + SET_FLATPTR(list[0].baseu, 0); + + dprintf(2, "AHCI/%d: send cmd ...\n", pnr); + intbits = ahci_port_readl(ctrl, pnr, PORT_IRQ_STAT); + if (intbits) + ahci_port_writel(ctrl, pnr, PORT_IRQ_STAT, intbits); + ahci_port_writel(ctrl, pnr, PORT_SCR_ACT, 1); + ahci_port_writel(ctrl, pnr, PORT_CMD_ISSUE, 1); + + end = calc_future_tsc(AHCI_REQUEST_TIMEOUT); + do { + for (;;) { + intbits = ahci_port_readl(ctrl, pnr, PORT_IRQ_STAT); + if (intbits) { + ahci_port_writel(ctrl, pnr, PORT_IRQ_STAT, intbits); + if (intbits & 0x02) { + status = GET_FLATPTR(fis->psfis[2]); + error = GET_FLATPTR(fis->psfis[3]); + break; + } + if (intbits & 0x01) { + status = GET_FLATPTR(fis->rfis[2]); + error = GET_FLATPTR(fis->rfis[3]); + break; + } + } + if (check_tsc(end)) { + warn_timeout(); + return -1; + } + yield(); + } + dprintf(2, "AHCI/%d: ... intbits 0x%x, status 0x%x ...\n", + pnr, intbits, status); + } while (status & ATA_CB_STAT_BSY); + + success = (0x00 == (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DF | + ATA_CB_STAT_ERR)) && + ATA_CB_STAT_RDY == (status & (ATA_CB_STAT_RDY))); + if (success) { + dprintf(2, "AHCI/%d: ... finished, status 0x%x, OK\n", pnr, + status); + } else { + dprintf(2, "AHCI/%d: ... finished, status 0x%x, ERROR 0x%x\n", pnr, + status, error); + + // non-queued error recovery (AHCI 1.3 section 6.2.2.1) + // Clears PxCMD.ST to 0 to reset the PxCI register + val = ahci_port_readl(ctrl, pnr, PORT_CMD); + ahci_port_writel(ctrl, pnr, PORT_CMD, val & ~PORT_CMD_START); + + // waits for PxCMD.CR to clear to 0 + while (1) { + val = ahci_port_readl(ctrl, pnr, PORT_CMD); + if ((val & PORT_CMD_LIST_ON) == 0) + break; + yield(); + } + + // Clears any error bits in PxSERR to enable capturing new errors + val = ahci_port_readl(ctrl, pnr, PORT_SCR_ERR); + ahci_port_writel(ctrl, pnr, PORT_SCR_ERR, val); + + // Clears status bits in PxIS as appropriate + val = ahci_port_readl(ctrl, pnr, PORT_IRQ_STAT); + ahci_port_writel(ctrl, pnr, PORT_IRQ_STAT, val); + + // If PxTFD.STS.BSY or PxTFD.STS.DRQ is set to 1, issue + // a COMRESET to the device to put it in an idle state + val = ahci_port_readl(ctrl, pnr, PORT_TFDATA); + if (val & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ)) { + dprintf(2, "AHCI/%d: issue comreset\n", pnr); + val = ahci_port_readl(ctrl, pnr, PORT_SCR_CTL); + // set Device Detection Initialization (DET) to 1 for 1 ms for comreset + ahci_port_writel(ctrl, pnr, PORT_SCR_CTL, val | 1); + mdelay (1); + ahci_port_writel(ctrl, pnr, PORT_SCR_CTL, val); + } + + // Sets PxCMD.ST to 1 to enable issuing new commands + val = ahci_port_readl(ctrl, pnr, PORT_CMD); + ahci_port_writel(ctrl, pnr, PORT_CMD, val | PORT_CMD_START); + } + return success ? 0 : -1; +} + +#define CDROM_CDB_SIZE 12 + +int ahci_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) +{ + if (! CONFIG_AHCI) + return 0; + + struct ahci_port_s *port = container_of( + op->drive_g, struct ahci_port_s, drive); + struct ahci_cmd_s *cmd = GET_GLOBAL(port->cmd); + u8 *atapi = cdbcmd; + int i, rc; + + sata_prep_atapi(&cmd->fis, blocksize); + for (i = 0; i < CDROM_CDB_SIZE; i++) { + SET_FLATPTR(cmd->atapi[i], atapi[i]); + } + rc = ahci_command(port, 0, 1, op->buf_fl, + op->count * blocksize); + if (rc < 0) + return DISK_RET_EBADTRACK; + return DISK_RET_SUCCESS; +} + +// read/write count blocks from a harddrive, op->buf_fl must be word aligned +static int +ahci_disk_readwrite_aligned(struct disk_op_s *op, int iswrite) +{ + struct ahci_port_s *port = container_of( + op->drive_g, struct ahci_port_s, drive); + struct ahci_cmd_s *cmd = GET_GLOBAL(port->cmd); + int rc; + + sata_prep_readwrite(&cmd->fis, op, iswrite); + rc = ahci_command(port, iswrite, 0, op->buf_fl, + op->count * DISK_SECTOR_SIZE); + dprintf(2, "ahci disk %s, lba %6x, count %3x, buf %p, rc %d\n", + iswrite ? "write" : "read", (u32)op->lba, op->count, op->buf_fl, rc); + if (rc < 0) + return DISK_RET_EBADTRACK; + return DISK_RET_SUCCESS; +} + +// read/write count blocks from a harddrive. +static int +ahci_disk_readwrite(struct disk_op_s *op, int iswrite) +{ + // if caller's buffer is word aligned, use it directly + if (((u32) op->buf_fl & 1) == 0) + return ahci_disk_readwrite_aligned(op, iswrite); + + // Use a word aligned buffer for AHCI I/O + int rc; + struct disk_op_s localop = *op; + u8 *alignedbuf_fl = GET_GLOBAL(bounce_buf_fl); + u8 *position = op->buf_fl; + + localop.buf_fl = alignedbuf_fl; + localop.count = 1; + + if (iswrite) { + u16 block; + for (block = 0; block < op->count; block++) { + memcpy_fl (alignedbuf_fl, position, DISK_SECTOR_SIZE); + rc = ahci_disk_readwrite_aligned (&localop, 1); + if (rc) + return rc; + position += DISK_SECTOR_SIZE; + localop.lba++; + } + } else { // read + u16 block; + for (block = 0; block < op->count; block++) { + rc = ahci_disk_readwrite_aligned (&localop, 0); + if (rc) + return rc; + memcpy_fl (position, alignedbuf_fl, DISK_SECTOR_SIZE); + position += DISK_SECTOR_SIZE; + localop.lba++; + } + } + return DISK_RET_SUCCESS; +} + +// command demuxer +int process_ahci_op(struct disk_op_s *op) +{ + struct ahci_port_s *port; + u32 atapi; + + if (!CONFIG_AHCI) + return 0; + + port = container_of(op->drive_g, struct ahci_port_s, drive); + atapi = GET_GLOBAL(port->atapi); + + if (atapi) { + switch (op->command) { + case CMD_READ: + return cdb_read(op); + case CMD_WRITE: + case CMD_FORMAT: + return DISK_RET_EWRITEPROTECT; + case CMD_RESET: + /* FIXME: what should we do here? */ + case CMD_VERIFY: + case CMD_SEEK: + return DISK_RET_SUCCESS; + default: + dprintf(1, "AHCI: unknown cdrom command %d\n", op->command); + op->count = 0; + return DISK_RET_EPARAM; + } + } else { + switch (op->command) { + case CMD_READ: + return ahci_disk_readwrite(op, 0); + case CMD_WRITE: + return ahci_disk_readwrite(op, 1); + case CMD_RESET: + /* FIXME: what should we do here? */ + case CMD_FORMAT: + case CMD_VERIFY: + case CMD_SEEK: + return DISK_RET_SUCCESS; + default: + dprintf(1, "AHCI: unknown disk command %d\n", op->command); + op->count = 0; + return DISK_RET_EPARAM; + } + } +} + +/**************************************************************** + * everything below is pure 32bit code + ****************************************************************/ + +static void +ahci_port_reset(struct ahci_ctrl_s *ctrl, u32 pnr) +{ + u32 val; + u64 end; + + /* disable FIS + CMD */ + end = calc_future_tsc(AHCI_RESET_TIMEOUT); + for (;;) { + val = ahci_port_readl(ctrl, pnr, PORT_CMD); + if (!(val & (PORT_CMD_FIS_RX | PORT_CMD_START | + PORT_CMD_FIS_ON | PORT_CMD_LIST_ON))) + break; + val &= ~(PORT_CMD_FIS_RX | PORT_CMD_START); + ahci_port_writel(ctrl, pnr, PORT_CMD, val); + if (check_tsc(end)) { + warn_timeout(); + break; + } + yield(); + } + + /* disable + clear IRQs */ + ahci_port_writel(ctrl, pnr, PORT_IRQ_MASK, 0); + val = ahci_port_readl(ctrl, pnr, PORT_IRQ_STAT); + if (val) + ahci_port_writel(ctrl, pnr, PORT_IRQ_STAT, val); +} + +static struct ahci_port_s* +ahci_port_alloc(struct ahci_ctrl_s *ctrl, u32 pnr) +{ + struct ahci_port_s *port = malloc_tmp(sizeof(*port)); + + if (!port) { + warn_noalloc(); + return NULL; + } + port->pnr = pnr; + port->ctrl = ctrl; + port->list = memalign_tmp(1024, 1024); + port->fis = memalign_tmp(256, 256); + port->cmd = memalign_tmp(256, 256); + if (port->list == NULL || port->fis == NULL || port->cmd == NULL) { + warn_noalloc(); + return NULL; + } + memset(port->list, 0, 1024); + memset(port->fis, 0, 256); + memset(port->cmd, 0, 256); + + ahci_port_writel(ctrl, pnr, PORT_LST_ADDR, (u32)port->list); + ahci_port_writel(ctrl, pnr, PORT_FIS_ADDR, (u32)port->fis); + return port; +} + +static struct ahci_port_s* ahci_port_realloc(struct ahci_port_s *port) +{ + struct ahci_port_s *tmp; + u32 cmd; + + tmp = malloc_fseg(sizeof(*port)); + *tmp = *port; + free(port); + port = tmp; + + ahci_port_reset(port->ctrl, port->pnr); + + free(port->list); + free(port->fis); + free(port->cmd); + port->list = memalign_low(1024, 1024); + port->fis = memalign_low(256, 256); + port->cmd = memalign_low(256, 256); + + ahci_port_writel(port->ctrl, port->pnr, PORT_LST_ADDR, (u32)port->list); + ahci_port_writel(port->ctrl, port->pnr, PORT_FIS_ADDR, (u32)port->fis); + + cmd = ahci_port_readl(port->ctrl, port->pnr, PORT_CMD); + cmd |= (PORT_CMD_FIS_RX|PORT_CMD_START); + ahci_port_writel(port->ctrl, port->pnr, PORT_CMD, cmd); + + return port; +} + +static void ahci_port_release(struct ahci_port_s *port) +{ + ahci_port_reset(port->ctrl, port->pnr); + free(port->list); + free(port->fis); + free(port->cmd); + free(port); +} + +#define MAXMODEL 40 + +/* See ahci spec chapter 10.1 "Software Initialization of HBA" */ +static int ahci_port_init(struct ahci_port_s *port) +{ + struct ahci_ctrl_s *ctrl = port->ctrl; + u32 pnr = port->pnr; + char model[MAXMODEL+1]; + u16 buffer[256]; + u32 cmd, stat, err, tf; + u64 end; + int rc; + + /* enable FIS recv */ + cmd = ahci_port_readl(ctrl, pnr, PORT_CMD); + cmd |= PORT_CMD_FIS_RX; + ahci_port_writel(ctrl, pnr, PORT_CMD, cmd); + + /* spin up */ + cmd |= PORT_CMD_SPIN_UP; + ahci_port_writel(ctrl, pnr, PORT_CMD, cmd); + end = calc_future_tsc(AHCI_LINK_TIMEOUT); + for (;;) { + stat = ahci_port_readl(ctrl, pnr, PORT_SCR_STAT); + if ((stat & 0x07) == 0x03) { + dprintf(1, "AHCI/%d: link up\n", port->pnr); + break; + } + if (check_tsc(end)) { + dprintf(1, "AHCI/%d: link down\n", port->pnr); + return -1; + } + yield(); + } + + /* clear error status */ + err = ahci_port_readl(ctrl, pnr, PORT_SCR_ERR); + if (err) + ahci_port_writel(ctrl, pnr, PORT_SCR_ERR, err); + + /* wait for device becoming ready */ + end = calc_future_tsc(AHCI_REQUEST_TIMEOUT); + for (;;) { + tf = ahci_port_readl(ctrl, pnr, PORT_TFDATA); + if (!(tf & (ATA_CB_STAT_BSY | + ATA_CB_STAT_DRQ))) + break; + if (check_tsc(end)) { + warn_timeout(); + dprintf(1, "AHCI/%d: device not ready (tf 0x%x)\n", port->pnr, tf); + return -1; + } + yield(); + } + + /* start device */ + cmd |= PORT_CMD_START; + ahci_port_writel(ctrl, pnr, PORT_CMD, cmd); + + sata_prep_simple(&port->cmd->fis, ATA_CMD_IDENTIFY_PACKET_DEVICE); + rc = ahci_command(port, 0, 0, buffer, sizeof(buffer)); + if (rc == 0) { + port->atapi = 1; + } else { + port->atapi = 0; + sata_prep_simple(&port->cmd->fis, ATA_CMD_IDENTIFY_DEVICE); + rc = ahci_command(port, 0, 0, buffer, sizeof(buffer)); + if (rc < 0) + return -1; + } + + port->drive.type = DTYPE_AHCI; + port->drive.cntl_id = pnr; + port->drive.removable = (buffer[0] & 0x80) ? 1 : 0; + + if (!port->atapi) { + // found disk (ata) + port->drive.blksize = DISK_SECTOR_SIZE; + port->drive.pchs.cylinders = buffer[1]; + port->drive.pchs.heads = buffer[3]; + port->drive.pchs.spt = buffer[6]; + + u64 sectors; + if (buffer[83] & (1 << 10)) // word 83 - lba48 support + sectors = *(u64*)&buffer[100]; // word 100-103 + else + sectors = *(u32*)&buffer[60]; // word 60 and word 61 + port->drive.sectors = sectors; + u64 adjsize = sectors >> 11; + char adjprefix = 'M'; + if (adjsize >= (1 << 16)) { + adjsize >>= 10; + adjprefix = 'G'; + } + port->desc = znprintf(MAXDESCSIZE + , "AHCI/%d: %s ATA-%d Hard-Disk (%u %ciBytes)" + , port->pnr + , ata_extract_model(model, MAXMODEL, buffer) + , ata_extract_version(buffer) + , (u32)adjsize, adjprefix); + port->prio = bootprio_find_ata_device(ctrl->pci_tmp, pnr, 0); + } else { + // found cdrom (atapi) + port->drive.blksize = CDROM_SECTOR_SIZE; + port->drive.sectors = (u64)-1; + u8 iscd = ((buffer[0] >> 8) & 0x1f) == 0x05; + if (!iscd) { + dprintf(1, "AHCI/%d: atapi device is'nt a cdrom\n", port->pnr); + return -1; + } + port->desc = znprintf(MAXDESCSIZE + , "DVD/CD [AHCI/%d: %s ATAPI-%d DVD/CD]" + , port->pnr + , ata_extract_model(model, MAXMODEL, buffer) + , ata_extract_version(buffer)); + port->prio = bootprio_find_ata_device(ctrl->pci_tmp, pnr, 0); + } + return 0; +} + +// Detect any drives attached to a given controller. +static void +ahci_port_detect(void *data) +{ + struct ahci_port_s *port = data; + int rc; + + dprintf(2, "AHCI/%d: probing\n", port->pnr); + ahci_port_reset(port->ctrl, port->pnr); + rc = ahci_port_init(port); + if (rc < 0) + ahci_port_release(port); + else { + port = ahci_port_realloc(port); + dprintf(1, "AHCI/%d: registering: \"%s\"\n", port->pnr, port->desc); + if (!port->atapi) { + // Register with bcv system. + boot_add_hd(&port->drive, port->desc, port->prio); + } else { + // fill cdidmap + boot_add_cd(&port->drive, port->desc, port->prio); + } + } +} + +// Initialize an ata controller and detect its drives. +static void +ahci_init_controller(struct pci_device *pci) +{ + struct ahci_ctrl_s *ctrl = malloc_fseg(sizeof(*ctrl)); + struct ahci_port_s *port; + u16 bdf = pci->bdf; + u32 val, pnr, max; + + if (!ctrl) { + warn_noalloc(); + return; + } + + if (bounce_buf_init() < 0) { + warn_noalloc(); + free(ctrl); + return; + } + + ctrl->pci_tmp = pci; + ctrl->pci_bdf = bdf; + ctrl->iobase = pci_config_readl(bdf, PCI_BASE_ADDRESS_5); + ctrl->irq = pci_config_readb(bdf, PCI_INTERRUPT_LINE); + dprintf(1, "AHCI controller at %02x.%x, iobase %x, irq %d\n", + bdf >> 3, bdf & 7, ctrl->iobase, ctrl->irq); + + pci_config_maskw(bdf, PCI_COMMAND, 0, + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + + val = ahci_ctrl_readl(ctrl, HOST_CTL); + ahci_ctrl_writel(ctrl, HOST_CTL, val | HOST_CTL_AHCI_EN); + + ctrl->caps = ahci_ctrl_readl(ctrl, HOST_CAP); + ctrl->ports = ahci_ctrl_readl(ctrl, HOST_PORTS_IMPL); + dprintf(2, "AHCI: cap 0x%x, ports_impl 0x%x\n", + ctrl->caps, ctrl->ports); + + max = ctrl->caps & 0x1f; + for (pnr = 0; pnr <= max; pnr++) { + if (!(ctrl->ports & (1 << pnr))) + continue; + port = ahci_port_alloc(ctrl, pnr); + if (port == NULL) + continue; + run_thread(ahci_port_detect, port); + } +} + +// Locate and init ahci controllers. +static void +ahci_init(void) +{ + // Scan PCI bus for ATA adapters + struct pci_device *pci; + foreachpci(pci) { + if (pci->class != PCI_CLASS_STORAGE_SATA) + continue; + if (pci->prog_if != 1 /* AHCI rev 1 */) + continue; + ahci_init_controller(pci); + } +} + +void +ahci_setup(void) +{ + ASSERT32FLAT(); + if (!CONFIG_AHCI) + return; + + dprintf(3, "init ahci\n"); + ahci_init(); +} diff --git a/bios/seabios/src/ahci.h b/bios/seabios/src/ahci.h new file mode 100644 index 0000000..c3d3a70 --- /dev/null +++ b/bios/seabios/src/ahci.h @@ -0,0 +1,199 @@ +#ifndef __AHCI_H +#define __AHCI_H + +struct sata_cmd_fis { + u8 reg; + u8 pmp_type; + u8 command; + u8 feature; + + u8 lba_low; + u8 lba_mid; + u8 lba_high; + u8 device; + + u8 lba_low2; + u8 lba_mid2; + u8 lba_high2; + u8 feature2; + + u8 sector_count; + u8 sector_count2; + u8 res_1; + u8 control; + + u8 res_2[64 - 16]; +}; + +struct ahci_ctrl_s { + struct pci_device *pci_tmp; + u16 pci_bdf; + u8 irq; + u32 iobase; + u32 caps; + u32 ports; +}; + +struct ahci_cmd_s { + struct sata_cmd_fis fis; + u8 atapi[0x20]; + u8 res[0x20]; + struct { + u32 base; + u32 baseu; + u32 res; + u32 flags; + } prdt[]; +}; + +/* command list */ +struct ahci_list_s { + u32 flags; + u32 bytes; + u32 base; + u32 baseu; + u32 res[4]; +}; + +struct ahci_fis_s { + u8 dsfis[0x1c]; /* dma setup */ + u8 res_1[0x04]; + u8 psfis[0x14]; /* pio setup */ + u8 res_2[0x0c]; + u8 rfis[0x14]; /* d2h register */ + u8 res_3[0x04]; + u8 sdbfis[0x08]; /* set device bits */ + u8 ufis[0x40]; /* unknown */ + u8 res_4[0x60]; +}; + +struct ahci_port_s { + struct drive_s drive; + struct ahci_ctrl_s *ctrl; + struct ahci_list_s *list; + struct ahci_fis_s *fis; + struct ahci_cmd_s *cmd; + u32 pnr; + u32 atapi; + char *desc; + int prio; +}; + +void ahci_setup(void); +int process_ahci_op(struct disk_op_s *op); +int ahci_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize); + +#define AHCI_IRQ_ON_SG (1 << 31) +#define AHCI_CMD_ATAPI (1 << 5) +#define AHCI_CMD_WRITE (1 << 6) +#define AHCI_CMD_PREFETCH (1 << 7) +#define AHCI_CMD_RESET (1 << 8) +#define AHCI_CMD_CLR_BUSY (1 << 10) + +#define RX_FIS_D2H_REG 0x40 /* offset of D2H Register FIS data */ +#define RX_FIS_SDB 0x58 /* offset of SDB FIS data */ +#define RX_FIS_UNK 0x60 /* offset of Unknown FIS data */ + +/* global controller registers */ +#define HOST_CAP 0x00 /* host capabilities */ +#define HOST_CTL 0x04 /* global host control */ +#define HOST_IRQ_STAT 0x08 /* interrupt status */ +#define HOST_PORTS_IMPL 0x0c /* bitmap of implemented ports */ +#define HOST_VERSION 0x10 /* AHCI spec. version compliancy */ + +/* HOST_CTL bits */ +#define HOST_CTL_RESET (1 << 0) /* reset controller; self-clear */ +#define HOST_CTL_IRQ_EN (1 << 1) /* global IRQ enable */ +#define HOST_CTL_AHCI_EN (1 << 31) /* AHCI enabled */ + +/* HOST_CAP bits */ +#define HOST_CAP_SSC (1 << 14) /* Slumber capable */ +#define HOST_CAP_AHCI (1 << 18) /* AHCI only */ +#define HOST_CAP_CLO (1 << 24) /* Command List Override support */ +#define HOST_CAP_SSS (1 << 27) /* Staggered Spin-up */ +#define HOST_CAP_NCQ (1 << 30) /* Native Command Queueing */ +#define HOST_CAP_64 (1 << 31) /* PCI DAC (64-bit DMA) support */ + +/* registers for each SATA port */ +#define PORT_LST_ADDR 0x00 /* command list DMA addr */ +#define PORT_LST_ADDR_HI 0x04 /* command list DMA addr hi */ +#define PORT_FIS_ADDR 0x08 /* FIS rx buf addr */ +#define PORT_FIS_ADDR_HI 0x0c /* FIS rx buf addr hi */ +#define PORT_IRQ_STAT 0x10 /* interrupt status */ +#define PORT_IRQ_MASK 0x14 /* interrupt enable/disable mask */ +#define PORT_CMD 0x18 /* port command */ +#define PORT_TFDATA 0x20 /* taskfile data */ +#define PORT_SIG 0x24 /* device TF signature */ +#define PORT_SCR_STAT 0x28 /* SATA phy register: SStatus */ +#define PORT_SCR_CTL 0x2c /* SATA phy register: SControl */ +#define PORT_SCR_ERR 0x30 /* SATA phy register: SError */ +#define PORT_SCR_ACT 0x34 /* SATA phy register: SActive */ +#define PORT_CMD_ISSUE 0x38 /* command issue */ +#define PORT_RESERVED 0x3c /* reserved */ + +/* PORT_IRQ_{STAT,MASK} bits */ +#define PORT_IRQ_COLD_PRES (1 << 31) /* cold presence detect */ +#define PORT_IRQ_TF_ERR (1 << 30) /* task file error */ +#define PORT_IRQ_HBUS_ERR (1 << 29) /* host bus fatal error */ +#define PORT_IRQ_HBUS_DATA_ERR (1 << 28) /* host bus data error */ +#define PORT_IRQ_IF_ERR (1 << 27) /* interface fatal error */ +#define PORT_IRQ_IF_NONFATAL (1 << 26) /* interface non-fatal error */ +#define PORT_IRQ_OVERFLOW (1 << 24) /* xfer exhausted available S/G */ +#define PORT_IRQ_BAD_PMP (1 << 23) /* incorrect port multiplier */ + +#define PORT_IRQ_PHYRDY (1 << 22) /* PhyRdy changed */ +#define PORT_IRQ_DEV_ILCK (1 << 7) /* device interlock */ +#define PORT_IRQ_CONNECT (1 << 6) /* port connect change status */ +#define PORT_IRQ_SG_DONE (1 << 5) /* descriptor processed */ +#define PORT_IRQ_UNK_FIS (1 << 4) /* unknown FIS rx'd */ +#define PORT_IRQ_SDB_FIS (1 << 3) /* Set Device Bits FIS rx'd */ +#define PORT_IRQ_DMAS_FIS (1 << 2) /* DMA Setup FIS rx'd */ +#define PORT_IRQ_PIOS_FIS (1 << 1) /* PIO Setup FIS rx'd */ +#define PORT_IRQ_D2H_REG_FIS (1 << 0) /* D2H Register FIS rx'd */ + +#define PORT_IRQ_FREEZE (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR | \ + PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY | \ + PORT_IRQ_UNK_FIS) +#define PORT_IRQ_ERROR (PORT_IRQ_FREEZE | PORT_IRQ_TF_ERR | \ + PORT_IRQ_HBUS_DATA_ERR) +#define DEF_PORT_IRQ (PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | \ + PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | \ + PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS) + +/* PORT_CMD bits */ +#define PORT_CMD_ATAPI (1 << 24) /* Device is ATAPI */ +#define PORT_CMD_LIST_ON (1 << 15) /* cmd list DMA engine running */ +#define PORT_CMD_FIS_ON (1 << 14) /* FIS DMA engine running */ +#define PORT_CMD_FIS_RX (1 << 4) /* Enable FIS receive DMA engine */ +#define PORT_CMD_CLO (1 << 3) /* Command list override */ +#define PORT_CMD_POWER_ON (1 << 2) /* Power up device */ +#define PORT_CMD_SPIN_UP (1 << 1) /* Spin up device */ +#define PORT_CMD_START (1 << 0) /* Enable port DMA engine */ + +#define PORT_CMD_ICC_MASK (0xf << 28) /* i/f ICC state mask */ +#define PORT_CMD_ICC_ACTIVE (0x1 << 28) /* Put i/f in active state */ +#define PORT_CMD_ICC_PARTIAL (0x2 << 28) /* Put i/f in partial state */ +#define PORT_CMD_ICC_SLUMBER (0x6 << 28) /* Put i/f in slumber state */ + +#define PORT_IRQ_STAT_DHRS (1 << 0) /* Device to Host Register FIS */ +#define PORT_IRQ_STAT_PSS (1 << 1) /* PIO Setup FIS */ +#define PORT_IRQ_STAT_DSS (1 << 2) /* DMA Setup FIS */ +#define PORT_IRQ_STAT_SDBS (1 << 3) /* Set Device Bits */ +#define PORT_IRQ_STAT_UFS (1 << 4) /* Unknown FIS */ +#define PORT_IRQ_STAT_DPS (1 << 5) /* Descriptor Processed */ +#define PORT_IRQ_STAT_PCS (1 << 6) /* Port Connect Change Status */ +#define PORT_IRQ_STAT_DMPS (1 << 7) /* Device Mechanical Presence + Status */ +#define PORT_IRQ_STAT_PRCS (1 << 22) /* File Ready Status */ +#define PORT_IRQ_STAT_IPMS (1 << 23) /* Incorrect Port Multiplier + Status */ +#define PORT_IRQ_STAT_OFS (1 << 24) /* Overflow Status */ +#define PORT_IRQ_STAT_INFS (1 << 26) /* Interface Non-Fatal Error + Status */ +#define PORT_IRQ_STAT_IFS (1 << 27) /* Interface Fatal Error */ +#define PORT_IRQ_STAT_HBDS (1 << 28) /* Host Bus Data Error Status */ +#define PORT_IRQ_STAT_HBFS (1 << 29) /* Host Bus Fatal Error Status */ +#define PORT_IRQ_STAT_TFES (1 << 30) /* Task File Error Status */ +#define PORT_IRQ_STAT_CPDS (1 << 31) /* Code Port Detect Status */ + +#endif // ahci.h diff --git a/bios/seabios/src/apm.c b/bios/seabios/src/apm.c new file mode 100644 index 0000000..c497dbe --- /dev/null +++ b/bios/seabios/src/apm.c @@ -0,0 +1,238 @@ +// Basic support for apmbios callbacks. +// +// Copyright (C) 2008 Kevin O'Connor +// Copyright (C) 2005 Struan Bartlett +// Copyright (C) 2004 Fabrice Bellard +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "farptr.h" // GET_VAR +#include "bregs.h" // struct bregs +#include "ioport.h" // outb +#include "util.h" // wait_irq +#include "config.h" // CONFIG_* +#include "biosvar.h" // GET_GLOBAL + +static void +out_str(const char *str_cs) +{ + if (CONFIG_COREBOOT) { + dprintf(1, "APM request '%s'\n", str_cs); + return; + } + + u8 *s = (u8*)str_cs; + for (;;) { + u8 c = GET_GLOBAL(*s); + if (!c) + break; + outb(c, PORT_BIOS_APM); + s++; + } +} + +// APM installation check +static void +handle_155300(struct bregs *regs) +{ + regs->ah = 1; // APM major version + regs->al = 2; // APM minor version + regs->bh = 'P'; + regs->bl = 'M'; + // bit 0 : 16 bit interface supported + // bit 1 : 32 bit interface supported + regs->cx = 0x03; + set_success(regs); +} + +// APM real mode interface connect +static void +handle_155301(struct bregs *regs) +{ + set_success(regs); +} + +// Assembler entry points defined in romlayout.S +extern void entry_apm16(void); +extern void entry_apm32(void); + +// APM 16 bit protected mode interface connect +static void +handle_155302(struct bregs *regs) +{ + regs->bx = (u32)entry_apm16; + regs->ax = SEG_BIOS; // 16 bit code segment base + regs->si = 0xfff0; // 16 bit code segment size + regs->cx = SEG_BIOS; // data segment address + regs->di = 0xfff0; // data segment length + set_success(regs); +} + +// APM 32 bit protected mode interface connect +static void +handle_155303(struct bregs *regs) +{ + regs->ax = SEG_BIOS; // 32 bit code segment base + regs->ebx = (u32)entry_apm32; + regs->cx = SEG_BIOS; // 16 bit code segment base + // 32 bit code segment size (low 16 bits) + // 16 bit code segment size (high 16 bits) + regs->esi = 0xfff0fff0; + regs->dx = SEG_BIOS; // data segment address + regs->di = 0xfff0; // data segment length + set_success(regs); +} + +// APM interface disconnect +static void +handle_155304(struct bregs *regs) +{ + set_success(regs); +} + +// APM cpu idle +static void +handle_155305(struct bregs *regs) +{ + wait_irq(); + set_success(regs); +} + +// APM cpu busy +static void +handle_155306(struct bregs *regs) +{ + set_success(regs); +} + +void +apm_shutdown(void) +{ + irq_disable(); + out_str("Shutdown"); + for (;;) + hlt(); +} + +// APM Set Power State +static void +handle_155307(struct bregs *regs) +{ + if (regs->bx != 1) { + set_success(regs); + return; + } + switch (regs->cx) { + case 1: + out_str("Standby"); + break; + case 2: + out_str("Suspend"); + break; + case 3: + apm_shutdown(); + break; + } + set_success(regs); +} + +static void +handle_155308(struct bregs *regs) +{ + set_success(regs); +} + +// Get Power Status +static void +handle_15530a(struct bregs *regs) +{ + regs->bh = 0x01; // on line + regs->bl = 0xff; // unknown battery status + regs->ch = 0x80; // no system battery + regs->cl = 0xff; // unknown remaining time + regs->dx = 0xffff; // unknown remaining time + regs->si = 0x00; // zero battery + set_success(regs); +} + +#define RET_ENOEVENT 0x80 + +// Get PM Event +static void +handle_15530b(struct bregs *regs) +{ + set_code_invalid_silent(regs, RET_ENOEVENT); +} + +// APM Driver Version +static void +handle_15530e(struct bregs *regs) +{ + regs->ah = 1; + regs->al = 2; + set_success(regs); +} + +// APM Engage / Disengage +static void +handle_15530f(struct bregs *regs) +{ + set_success(regs); +} + +// APM Get Capabilities +static void +handle_155310(struct bregs *regs) +{ + regs->bl = 0; + regs->cx = 0; + set_success(regs); +} + +static void +handle_1553XX(struct bregs *regs) +{ + set_unimplemented(regs); +} + +void +handle_1553(struct bregs *regs) +{ + if (! CONFIG_APMBIOS) { + set_code_invalid(regs, RET_EUNSUPPORTED); + return; + } + + //debug_stub(regs); + switch (regs->al) { + case 0x00: handle_155300(regs); break; + case 0x01: handle_155301(regs); break; + case 0x02: handle_155302(regs); break; + case 0x03: handle_155303(regs); break; + case 0x04: handle_155304(regs); break; + case 0x05: handle_155305(regs); break; + case 0x06: handle_155306(regs); break; + case 0x07: handle_155307(regs); break; + case 0x08: handle_155308(regs); break; + case 0x0a: handle_15530a(regs); break; + case 0x0b: handle_15530b(regs); break; + case 0x0e: handle_15530e(regs); break; + case 0x0f: handle_15530f(regs); break; + case 0x10: handle_155310(regs); break; + default: handle_1553XX(regs); break; + } +} + +void VISIBLE16 +handle_apm16(struct bregs *regs) +{ + debug_enter(regs, DEBUG_HDL_apm); + handle_1553(regs); +} + +void VISIBLE32SEG +handle_apm32(struct bregs *regs) +{ + debug_enter(regs, DEBUG_HDL_apm); + handle_1553(regs); +} diff --git a/bios/seabios/src/asm-offsets.c b/bios/seabios/src/asm-offsets.c new file mode 100644 index 0000000..5035cef --- /dev/null +++ b/bios/seabios/src/asm-offsets.c @@ -0,0 +1,31 @@ +// Generate assembler offsets. + +#include "gen-defs.h" // OFFSET +#include "bregs.h" // struct bregs +#include "biosvar.h" // struct bios_data_area_s + +/* workaround for a warning with -Wmissing-prototypes */ +void foo(void) VISIBLE16; + +void foo(void) +{ + COMMENT("BREGS"); + OFFSET(BREGS_es, bregs, es); + OFFSET(BREGS_ds, bregs, ds); + OFFSET(BREGS_eax, bregs, eax); + OFFSET(BREGS_ebx, bregs, ebx); + OFFSET(BREGS_ecx, bregs, ecx); + OFFSET(BREGS_edx, bregs, edx); + OFFSET(BREGS_ebp, bregs, ebp); + OFFSET(BREGS_esi, bregs, esi); + OFFSET(BREGS_edi, bregs, edi); + OFFSET(BREGS_flags, bregs, flags); + OFFSET(BREGS_code, bregs, code); + + COMMENT("BDA"); + OFFSET(BDA_ebda_seg, bios_data_area_s, ebda_seg); + + COMMENT("EBDA"); + DEFINE(EBDA_OFFSET_TOP_STACK, EBDA_OFFSET_TOP_STACK); + DEFINE(EBDA_SEGMENT_START, EBDA_SEGMENT_START); +} diff --git a/bios/seabios/src/ata.c b/bios/seabios/src/ata.c new file mode 100644 index 0000000..76e4f20 --- /dev/null +++ b/bios/seabios/src/ata.c @@ -0,0 +1,1071 @@ +// Low level ATA disk access +// +// Copyright (C) 2008,2009 Kevin O'Connor +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "types.h" // u8 +#include "ioport.h" // inb +#include "util.h" // dprintf +#include "cmos.h" // inb_cmos +#include "pic.h" // enable_hwirq +#include "biosvar.h" // GET_EBDA +#include "pci.h" // foreachpci +#include "pci_ids.h" // PCI_CLASS_STORAGE_OTHER +#include "pci_regs.h" // PCI_INTERRUPT_LINE +#include "boot.h" // boot_add_hd +#include "disk.h" // struct ata_s +#include "ata.h" // ATA_CB_STAT +#include "blockcmd.h" // CDB_CMD_READ_10 + +#define IDE_TIMEOUT 32000 //32 seconds max for IDE ops + + +/**************************************************************** + * Helper functions + ****************************************************************/ + +// Wait for the specified ide state +static inline int +await_ide(u8 mask, u8 flags, u16 base, u16 timeout) +{ + u64 end = calc_future_tsc(timeout); + for (;;) { + u8 status = inb(base+ATA_CB_STAT); + if ((status & mask) == flags) + return status; + if (check_tsc(end)) { + warn_timeout(); + return -1; + } + yield(); + } +} + +// Wait for the device to be not-busy. +static int +await_not_bsy(u16 base) +{ + return await_ide(ATA_CB_STAT_BSY, 0, base, IDE_TIMEOUT); +} + +// Wait for the device to be ready. +static int +await_rdy(u16 base) +{ + return await_ide(ATA_CB_STAT_RDY, ATA_CB_STAT_RDY, base, IDE_TIMEOUT); +} + +// Wait for ide state - pauses for one ata cycle first. +static inline int +pause_await_not_bsy(u16 iobase1, u16 iobase2) +{ + // Wait one PIO transfer cycle. + inb(iobase2 + ATA_CB_ASTAT); + + return await_not_bsy(iobase1); +} + +// Wait for ide state - pause for 400ns first. +static inline int +ndelay_await_not_bsy(u16 iobase1) +{ + ndelay(400); + return await_not_bsy(iobase1); +} + +// Reset a drive +static void +ata_reset(struct atadrive_s *adrive_g) +{ + struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf); + u8 slave = GET_GLOBAL(adrive_g->slave); + u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); + u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2); + + dprintf(6, "ata_reset drive=%p\n", &adrive_g->drive); + // Pulse SRST + outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST, iobase2+ATA_CB_DC); + udelay(5); + outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2+ATA_CB_DC); + msleep(2); + + // wait for device to become not busy. + int status = await_not_bsy(iobase1); + if (status < 0) + goto done; + if (slave) { + // Change device. + u64 end = calc_future_tsc(IDE_TIMEOUT); + for (;;) { + outb(ATA_CB_DH_DEV1, iobase1 + ATA_CB_DH); + status = ndelay_await_not_bsy(iobase1); + if (status < 0) + goto done; + if (inb(iobase1 + ATA_CB_DH) == ATA_CB_DH_DEV1) + break; + // Change drive request failed to take effect - retry. + if (check_tsc(end)) { + warn_timeout(); + goto done; + } + } + } else { + // QEMU doesn't reset dh on reset, so set it explicitly. + outb(ATA_CB_DH_DEV0, iobase1 + ATA_CB_DH); + } + + // On a user-reset request, wait for RDY if it is an ATA device. + u8 type=GET_GLOBAL(adrive_g->drive.type); + if (type == DTYPE_ATA) + status = await_rdy(iobase1); + +done: + // Enable interrupts + outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC); + + dprintf(6, "ata_reset exit status=%x\n", status); +} + +// Check for drive RDY for 16bit interface command. +static int +isready(struct atadrive_s *adrive_g) +{ + // Read the status from controller + struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf); + u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); + u8 status = inb(iobase1 + ATA_CB_STAT); + if ((status & (ATA_CB_STAT_BSY|ATA_CB_STAT_RDY)) == ATA_CB_STAT_RDY) + return DISK_RET_SUCCESS; + return DISK_RET_ENOTREADY; +} + +// Default 16bit command demuxer for ATA and ATAPI devices. +static int +process_ata_misc_op(struct disk_op_s *op) +{ + if (!CONFIG_ATA) + return 0; + + struct atadrive_s *adrive_g = container_of( + op->drive_g, struct atadrive_s, drive); + switch (op->command) { + case CMD_RESET: + ata_reset(adrive_g); + return DISK_RET_SUCCESS; + case CMD_ISREADY: + return isready(adrive_g); + case CMD_FORMAT: + case CMD_VERIFY: + case CMD_SEEK: + return DISK_RET_SUCCESS; + default: + op->count = 0; + return DISK_RET_EPARAM; + } +} + + +/**************************************************************** + * ATA send command + ****************************************************************/ + +struct ata_pio_command { + u8 feature; + u8 sector_count; + u8 lba_low; + u8 lba_mid; + u8 lba_high; + u8 device; + u8 command; + + u8 feature2; + u8 sector_count2; + u8 lba_low2; + u8 lba_mid2; + u8 lba_high2; +}; + +// Send an ata command to the drive. +static int +send_cmd(struct atadrive_s *adrive_g, struct ata_pio_command *cmd) +{ + struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf); + u8 slave = GET_GLOBAL(adrive_g->slave); + u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); + + // Select device + int status = await_not_bsy(iobase1); + if (status < 0) + return status; + u8 newdh = ((cmd->device & ~ATA_CB_DH_DEV1) + | (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0)); + u8 olddh = inb(iobase1 + ATA_CB_DH); + outb(newdh, iobase1 + ATA_CB_DH); + if ((olddh ^ newdh) & (1<<4)) { + // Was a device change - wait for device to become not busy. + status = ndelay_await_not_bsy(iobase1); + if (status < 0) + return status; + } + + // Check for ATA_CMD_(READ|WRITE)_(SECTORS|DMA)_EXT commands. + if ((cmd->command & ~0x11) == ATA_CMD_READ_SECTORS_EXT) { + outb(cmd->feature2, iobase1 + ATA_CB_FR); + outb(cmd->sector_count2, iobase1 + ATA_CB_SC); + outb(cmd->lba_low2, iobase1 + ATA_CB_SN); + outb(cmd->lba_mid2, iobase1 + ATA_CB_CL); + outb(cmd->lba_high2, iobase1 + ATA_CB_CH); + } + outb(cmd->feature, iobase1 + ATA_CB_FR); + outb(cmd->sector_count, iobase1 + ATA_CB_SC); + outb(cmd->lba_low, iobase1 + ATA_CB_SN); + outb(cmd->lba_mid, iobase1 + ATA_CB_CL); + outb(cmd->lba_high, iobase1 + ATA_CB_CH); + outb(cmd->command, iobase1 + ATA_CB_CMD); + + return 0; +} + +// Wait for data after calling 'send_cmd'. +static int +ata_wait_data(u16 iobase1) +{ + int status = ndelay_await_not_bsy(iobase1); + if (status < 0) + return status; + + if (status & ATA_CB_STAT_ERR) { + dprintf(6, "send_cmd : read error (status=%02x err=%02x)\n" + , status, inb(iobase1 + ATA_CB_ERR)); + return -4; + } + if (!(status & ATA_CB_STAT_DRQ)) { + dprintf(6, "send_cmd : DRQ not set (status %02x)\n", status); + return -5; + } + + return 0; +} + +// Send an ata command that does not transfer any further data. +int +ata_cmd_nondata(struct atadrive_s *adrive_g, struct ata_pio_command *cmd) +{ + struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf); + u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); + u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2); + + // Disable interrupts + outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC); + + int ret = send_cmd(adrive_g, cmd); + if (ret) + goto fail; + ret = ndelay_await_not_bsy(iobase1); + if (ret < 0) + goto fail; + + if (ret & ATA_CB_STAT_ERR) { + dprintf(6, "nondata cmd : read error (status=%02x err=%02x)\n" + , ret, inb(iobase1 + ATA_CB_ERR)); + ret = -4; + goto fail; + } + if (ret & ATA_CB_STAT_DRQ) { + dprintf(6, "nondata cmd : DRQ set (status %02x)\n", ret); + ret = -5; + goto fail; + } + +fail: + // Enable interrupts + outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC); + + return ret; +} + + +/**************************************************************** + * ATA PIO transfers + ****************************************************************/ + +// Transfer 'op->count' blocks (of 'blocksize' bytes) to/from drive +// 'op->drive_g'. +static int +ata_pio_transfer(struct disk_op_s *op, int iswrite, int blocksize) +{ + dprintf(16, "ata_pio_transfer id=%p write=%d count=%d bs=%d buf=%p\n" + , op->drive_g, iswrite, op->count, blocksize, op->buf_fl); + + struct atadrive_s *adrive_g = container_of( + op->drive_g, struct atadrive_s, drive); + struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf); + u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); + u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2); + int count = op->count; + void *buf_fl = op->buf_fl; + int status; + for (;;) { + if (iswrite) { + // Write data to controller + dprintf(16, "Write sector id=%p dest=%p\n", op->drive_g, buf_fl); + if (CONFIG_ATA_PIO32) + outsl_fl(iobase1, buf_fl, blocksize / 4); + else + outsw_fl(iobase1, buf_fl, blocksize / 2); + } else { + // Read data from controller + dprintf(16, "Read sector id=%p dest=%p\n", op->drive_g, buf_fl); + if (CONFIG_ATA_PIO32) + insl_fl(iobase1, buf_fl, blocksize / 4); + else + insw_fl(iobase1, buf_fl, blocksize / 2); + } + buf_fl += blocksize; + + status = pause_await_not_bsy(iobase1, iobase2); + if (status < 0) { + // Error + op->count -= count; + return status; + } + + count--; + if (!count) + break; + status &= (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR); + if (status != ATA_CB_STAT_DRQ) { + dprintf(6, "ata_pio_transfer : more sectors left (status %02x)\n" + , status); + op->count -= count; + return -6; + } + } + + status &= (ATA_CB_STAT_BSY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ + | ATA_CB_STAT_ERR); + if (!iswrite) + status &= ~ATA_CB_STAT_DF; + if (status != 0) { + dprintf(6, "ata_pio_transfer : no sectors left (status %02x)\n", status); + return -7; + } + + return 0; +} + + +/**************************************************************** + * ATA DMA transfers + ****************************************************************/ + +#define BM_CMD 0 +#define BM_CMD_MEMWRITE 0x08 +#define BM_CMD_START 0x01 +#define BM_STATUS 2 +#define BM_STATUS_IRQ 0x04 +#define BM_STATUS_ERROR 0x02 +#define BM_STATUS_ACTIVE 0x01 +#define BM_TABLE 4 + +struct sff_dma_prd { + u32 buf_fl; + u32 count; +}; + +// Check if DMA available and setup transfer if so. +static int +ata_try_dma(struct disk_op_s *op, int iswrite, int blocksize) +{ + if (! CONFIG_ATA_DMA) + return -1; + u32 dest = (u32)op->buf_fl; + if (dest & 1) + // Need minimum alignment of 1. + return -1; + struct atadrive_s *adrive_g = container_of( + op->drive_g, struct atadrive_s, drive); + struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf); + u16 iomaster = GET_GLOBALFLAT(chan_gf->iomaster); + if (! iomaster) + return -1; + u32 bytes = op->count * blocksize; + if (! bytes) + return -1; + + // Build PRD dma structure. + struct sff_dma_prd *dma = MAKE_FLATPTR( + get_ebda_seg() + , (void*)offsetof(struct extended_bios_data_area_s, extra_stack)); + struct sff_dma_prd *origdma = dma; + while (bytes) { + if (dma >= &origdma[16]) + // Too many descriptors.. + return -1; + u32 count = bytes; + u32 max = 0x10000 - (dest & 0xffff); + if (count > max) + count = max; + + SET_FLATPTR(dma->buf_fl, dest); + bytes -= count; + if (!bytes) + // Last descriptor. + count |= 1<<31; + dprintf(16, "dma@%p: %08x %08x\n", dma, dest, count); + dest += count; + SET_FLATPTR(dma->count, count); + dma++; + } + + // Program bus-master controller. + outl((u32)origdma, iomaster + BM_TABLE); + u8 oldcmd = inb(iomaster + BM_CMD) & ~(BM_CMD_MEMWRITE|BM_CMD_START); + outb(oldcmd | (iswrite ? 0x00 : BM_CMD_MEMWRITE), iomaster + BM_CMD); + outb(BM_STATUS_ERROR|BM_STATUS_IRQ, iomaster + BM_STATUS); + + return 0; +} + +// Transfer data using DMA. +static int +ata_dma_transfer(struct disk_op_s *op) +{ + if (! CONFIG_ATA_DMA) + return -1; + dprintf(16, "ata_dma_transfer id=%p buf=%p\n", op->drive_g, op->buf_fl); + + struct atadrive_s *adrive_g = container_of( + op->drive_g, struct atadrive_s, drive); + struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf); + u16 iomaster = GET_GLOBALFLAT(chan_gf->iomaster); + + // Start bus-master controller. + u8 oldcmd = inb(iomaster + BM_CMD); + outb(oldcmd | BM_CMD_START, iomaster + BM_CMD); + + u64 end = calc_future_tsc(IDE_TIMEOUT); + u8 status; + for (;;) { + status = inb(iomaster + BM_STATUS); + if (status & BM_STATUS_IRQ) + break; + // Transfer in progress + if (check_tsc(end)) { + // Timeout. + warn_timeout(); + break; + } + yield(); + } + outb(oldcmd & ~BM_CMD_START, iomaster + BM_CMD); + + u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); + u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2); + int idestatus = pause_await_not_bsy(iobase1, iobase2); + + if ((status & (BM_STATUS_IRQ|BM_STATUS_ACTIVE)) == BM_STATUS_IRQ + && idestatus >= 0x00 + && (idestatus & (ATA_CB_STAT_BSY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ + | ATA_CB_STAT_ERR)) == 0x00) + // Success. + return 0; + + dprintf(6, "IDE DMA error (dma=%x ide=%x/%x/%x)\n", status, idestatus + , inb(iobase2 + ATA_CB_ASTAT), inb(iobase1 + ATA_CB_ERR)); + op->count = 0; + return -1; +} + + +/**************************************************************** + * ATA hard drive functions + ****************************************************************/ + +// Transfer data to harddrive using PIO protocol. +static int +ata_pio_cmd_data(struct disk_op_s *op, int iswrite, struct ata_pio_command *cmd) +{ + struct atadrive_s *adrive_g = container_of( + op->drive_g, struct atadrive_s, drive); + struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf); + u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); + u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2); + + // Disable interrupts + outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC); + + int ret = send_cmd(adrive_g, cmd); + if (ret) + goto fail; + ret = ata_wait_data(iobase1); + if (ret) + goto fail; + ret = ata_pio_transfer(op, iswrite, DISK_SECTOR_SIZE); + +fail: + // Enable interrupts + outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC); + return ret; +} + +// Transfer data to harddrive using DMA protocol. +static int +ata_dma_cmd_data(struct disk_op_s *op, struct ata_pio_command *cmd) +{ + if (! CONFIG_ATA_DMA) + return -1; + struct atadrive_s *adrive_g = container_of( + op->drive_g, struct atadrive_s, drive); + int ret = send_cmd(adrive_g, cmd); + if (ret) + return ret; + return ata_dma_transfer(op); +} + +// Read/write count blocks from a harddrive. +static int +ata_readwrite(struct disk_op_s *op, int iswrite) +{ + u64 lba = op->lba; + + int usepio = ata_try_dma(op, iswrite, DISK_SECTOR_SIZE); + + struct ata_pio_command cmd; + memset(&cmd, 0, sizeof(cmd)); + + if (op->count >= (1<<8) || lba + op->count >= (1<<28)) { + cmd.sector_count2 = op->count >> 8; + cmd.lba_low2 = lba >> 24; + cmd.lba_mid2 = lba >> 32; + cmd.lba_high2 = lba >> 40; + lba &= 0xffffff; + + if (usepio) + cmd.command = (iswrite ? ATA_CMD_WRITE_SECTORS_EXT + : ATA_CMD_READ_SECTORS_EXT); + else + cmd.command = (iswrite ? ATA_CMD_WRITE_DMA_EXT + : ATA_CMD_READ_DMA_EXT); + } else { + if (usepio) + cmd.command = (iswrite ? ATA_CMD_WRITE_SECTORS + : ATA_CMD_READ_SECTORS); + else + cmd.command = (iswrite ? ATA_CMD_WRITE_DMA + : ATA_CMD_READ_DMA); + } + + cmd.sector_count = op->count; + cmd.lba_low = lba; + cmd.lba_mid = lba >> 8; + cmd.lba_high = lba >> 16; + cmd.device = ((lba >> 24) & 0xf) | ATA_CB_DH_LBA; + + int ret; + if (usepio) + ret = ata_pio_cmd_data(op, iswrite, &cmd); + else + ret = ata_dma_cmd_data(op, &cmd); + if (ret) + return DISK_RET_EBADTRACK; + return DISK_RET_SUCCESS; +} + +// 16bit command demuxer for ATA harddrives. +int +process_ata_op(struct disk_op_s *op) +{ + if (!CONFIG_ATA) + return 0; + + switch (op->command) { + case CMD_READ: + return ata_readwrite(op, 0); + case CMD_WRITE: + return ata_readwrite(op, 1); + default: + return process_ata_misc_op(op); + } +} + + +/**************************************************************** + * ATAPI functions + ****************************************************************/ + +#define CDROM_CDB_SIZE 12 + +// Low-level atapi command transmit function. +int +atapi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) +{ + if (! CONFIG_ATA) + return 0; + + struct atadrive_s *adrive_g = container_of( + op->drive_g, struct atadrive_s, drive); + struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf); + u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); + u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2); + + struct ata_pio_command cmd; + memset(&cmd, 0, sizeof(cmd)); + cmd.lba_mid = blocksize; + cmd.lba_high = blocksize >> 8; + cmd.command = ATA_CMD_PACKET; + + // Disable interrupts + outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC); + + int ret = send_cmd(adrive_g, &cmd); + if (ret) + goto fail; + ret = ata_wait_data(iobase1); + if (ret) + goto fail; + + // Send command to device + outsw_fl(iobase1, MAKE_FLATPTR(GET_SEG(SS), cdbcmd), CDROM_CDB_SIZE / 2); + + int status = pause_await_not_bsy(iobase1, iobase2); + if (status < 0) { + ret = status; + goto fail; + } + + if (status & ATA_CB_STAT_ERR) { + u8 err = inb(iobase1 + ATA_CB_ERR); + // skip "Not Ready" + if (err != 0x20) + dprintf(6, "send_atapi_cmd : read error (status=%02x err=%02x)\n" + , status, err); + ret = -2; + goto fail; + } + if (!(status & ATA_CB_STAT_DRQ)) { + dprintf(6, "send_atapi_cmd : DRQ not set (status %02x)\n", status); + ret = -3; + goto fail; + } + + ret = ata_pio_transfer(op, 0, blocksize); + +fail: + // Enable interrupts + outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC); + if (ret) + return DISK_RET_EBADTRACK; + return DISK_RET_SUCCESS; +} + +// 16bit command demuxer for ATAPI cdroms. +int +process_atapi_op(struct disk_op_s *op) +{ + if (!CONFIG_ATA) + return 0; + switch (op->command) { + case CMD_READ: + return cdb_read(op); + case CMD_FORMAT: + case CMD_WRITE: + return DISK_RET_EWRITEPROTECT; + default: + return process_ata_misc_op(op); + } +} + + +/**************************************************************** + * ATA detect and init + ****************************************************************/ + +// Send an identify device or identify device packet command. +static int +send_ata_identity(struct atadrive_s *adrive_g, u16 *buffer, int command) +{ + memset(buffer, 0, DISK_SECTOR_SIZE); + + struct disk_op_s dop; + memset(&dop, 0, sizeof(dop)); + dop.drive_g = &adrive_g->drive; + dop.count = 1; + dop.lba = 1; + dop.buf_fl = MAKE_FLATPTR(GET_SEG(SS), buffer); + + struct ata_pio_command cmd; + memset(&cmd, 0, sizeof(cmd)); + cmd.command = command; + + return ata_pio_cmd_data(&dop, 0, &cmd); +} + +// Extract the ATA/ATAPI version info. +int +ata_extract_version(u16 *buffer) +{ + // Extract ATA/ATAPI version. + u16 ataversion = buffer[80]; + u8 version; + for (version=15; version>0; version--) + if (ataversion & (1<chan_gf = dummy->chan_gf; + adrive_g->slave = dummy->slave; + adrive_g->drive.cntl_id = adrive_g->chan_gf->chanid * 2 + dummy->slave; + adrive_g->drive.removable = (buffer[0] & 0x80) ? 1 : 0; + return adrive_g; +} + +// Detect if the given drive is an atapi - initialize it if so. +static struct atadrive_s * +init_drive_atapi(struct atadrive_s *dummy, u16 *buffer) +{ + // Send an IDENTIFY_DEVICE_PACKET command to device + int ret = send_ata_identity(dummy, buffer, ATA_CMD_IDENTIFY_PACKET_DEVICE); + if (ret) + return NULL; + + // Success - setup as ATAPI. + struct atadrive_s *adrive_g = init_atadrive(dummy, buffer); + if (!adrive_g) + return NULL; + adrive_g->drive.type = DTYPE_ATAPI; + adrive_g->drive.blksize = CDROM_SECTOR_SIZE; + adrive_g->drive.sectors = (u64)-1; + u8 iscd = ((buffer[0] >> 8) & 0x1f) == 0x05; + char model[MAXMODEL+1]; + char *desc = znprintf(MAXDESCSIZE + , "DVD/CD [ata%d-%d: %s ATAPI-%d %s]" + , adrive_g->chan_gf->chanid, adrive_g->slave + , ata_extract_model(model, MAXMODEL, buffer) + , ata_extract_version(buffer) + , (iscd ? "DVD/CD" : "Device")); + dprintf(1, "%s\n", desc); + + // fill cdidmap + if (iscd) { + int prio = bootprio_find_ata_device(adrive_g->chan_gf->pci_tmp, + adrive_g->chan_gf->chanid, + adrive_g->slave); + boot_add_cd(&adrive_g->drive, desc, prio); + } + + return adrive_g; +} + +// Detect if the given drive is a regular ata drive - initialize it if so. +static struct atadrive_s * +init_drive_ata(struct atadrive_s *dummy, u16 *buffer) +{ + // Send an IDENTIFY_DEVICE command to device + int ret = send_ata_identity(dummy, buffer, ATA_CMD_IDENTIFY_DEVICE); + if (ret) + return NULL; + + // Success - setup as ATA. + struct atadrive_s *adrive_g = init_atadrive(dummy, buffer); + if (!adrive_g) + return NULL; + adrive_g->drive.type = DTYPE_ATA; + adrive_g->drive.blksize = DISK_SECTOR_SIZE; + + adrive_g->drive.pchs.cylinders = buffer[1]; + adrive_g->drive.pchs.heads = buffer[3]; + adrive_g->drive.pchs.spt = buffer[6]; + + u64 sectors; + if (buffer[83] & (1 << 10)) // word 83 - lba48 support + sectors = *(u64*)&buffer[100]; // word 100-103 + else + sectors = *(u32*)&buffer[60]; // word 60 and word 61 + adrive_g->drive.sectors = sectors; + u64 adjsize = sectors >> 11; + char adjprefix = 'M'; + if (adjsize >= (1 << 16)) { + adjsize >>= 10; + adjprefix = 'G'; + } + char model[MAXMODEL+1]; + char *desc = znprintf(MAXDESCSIZE + , "ata%d-%d: %s ATA-%d Hard-Disk (%u %ciBytes)" + , adrive_g->chan_gf->chanid, adrive_g->slave + , ata_extract_model(model, MAXMODEL, buffer) + , ata_extract_version(buffer) + , (u32)adjsize, adjprefix); + dprintf(1, "%s\n", desc); + + int prio = bootprio_find_ata_device(adrive_g->chan_gf->pci_tmp, + adrive_g->chan_gf->chanid, + adrive_g->slave); + // Register with bcv system. + boot_add_hd(&adrive_g->drive, desc, prio); + + return adrive_g; +} + +static u64 SpinupEnd; + +// Wait for non-busy status and check for "floating bus" condition. +static int +powerup_await_non_bsy(u16 base) +{ + u8 orstatus = 0; + u8 status; + for (;;) { + status = inb(base+ATA_CB_STAT); + if (!(status & ATA_CB_STAT_BSY)) + break; + orstatus |= status; + if (orstatus == 0xff) { + dprintf(4, "powerup IDE floating\n"); + return orstatus; + } + if (check_tsc(SpinupEnd)) { + warn_timeout(); + return -1; + } + yield(); + } + dprintf(6, "powerup iobase=%x st=%x\n", base, status); + return status; +} + +// Detect any drives attached to a given controller. +static void +ata_detect(void *data) +{ + struct ata_channel_s *chan_gf = data; + struct atadrive_s dummy; + memset(&dummy, 0, sizeof(dummy)); + dummy.chan_gf = chan_gf; + // Device detection + int didreset = 0; + u8 slave; + for (slave=0; slave<=1; slave++) { + // Wait for not-bsy. + u16 iobase1 = chan_gf->iobase1; + int status = powerup_await_non_bsy(iobase1); + if (status < 0) + continue; + u8 newdh = slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0; + outb(newdh, iobase1+ATA_CB_DH); + ndelay(400); + status = powerup_await_non_bsy(iobase1); + if (status < 0) + continue; + + // Check if ioport registers look valid. + outb(newdh, iobase1+ATA_CB_DH); + u8 dh = inb(iobase1+ATA_CB_DH); + outb(0x55, iobase1+ATA_CB_SC); + outb(0xaa, iobase1+ATA_CB_SN); + u8 sc = inb(iobase1+ATA_CB_SC); + u8 sn = inb(iobase1+ATA_CB_SN); + dprintf(6, "ata_detect ata%d-%d: sc=%x sn=%x dh=%x\n" + , chan_gf->chanid, slave, sc, sn, dh); + if (sc != 0x55 || sn != 0xaa || dh != newdh) + continue; + + // Prepare new drive. + dummy.slave = slave; + + // reset the channel + if (!didreset) { + ata_reset(&dummy); + didreset = 1; + } + + // check for ATAPI + u16 buffer[256]; + struct atadrive_s *adrive_g = init_drive_atapi(&dummy, buffer); + if (!adrive_g) { + // Didn't find an ATAPI drive - look for ATA drive. + u8 st = inb(iobase1+ATA_CB_STAT); + if (!st) + // Status not set - can't be a valid drive. + continue; + + // Wait for RDY. + int ret = await_rdy(iobase1); + if (ret < 0) + continue; + + // check for ATA. + adrive_g = init_drive_ata(&dummy, buffer); + if (!adrive_g) + // No ATA drive found + continue; + } + + u16 resetresult = buffer[93]; + dprintf(6, "ata_detect resetresult=%04x\n", resetresult); + if (!slave && (resetresult & 0xdf61) == 0x4041) + // resetresult looks valid and device 0 is responding to + // device 1 requests - device 1 must not be present - skip + // detection. + break; + } +} + +// Initialize an ata controller and detect its drives. +static void +init_controller(struct pci_device *pci, int irq + , u32 port1, u32 port2, u32 master) +{ + static int chanid = 0; + struct ata_channel_s *chan_gf = malloc_fseg(sizeof(*chan_gf)); + if (!chan_gf) { + warn_noalloc(); + return; + } + chan_gf->chanid = chanid++; + chan_gf->irq = irq; + chan_gf->pci_bdf = pci ? pci->bdf : -1; + chan_gf->pci_tmp = pci; + chan_gf->iobase1 = port1; + chan_gf->iobase2 = port2; + chan_gf->iomaster = master; + dprintf(1, "ATA controller %d at %x/%x/%x (irq %d dev %x)\n" + , chanid, port1, port2, master, irq, chan_gf->pci_bdf); + run_thread(ata_detect, chan_gf); +} + +#define IRQ_ATA1 14 +#define IRQ_ATA2 15 + +// Handle controllers on an ATA PCI device. +static void +init_pciata(struct pci_device *pci, u8 prog_if) +{ + pci->have_driver = 1; + u16 bdf = pci->bdf; + u8 pciirq = pci_config_readb(bdf, PCI_INTERRUPT_LINE); + int master = 0; + if (CONFIG_ATA_DMA && prog_if & 0x80) { + // Check for bus-mastering. + u32 bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_4); + if (bar & PCI_BASE_ADDRESS_SPACE_IO) { + master = bar & PCI_BASE_ADDRESS_IO_MASK; + pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER); + } + } + + u32 port1, port2, irq; + if (prog_if & 1) { + port1 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_0) + & PCI_BASE_ADDRESS_IO_MASK); + port2 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_1) + & PCI_BASE_ADDRESS_IO_MASK); + irq = pciirq; + } else { + port1 = PORT_ATA1_CMD_BASE; + port2 = PORT_ATA1_CTRL_BASE; + irq = IRQ_ATA1; + } + init_controller(pci, irq, port1, port2, master); + + if (prog_if & 4) { + port1 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_2) + & PCI_BASE_ADDRESS_IO_MASK); + port2 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_3) + & PCI_BASE_ADDRESS_IO_MASK); + irq = pciirq; + } else { + port1 = PORT_ATA2_CMD_BASE; + port2 = PORT_ATA2_CTRL_BASE; + irq = IRQ_ATA2; + } + init_controller(pci, irq, port1, port2, master ? master + 8 : 0); +} + +static void +found_genericata(struct pci_device *pci, void *arg) +{ + init_pciata(pci, pci->prog_if); +} + +static void +found_compatibleahci(struct pci_device *pci, void *arg) +{ + if (CONFIG_AHCI) + // Already handled directly via native ahci interface. + return; + init_pciata(pci, 0x8f); +} + +static const struct pci_device_id pci_ata_tbl[] = { + PCI_DEVICE_CLASS(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE + , found_genericata), + PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4391, found_compatibleahci), + PCI_DEVICE_END, +}; + +// Locate and init ata controllers. +static void +ata_init(void) +{ + if (!CONFIG_COREBOOT && !PCIDevices) { + // No PCI devices found - probably a QEMU "-M isapc" machine. + // Try using ISA ports for ATA controllers. + init_controller(NULL, IRQ_ATA1 + , PORT_ATA1_CMD_BASE, PORT_ATA1_CTRL_BASE, 0); + init_controller(NULL, IRQ_ATA2 + , PORT_ATA2_CMD_BASE, PORT_ATA2_CTRL_BASE, 0); + return; + } + + // Scan PCI bus for ATA adapters + struct pci_device *pci; + foreachpci(pci) { + pci_init_device(pci_ata_tbl, pci, NULL); + } +} + +void +ata_setup(void) +{ + ASSERT32FLAT(); + if (!CONFIG_ATA) + return; + + dprintf(3, "init hard drives\n"); + + SpinupEnd = calc_future_tsc(IDE_TIMEOUT); + ata_init(); + + SET_BDA(disk_control_byte, 0xc0); + + enable_hwirq(14, FUNC16(entry_76)); +} diff --git a/bios/seabios/src/ata.h b/bios/seabios/src/ata.h new file mode 100644 index 0000000..cfc6108 --- /dev/null +++ b/bios/seabios/src/ata.h @@ -0,0 +1,154 @@ +#ifndef __ATA_H +#define __ATA_H + +#include "types.h" // u8 +#include "config.h" // CONFIG_MAX_ATA_INTERFACES +#include "disk.h" // struct drive_s + +struct ata_channel_s { + u16 iobase1; + u16 iobase2; + u16 iomaster; + u8 irq; + u8 chanid; + int pci_bdf; + struct pci_device *pci_tmp; +}; + +struct atadrive_s { + struct drive_s drive; + struct ata_channel_s *chan_gf; + u8 slave; +}; + +// ata.c +char *ata_extract_model(char *model, u32 size, u16 *buffer); +int ata_extract_version(u16 *buffer); +int cdrom_read(struct disk_op_s *op); +int atapi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize); +void ata_setup(void); +int process_ata_op(struct disk_op_s *op); +int process_atapi_op(struct disk_op_s *op); + +// Global defines -- ATA register and register bits. +// command block & control block regs +#define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0 +#define ATA_CB_ERR 1 // error in pio_base_addr1+1 +#define ATA_CB_FR 1 // feature reg out pio_base_addr1+1 +#define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2 +#define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3 +#define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4 +#define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5 +#define ATA_CB_DH 6 // device head in/out pio_base_addr1+6 +#define ATA_CB_STAT 7 // primary status in pio_base_addr1+7 +#define ATA_CB_CMD 7 // command out pio_base_addr1+7 + +#define ATA_CB_ASTAT 2 // alternate status in pio_base_addr2+2 +#define ATA_CB_DC 2 // device control out pio_base_addr2+2 +#define ATA_CB_DA 3 // device address in pio_base_addr2+3 + +#define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC +#define ATA_CB_ER_BBK 0x80 // ATA bad block +#define ATA_CB_ER_UNC 0x40 // ATA uncorrected error +#define ATA_CB_ER_MC 0x20 // ATA media change +#define ATA_CB_ER_IDNF 0x10 // ATA id not found +#define ATA_CB_ER_MCR 0x08 // ATA media change request +#define ATA_CB_ER_ABRT 0x04 // ATA command aborted +#define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found +#define ATA_CB_ER_NDAM 0x01 // ATA address mark not found + +#define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask) +#define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request +#define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort +#define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media +#define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication + +// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC) +#define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask) +#define ATA_CB_SC_P_REL 0x04 // ATAPI release +#define ATA_CB_SC_P_IO 0x02 // ATAPI I/O +#define ATA_CB_SC_P_CD 0x01 // ATAPI C/D + +// bits 7-4 of the device/head (CB_DH) reg +#define ATA_CB_DH_DEV0 0xa0 // select device 0 +#define ATA_CB_DH_DEV1 0xb0 // select device 1 +#define ATA_CB_DH_LBA 0x40 // use LBA + +// status reg (CB_STAT and CB_ASTAT) bits +#define ATA_CB_STAT_BSY 0x80 // busy +#define ATA_CB_STAT_RDY 0x40 // ready +#define ATA_CB_STAT_DF 0x20 // device fault +#define ATA_CB_STAT_WFT 0x20 // write fault (old name) +#define ATA_CB_STAT_SKC 0x10 // seek complete +#define ATA_CB_STAT_SERV 0x10 // service +#define ATA_CB_STAT_DRQ 0x08 // data request +#define ATA_CB_STAT_CORR 0x04 // corrected +#define ATA_CB_STAT_IDX 0x02 // index +#define ATA_CB_STAT_ERR 0x01 // error (ATA) +#define ATA_CB_STAT_CHK 0x01 // check (ATAPI) + +// device control reg (CB_DC) bits +#define ATA_CB_DC_HD15 0x08 // bit should always be set to one +#define ATA_CB_DC_SRST 0x04 // soft reset +#define ATA_CB_DC_NIEN 0x02 // disable interrupts + +// Most mandtory and optional ATA commands (from ATA-3), +#define ATA_CMD_NOP 0x00 +#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03 +#define ATA_CMD_DEVICE_RESET 0x08 +#define ATA_CMD_RECALIBRATE 0x10 +#define ATA_CMD_READ_SECTORS 0x20 +#define ATA_CMD_READ_SECTORS_EXT 0x24 +#define ATA_CMD_READ_DMA_EXT 0x25 +#define ATA_CMD_READ_DMA_QUEUED_EXT 0x26 +#define ATA_CMD_READ_NATIVE_MAX_ADDRESS_EXT 0x27 +#define ATA_CMD_READ_MULTIPLE_EXT 0x29 +#define ATA_CMD_READ_LOG_EXT 0x2F +#define ATA_CMD_WRITE_SECTORS 0x30 +#define ATA_CMD_WRITE_SECTORS_EXT 0x34 +#define ATA_CMD_WRITE_DMA_EXT 0x35 +#define ATA_CMD_WRITE_DMA_QUEUED_EXT 0x36 +#define ATA_CMD_SET_MAX_ADDRESS_EXT 0x37 +#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38 +#define ATA_CMD_WRITE_MULTIPLE_EXT 0x39 +#define ATA_CMD_WRITE_VERIFY 0x3C +#define ATA_CMD_WRITE_LOG_EXT 0x3F +#define ATA_CMD_READ_VERIFY_SECTORS 0x40 +#define ATA_CMD_READ_VERIFY_SECTORS_EXT 0x42 +#define ATA_CMD_FORMAT_TRACK 0x50 +#define ATA_CMD_SEEK 0x70 +#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87 +#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90 +#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91 +#define ATA_CMD_STANDBY_IMMEDIATE2 0x94 +#define ATA_CMD_IDLE_IMMEDIATE2 0x95 +#define ATA_CMD_STANDBY2 0x96 +#define ATA_CMD_IDLE2 0x97 +#define ATA_CMD_CHECK_POWER_MODE2 0x98 +#define ATA_CMD_SLEEP2 0x99 +#define ATA_CMD_PACKET 0xA0 +#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1 +#define ATA_CMD_CFA_ERASE_SECTORS 0xC0 +#define ATA_CMD_READ_MULTIPLE 0xC4 +#define ATA_CMD_WRITE_MULTIPLE 0xC5 +#define ATA_CMD_SET_MULTIPLE_MODE 0xC6 +#define ATA_CMD_READ_DMA_QUEUED 0xC7 +#define ATA_CMD_READ_DMA 0xC8 +#define ATA_CMD_WRITE_DMA 0xCA +#define ATA_CMD_WRITE_DMA_QUEUED 0xCC +#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD +#define ATA_CMD_STANDBY_IMMEDIATE 0xE0 +#define ATA_CMD_IDLE_IMMEDIATE 0xE1 +#define ATA_CMD_STANDBY 0xE2 +#define ATA_CMD_IDLE 0xE3 +#define ATA_CMD_READ_BUFFER 0xE4 +#define ATA_CMD_CHECK_POWER_MODE 0xE5 +#define ATA_CMD_SLEEP 0xE6 +#define ATA_CMD_FLUSH_CACHE 0xE7 +#define ATA_CMD_WRITE_BUFFER 0xE8 +#define ATA_CMD_IDENTIFY_DEVICE 0xEC +#define ATA_CMD_SET_FEATURES 0xEF +#define ATA_CMD_READ_NATIVE_MAX_ADDRESS 0xF8 +#define ATA_CMD_SET_MAX 0xF9 + +#endif // ata.h diff --git a/bios/seabios/src/biostables.c b/bios/seabios/src/biostables.c new file mode 100644 index 0000000..57a5c57 --- /dev/null +++ b/bios/seabios/src/biostables.c @@ -0,0 +1,108 @@ +// Coreboot interface support. +// +// Copyright (C) 2008,2009 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "config.h" // CONFIG_* +#include "util.h" // dprintf +#include "pci.h" // struct pir_header +#include "acpi.h" // struct rsdp_descriptor +#include "mptable.h" // MPTABLE_SIGNATURE +#include "smbios.h" // struct smbios_entry_point + +void +copy_pir(void *pos) +{ + struct pir_header *p = pos; + if (p->signature != PIR_SIGNATURE) + return; + if (PirOffset) + return; + if (p->size < sizeof(*p)) + return; + if (checksum(pos, p->size) != 0) + return; + void *newpos = malloc_fseg(p->size); + if (!newpos) { + warn_noalloc(); + return; + } + dprintf(1, "Copying PIR from %p to %p\n", pos, newpos); + memcpy(newpos, pos, p->size); + PirOffset = (u32)newpos - BUILD_BIOS_ADDR; +} + +void +copy_mptable(void *pos) +{ + struct mptable_floating_s *p = pos; + if (p->signature != MPTABLE_SIGNATURE) + return; + if (!p->physaddr) + return; + if (checksum(pos, sizeof(*p)) != 0) + return; + u32 length = p->length * 16; + u16 mpclength = ((struct mptable_config_s *)p->physaddr)->length; + struct mptable_floating_s *newpos = malloc_fseg(length + mpclength); + if (!newpos) { + warn_noalloc(); + return; + } + dprintf(1, "Copying MPTABLE from %p/%x to %p\n", pos, p->physaddr, newpos); + memcpy(newpos, pos, length); + newpos->physaddr = (u32)newpos + length; + newpos->checksum -= checksum(newpos, sizeof(*newpos)); + memcpy((void*)newpos + length, (void*)p->physaddr, mpclength); +} + +void +copy_acpi_rsdp(void *pos) +{ + if (RsdpAddr) + return; + struct rsdp_descriptor *p = pos; + if (p->signature != RSDP_SIGNATURE) + return; + u32 length = 20; + if (checksum(pos, length) != 0) + return; + if (p->revision > 1) { + length = p->length; + if (checksum(pos, length) != 0) + return; + } + void *newpos = malloc_fseg(length); + if (!newpos) { + warn_noalloc(); + return; + } + dprintf(1, "Copying ACPI RSDP from %p to %p\n", pos, newpos); + memcpy(newpos, pos, length); + RsdpAddr = newpos; +} + +void +copy_smbios(void *pos) +{ + if (SMBiosAddr) + return; + struct smbios_entry_point *p = pos; + if (memcmp(p->anchor_string, "_SM_", 4)) + return; + if (checksum(pos, 0x10) != 0) + return; + if (memcmp(p->intermediate_anchor_string, "_DMI_", 5)) + return; + if (checksum(pos+0x10, p->length-0x10) != 0) + return; + struct smbios_entry_point *newpos = malloc_fseg(p->length); + if (!newpos) { + warn_noalloc(); + return; + } + dprintf(1, "Copying SMBIOS entry point from %p to %p\n", pos, newpos); + memcpy(newpos, pos, p->length); + SMBiosAddr = newpos; +} diff --git a/bios/seabios/src/biosvar.h b/bios/seabios/src/biosvar.h new file mode 100644 index 0000000..2b755e3 --- /dev/null +++ b/bios/seabios/src/biosvar.h @@ -0,0 +1,332 @@ +// Variable layouts of bios. +// +// Copyright (C) 2008-2010 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. +#ifndef __BIOSVAR_H +#define __BIOSVAR_H + +#include "types.h" // u8 +#include "farptr.h" // GET_FARVAR +#include "config.h" // CONFIG_* +#include "disk.h" // struct chs_s + + +/**************************************************************** + * Interupt vector table + ****************************************************************/ + +struct rmode_IVT { + struct segoff_s ivec[256]; +}; + +#define GET_IVT(vector) \ + GET_FARVAR(SEG_IVT, ((struct rmode_IVT *)0)->ivec[vector]) +#define SET_IVT(vector, segoff) \ + SET_FARVAR(SEG_IVT, ((struct rmode_IVT *)0)->ivec[vector], segoff) + +#define FUNC16(func) ({ \ + ASSERT32FLAT(); \ + extern void func (void); \ + SEGOFF(SEG_BIOS, (u32)func - BUILD_BIOS_ADDR); \ + }) + + +/**************************************************************** + * Bios Data Area (BDA) + ****************************************************************/ + +struct bios_data_area_s { + // 40:00 + u16 port_com[4]; + u16 port_lpt[3]; + u16 ebda_seg; + // 40:10 + u16 equipment_list_flags; + u8 pad1; + u16 mem_size_kb; + u8 pad2; + u8 ps2_ctrl_flag; + u8 kbd_flag0; + u8 kbd_flag1; + 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 video_mode; + u16 video_cols; + u16 video_pagesize; + u16 video_pagestart; + // 40:50 + u16 cursor_pos[8]; + // 40:60 + u16 cursor_type; + u8 video_page; + u16 crtc_address; + u8 video_msr; + u8 video_pal; + struct segoff_s jump; + u8 other_6b; + u32 timer_counter; + // 40:70 + u8 timer_rollover; + u8 break_flag; + u16 soft_reset_flag; + u8 disk_last_status; + u8 hdcount; + u8 disk_control_byte; + u8 port_disk; + u8 lpt_timeout[4]; + u8 com_timeout[4]; + // 40:80 + u16 kbd_buf_start_offset; + u16 kbd_buf_end_offset; + u8 video_rows; + u16 char_height; + u8 video_ctl; + u8 video_switches; + u8 modeset_ctl; + u8 dcc_index; + u8 floppy_last_data_rate; + u8 disk_status_controller; + u8 disk_error_controller; + u8 disk_interrupt_flag; + u8 floppy_harddisk_info; + // 40:90 + u8 floppy_media_state[4]; + u8 floppy_track[2]; + u8 kbd_flag2; + u8 kbd_led; + struct segoff_s user_wait_complete_flag; + u32 user_wait_timeout; + // 40:A0 + u8 rtc_wait_flag; + u8 other_a1[7]; + struct segoff_s video_savetable; + u8 other_ac[4]; + // 40:B0 + u8 other_b0[10]; + u16 vbe_mode; +} 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) \ + GET_FARVAR(SEG_BDA, ((struct bios_data_area_s *)0)->var) +#define SET_BDA(var, val) \ + SET_FARVAR(SEG_BDA, ((struct bios_data_area_s *)0)->var, (val)) +#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) + ****************************************************************/ + +// DPTE definition +struct dpte_s { + u16 iobase1; + u16 iobase2; + u8 prefix; + u8 unused; + u8 irq; + u8 blkcount; + u8 dma; + u8 pio; + u16 options; + u16 reserved; + u8 revision; + u8 checksum; +}; + +// ElTorito Device Emulation data +struct cdemu_s { + struct drive_s *emulated_drive_gf; + u32 ilba; + u16 buffer_segment; + u16 load_segment; + u16 sector_count; + u8 active; + u8 media; + u8 emulated_extdrive; + + // Virtual device + struct chs_s lchs; +}; + +struct fdpt_s { + u16 cylinders; + u8 heads; + u8 a0h_signature; + u8 phys_sectors; + u16 precompensation; + u8 reserved; + u8 drive_control_byte; + u16 phys_cylinders; + u8 phys_heads; + u16 landing_zone; + u8 sectors; + u8 checksum; +} PACKED; + +struct usbkeyinfo { + union { + struct { + u8 modifiers; + u8 repeatcount; + u8 keys[6]; + }; + u64 data; + }; +}; + +struct extended_bios_data_area_s { + u8 size; + u8 reserved1[0x21]; + struct segoff_s far_call_pointer; + u8 mouse_flag1; + u8 mouse_flag2; + u8 mouse_data[0x08]; + // 0x30 + u8 other1[0x0d]; + + // 0x3d + struct fdpt_s fdpt[2]; + + // 0x5d + u8 other2[0xC4]; + + // 0x121 - Begin custom storage. + u8 ps2ctr; + struct usbkeyinfo usbkey_last; + + int RTCusers; + + // El Torito Emulation data + struct cdemu_s cdemu; + + // Buffer for disk DPTE table + struct dpte_s dpte; + + // Locks for removable devices + u8 cdrom_locks[CONFIG_MAX_EXTDRIVE]; + + u16 boot_sequence; + + // Stack space available for code that needs it. + u8 extra_stack[512] __aligned(8); +} PACKED; + +// The initial size and location of EBDA +#define EBDA_SIZE_START \ + DIV_ROUND_UP(sizeof(struct extended_bios_data_area_s), 1024) +#define EBDA_SEGMENT_START \ + FLATPTR_TO_SEG(BUILD_LOWRAM_END - EBDA_SIZE_START*1024) + +// Accessor functions +static inline u16 get_ebda_seg(void) { + return GET_BDA(ebda_seg); +} +static inline struct extended_bios_data_area_s * +get_ebda_ptr(void) +{ + ASSERT32FLAT(); + return MAKE_FLATPTR(get_ebda_seg(), 0); +} +#define GET_EBDA2(eseg, var) \ + GET_FARVAR(eseg, ((struct extended_bios_data_area_s *)0)->var) +#define SET_EBDA2(eseg, var, val) \ + SET_FARVAR(eseg, ((struct extended_bios_data_area_s *)0)->var, (val)) +#define GET_EBDA(var) \ + GET_EBDA2(get_ebda_seg(), var) +#define SET_EBDA(var, val) \ + SET_EBDA2(get_ebda_seg(), var, (val)) + +#define EBDA_OFFSET_TOP_STACK \ + offsetof(struct extended_bios_data_area_s, extra_stack[ \ + FIELD_SIZEOF(struct extended_bios_data_area_s \ + , extra_stack)]) + + +/**************************************************************** + * Global variables + ****************************************************************/ + +#if MODE16 == 0 && MODESEGMENT == 1 +// In 32bit segmented mode %cs may not be readable and the code may be +// relocated. The entry code sets up %gs with a readable segment and +// the code offset can be determined by get_global_offset(). +#define GLOBAL_SEGREG GS +static inline u32 __attribute_const get_global_offset(void) { + u32 ret; + asm(" calll 1f\n" + "1:popl %0\n" + " subl $1b, %0" + : "=r"(ret)); + return ret; +} +#else +#define GLOBAL_SEGREG CS +static inline u32 __attribute_const get_global_offset(void) { + return 0; +} +#endif +static inline u16 get_global_seg(void) { + return GET_SEG(GLOBAL_SEGREG); +} +#define GET_GLOBAL(var) \ + GET_VAR(GLOBAL_SEGREG, *(typeof(&(var)))((void*)&(var) \ + + get_global_offset())) +#define SET_GLOBAL(var, val) do { \ + ASSERT32FLAT(); \ + (var) = (val); \ + } while (0) +#if MODESEGMENT +#define GLOBALFLAT2GLOBAL(var) ((typeof(var))((void*)(var) - BUILD_BIOS_ADDR)) +#else +#define GLOBALFLAT2GLOBAL(var) (var) +#endif +// Access a "flat" pointer known to point to the f-segment. +#define GET_GLOBALFLAT(var) GET_GLOBAL(*GLOBALFLAT2GLOBAL(&(var))) + + +/**************************************************************** + * Bios Config Table + ****************************************************************/ + +struct bios_config_table_s { + u16 size; + u8 model; + u8 submodel; + u8 biosrev; + u8 feature1, feature2, feature3, feature4, feature5; +} PACKED; + +extern struct bios_config_table_s BIOS_CONFIG_TABLE __aligned(1); + +#endif // __BIOSVAR_H diff --git a/bios/seabios/src/block.c b/bios/seabios/src/block.c new file mode 100644 index 0000000..f7e7851 --- /dev/null +++ b/bios/seabios/src/block.c @@ -0,0 +1,338 @@ +// Disk setup and access +// +// Copyright (C) 2008,2009 Kevin O'Connor +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "disk.h" // struct ata_s +#include "biosvar.h" // GET_GLOBAL +#include "cmos.h" // inb_cmos +#include "util.h" // dprintf +#include "ata.h" // process_ata_op +#include "ahci.h" // process_ahci_op +#include "usb-msc.h" // process_usb_op +#include "virtio-blk.h" // process_virtio_op + +u8 FloppyCount VAR16VISIBLE; +u8 CDCount; +struct drive_s *IDMap[3][CONFIG_MAX_EXTDRIVE] VAR16VISIBLE; +u8 *bounce_buf_fl VAR16VISIBLE; + +struct drive_s * +getDrive(u8 exttype, u8 extdriveoffset) +{ + if (extdriveoffset >= ARRAY_SIZE(IDMap[0])) + return NULL; + struct drive_s *drive_gf = GET_GLOBAL(IDMap[exttype][extdriveoffset]); + if (!drive_gf) + return NULL; + return GLOBALFLAT2GLOBAL(drive_gf); +} + +int getDriveId(u8 exttype, struct drive_s *drive_g) +{ + int i; + for (i = 0; i < ARRAY_SIZE(IDMap[0]); i++) + if (getDrive(exttype, i) == drive_g) + return i; + return -1; +} + +int bounce_buf_init(void) +{ + if (bounce_buf_fl) + return 0; + + u8 *buf = malloc_low(CDROM_SECTOR_SIZE); + if (!buf) { + warn_noalloc(); + return -1; + } + bounce_buf_fl = buf; + return 0; +} + +/**************************************************************** + * Disk geometry translation + ****************************************************************/ + +static u8 +get_translation(struct drive_s *drive_g) +{ + u8 type = GET_GLOBAL(drive_g->type); + if (! CONFIG_COREBOOT && type == DTYPE_ATA) { + // Emulators pass in the translation info via nvram. + u8 ataid = GET_GLOBAL(drive_g->cntl_id); + u8 channel = ataid / 2; + u8 translation = inb_cmos(CMOS_BIOS_DISKTRANSFLAG + channel/2); + translation >>= 2 * (ataid % 4); + translation &= 0x03; + return translation; + } + + // Otherwise use a heuristic to determine translation type. + u16 heads = GET_GLOBAL(drive_g->pchs.heads); + u16 cylinders = GET_GLOBAL(drive_g->pchs.cylinders); + u16 spt = GET_GLOBAL(drive_g->pchs.spt); + u64 sectors = GET_GLOBAL(drive_g->sectors); + u64 psectors = (u64)heads * cylinders * spt; + if (!heads || !cylinders || !spt || psectors > sectors) + // pchs doesn't look valid - use LBA. + return TRANSLATION_LBA; + + if (cylinders <= 1024 && heads <= 16 && spt <= 63) + return TRANSLATION_NONE; + if (cylinders * heads <= 131072) + return TRANSLATION_LARGE; + return TRANSLATION_LBA; +} + +static void +setup_translation(struct drive_s *drive_g) +{ + u8 translation = get_translation(drive_g); + SET_GLOBAL(drive_g->translation, translation); + + u16 heads = GET_GLOBAL(drive_g->pchs.heads); + u16 cylinders = GET_GLOBAL(drive_g->pchs.cylinders); + u16 spt = GET_GLOBAL(drive_g->pchs.spt); + u64 sectors = GET_GLOBAL(drive_g->sectors); + const char *desc = NULL; + + switch (translation) { + default: + case TRANSLATION_NONE: + desc = "none"; + break; + case TRANSLATION_LBA: + desc = "lba"; + spt = 63; + if (sectors > 63*255*1024) { + heads = 255; + cylinders = 1024; + break; + } + u32 sect = (u32)sectors / 63; + heads = sect / 1024; + if (heads>128) + heads = 255; + else if (heads>64) + heads = 128; + else if (heads>32) + heads = 64; + else if (heads>16) + heads = 32; + else + heads = 16; + cylinders = sect / heads; + break; + case TRANSLATION_RECHS: + desc = "r-echs"; + // Take care not to overflow + if (heads==16) { + if (cylinders>61439) + cylinders=61439; + heads=15; + cylinders = (u16)((u32)(cylinders)*16/15); + } + // then go through the large bitshift process + case TRANSLATION_LARGE: + if (translation == TRANSLATION_LARGE) + desc = "large"; + while (cylinders > 1024) { + cylinders >>= 1; + heads <<= 1; + + // If we max out the head count + if (heads > 127) + break; + } + break; + } + // clip to 1024 cylinders in lchs + if (cylinders > 1024) + cylinders = 1024; + dprintf(1, "drive %p: PCHS=%u/%d/%d translation=%s LCHS=%d/%d/%d s=%d\n" + , drive_g + , drive_g->pchs.cylinders, drive_g->pchs.heads, drive_g->pchs.spt + , desc + , cylinders, heads, spt + , (u32)sectors); + + SET_GLOBAL(drive_g->lchs.heads, heads); + SET_GLOBAL(drive_g->lchs.cylinders, cylinders); + SET_GLOBAL(drive_g->lchs.spt, spt); +} + + +/**************************************************************** + * Drive mapping + ****************************************************************/ + +// Fill in Fixed Disk Parameter Table (located in ebda). +static void +fill_fdpt(struct drive_s *drive_g, int hdid) +{ + if (hdid > 1) + return; + + u16 nlc = GET_GLOBAL(drive_g->lchs.cylinders); + u16 nlh = GET_GLOBAL(drive_g->lchs.heads); + u16 nlspt = GET_GLOBAL(drive_g->lchs.spt); + + u16 npc = GET_GLOBAL(drive_g->pchs.cylinders); + u16 nph = GET_GLOBAL(drive_g->pchs.heads); + u16 npspt = GET_GLOBAL(drive_g->pchs.spt); + + struct fdpt_s *fdpt = &get_ebda_ptr()->fdpt[hdid]; + fdpt->precompensation = 0xffff; + fdpt->drive_control_byte = 0xc0 | ((nph > 8) << 3); + fdpt->landing_zone = npc; + fdpt->cylinders = nlc; + fdpt->heads = nlh; + fdpt->sectors = nlspt; + + if (nlc != npc || nlh != nph || nlspt != npspt) { + // Logical mapping present - use extended structure. + + // complies with Phoenix style Translated Fixed Disk Parameter + // Table (FDPT) + fdpt->phys_cylinders = npc; + fdpt->phys_heads = nph; + fdpt->phys_sectors = npspt; + fdpt->a0h_signature = 0xa0; + + // Checksum structure. + fdpt->checksum -= checksum(fdpt, sizeof(*fdpt)); + } + + if (hdid == 0) + SET_IVT(0x41, SEGOFF(get_ebda_seg(), offsetof( + struct extended_bios_data_area_s, fdpt[0]))); + else + SET_IVT(0x46, SEGOFF(get_ebda_seg(), offsetof( + struct extended_bios_data_area_s, fdpt[1]))); +} + +// Find spot to add a drive +static void +add_drive(struct drive_s **idmap, u8 *count, struct drive_s *drive_g) +{ + if (*count >= ARRAY_SIZE(IDMap[0])) { + warn_noalloc(); + return; + } + idmap[*count] = drive_g; + *count = *count + 1; +} + +// Map a hard drive +void +map_hd_drive(struct drive_s *drive_g) +{ + ASSERT32FLAT(); + struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0); + int hdid = bda->hdcount; + dprintf(3, "Mapping hd drive %p to %d\n", drive_g, hdid); + add_drive(IDMap[EXTTYPE_HD], &bda->hdcount, drive_g); + + // Setup disk geometry translation. + setup_translation(drive_g); + + // Fill "fdpt" structure. + fill_fdpt(drive_g, hdid); +} + +// Map a cd +void +map_cd_drive(struct drive_s *drive_g) +{ + dprintf(3, "Mapping cd drive %p\n", drive_g); + add_drive(IDMap[EXTTYPE_CD], &CDCount, drive_g); +} + +// Map a floppy +void +map_floppy_drive(struct drive_s *drive_g) +{ + dprintf(3, "Mapping floppy drive %p\n", drive_g); + add_drive(IDMap[EXTTYPE_FLOPPY], &FloppyCount, drive_g); + + // Update equipment word bits for floppy + if (FloppyCount == 1) { + // 1 drive, ready for boot + SETBITS_BDA(equipment_list_flags, 0x01); + SET_BDA(floppy_harddisk_info, 0x07); + } else if (FloppyCount >= 2) { + // 2 drives, ready for boot + SETBITS_BDA(equipment_list_flags, 0x41); + SET_BDA(floppy_harddisk_info, 0x77); + } +} + + +/**************************************************************** + * 16bit calling interface + ****************************************************************/ + +// Execute a disk_op request. +int +process_op(struct disk_op_s *op) +{ + ASSERT16(); + u8 type = GET_GLOBAL(op->drive_g->type); + switch (type) { + case DTYPE_FLOPPY: + return process_floppy_op(op); + case DTYPE_ATA: + return process_ata_op(op); + case DTYPE_ATAPI: + return process_atapi_op(op); + case DTYPE_RAMDISK: + return process_ramdisk_op(op); + case DTYPE_CDEMU: + return process_cdemu_op(op); + case DTYPE_USB: + return process_usb_op(op); + case DTYPE_VIRTIO: + return process_virtio_op(op); + case DTYPE_AHCI: + return process_ahci_op(op); + default: + op->count = 0; + return DISK_RET_EPARAM; + } +} + +// Execute a "disk_op_s" request - this runs on a stack in the ebda. +static int +__send_disk_op(struct disk_op_s *op_far, u16 op_seg) +{ + struct disk_op_s dop; + memcpy_far(GET_SEG(SS), &dop + , op_seg, op_far + , sizeof(dop)); + + dprintf(DEBUG_HDL_13, "disk_op d=%p lba=%d buf=%p count=%d cmd=%d\n" + , dop.drive_g, (u32)dop.lba, dop.buf_fl + , dop.count, dop.command); + + int status = process_op(&dop); + + // Update count with total sectors transferred. + SET_FARVAR(op_seg, op_far->count, dop.count); + + return status; +} + +// Execute a "disk_op_s" request by jumping to a stack in the ebda. +int +send_disk_op(struct disk_op_s *op) +{ + ASSERT16(); + if (! CONFIG_DRIVES) + return -1; + + return stack_hop((u32)op, GET_SEG(SS), __send_disk_op); +} diff --git a/bios/seabios/src/blockcmd.c b/bios/seabios/src/blockcmd.c new file mode 100644 index 0000000..c9c6845 --- /dev/null +++ b/bios/seabios/src/blockcmd.c @@ -0,0 +1,81 @@ +// Support for several common scsi like command data block requests +// +// Copyright (C) 2010 Kevin O'Connor +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "biosvar.h" // GET_GLOBAL +#include "util.h" // htonl +#include "disk.h" // struct disk_op_s +#include "blockcmd.h" // struct cdb_request_sense +#include "ata.h" // atapi_cmd_data +#include "ahci.h" // atapi_cmd_data +#include "usb-msc.h" // usb_cmd_data + +// Route command to low-level handler. +static int +cdb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) +{ + u8 type = GET_GLOBAL(op->drive_g->type); + switch (type) { + case DTYPE_ATAPI: + return atapi_cmd_data(op, cdbcmd, blocksize); + case DTYPE_USB: + return usb_cmd_data(op, cdbcmd, blocksize); + case DTYPE_AHCI: + return ahci_cmd_data(op, cdbcmd, blocksize); + default: + op->count = 0; + return DISK_RET_EPARAM; + } +} + +int +cdb_get_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data) +{ + struct cdb_request_sense cmd; + memset(&cmd, 0, sizeof(cmd)); + cmd.command = CDB_CMD_INQUIRY; + cmd.length = sizeof(*data); + op->count = 1; + op->buf_fl = data; + return cdb_cmd_data(op, &cmd, sizeof(*data)); +} + +// Request SENSE +int +cdb_get_sense(struct disk_op_s *op, struct cdbres_request_sense *data) +{ + struct cdb_request_sense cmd; + memset(&cmd, 0, sizeof(cmd)); + cmd.command = CDB_CMD_REQUEST_SENSE; + cmd.length = sizeof(*data); + op->count = 1; + op->buf_fl = data; + return cdb_cmd_data(op, &cmd, sizeof(*data)); +} + +// Request capacity +int +cdb_read_capacity(struct disk_op_s *op, struct cdbres_read_capacity *data) +{ + struct cdb_read_capacity cmd; + memset(&cmd, 0, sizeof(cmd)); + cmd.command = CDB_CMD_READ_CAPACITY; + op->count = 1; + op->buf_fl = data; + return cdb_cmd_data(op, &cmd, sizeof(*data)); +} + +// Read sectors. +int +cdb_read(struct disk_op_s *op) +{ + struct cdb_rwdata_10 cmd; + memset(&cmd, 0, sizeof(cmd)); + cmd.command = CDB_CMD_READ_10; + cmd.lba = htonl(op->lba); + cmd.count = htons(op->count); + return cdb_cmd_data(op, &cmd, GET_GLOBAL(op->drive_g->blksize)); +} diff --git a/bios/seabios/src/blockcmd.h b/bios/seabios/src/blockcmd.h new file mode 100644 index 0000000..903c435 --- /dev/null +++ b/bios/seabios/src/blockcmd.h @@ -0,0 +1,77 @@ +// Definitions for SCSI style command data blocks. +#ifndef __BLOCKCMD_H +#define __BLOCKCMD_H + +#include "types.h" // u8 + +#define CDB_CMD_READ_10 0x28 +#define CDB_CMD_VERIFY_10 0x2f +#define CDB_CMD_WRITE_10 0x2a + +struct cdb_rwdata_10 { + u8 command; + u8 flags; + u32 lba; + u8 resreved_06; + u16 count; + u8 reserved_09; + u8 pad[6]; +} PACKED; + +#define CDB_CMD_READ_CAPACITY 0x25 + +struct cdb_read_capacity { + u8 command; + u8 flags; + u8 resreved_02[8]; + u8 pad[6]; +} PACKED; + +struct cdbres_read_capacity { + u32 sectors; + u32 blksize; +} PACKED; + +#define CDB_CMD_INQUIRY 0x12 +#define CDB_CMD_REQUEST_SENSE 0x03 + +struct cdb_request_sense { + u8 command; + u8 flags; + u16 reserved_02; + u8 length; + u8 reserved_05; + u8 pad[10]; +} PACKED; + +struct cdbres_request_sense { + u8 errcode; + u8 segment; + u8 flags; + u32 info; + u8 additional; + u32 specific; + u8 asc; + u8 ascq; + u32 reserved_0e; +} PACKED; + +struct cdbres_inquiry { + u8 pdt; + u8 removable; + u8 reserved_02[2]; + u8 additional; + u8 reserved_05[3]; + char vendor[8]; + char product[16]; + char rev[4]; +} PACKED; + +// blockcmd.c +int cdb_get_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data); +int cdb_get_sense(struct disk_op_s *op, struct cdbres_request_sense *data); +int cdb_read_capacity(struct disk_op_s *op, struct cdbres_read_capacity *data); +int cdb_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data); +int cdb_read(struct disk_op_s *op); + +#endif // blockcmd.h diff --git a/bios/seabios/src/bmp.c b/bios/seabios/src/bmp.c new file mode 100644 index 0000000..0d54efd --- /dev/null +++ b/bios/seabios/src/bmp.c @@ -0,0 +1,105 @@ +/* +* Basic BMP data process and Raw picture data handle functions. +* Could be used to adjust pixel data format, get infomation, etc. +* +* Copyright (C) 2011 Wayne Xia +* +* This work is licensed under the terms of the GNU LGPLv3. +*/ +#include "util.h" +#include "bmp.h" + +#define bmp_load4byte(addr) (*(u32 *)(addr)) +#define bmp_load2byte(addr) (*(u16 *)(addr)) + +typedef struct tagBITMAPFILEHEADER { + u8 bfType[2]; + u8 bfSize[4]; + u8 bfReserved1[2]; + u8 bfReserved2[2]; + u8 bfOffBits[4]; +} BITMAPFILEHEADER, tagBITMAPFILEHEADER; + +typedef struct tagBITMAPINFOHEADER { + u8 biSize[4]; + u8 biWidth[4]; + u8 biHeight[4]; + u8 biPlanes[2]; + u8 biBitCount[2]; + u8 biCompression[4]; + u8 biSizeImage[4]; + u8 biXPelsPerMeter[4]; + u8 biYPelsPerMeter[4]; + u8 biClrUsed[4]; + u8 biClrImportant[4]; +} BITMAPINFOHEADER, tagBITMAPINFOHEADER; + +typedef struct tagRGBQUAD { + u8 rgbBlue; + u8 rgbGreen; + u8 rgbRed; + u8 rgbReserved; +} RGBQUAD, tagRGBQUAD; + +/* flat picture data adjusting function +* description: +* switch the vertical line sequence +* arrange horizontal pixel data, add extra space in the dest buffer +* for every line +*/ +static void raw_data_format_adjust_24bpp(u8 *src, u8 *dest, int width, + int height, int bytes_per_line_dest) +{ + int bytes_per_line_src = 3 * width; + int i; + for (i = 0 ; i < height ; i++) { + memcpy(dest + i * bytes_per_line_dest, + src + (height - 1 - i) * bytes_per_line_src, bytes_per_line_src); + } +} + +struct bmp_decdata *bmp_alloc(void) +{ + struct bmp_decdata *bmp = malloc_tmphigh(sizeof(*bmp)); + return bmp; +} + +int bmp_decode(struct bmp_decdata *bmp, unsigned char *data, int data_size) +{ + if (data_size < 54) + return 1; + + u16 bmp_filehead = bmp_load2byte(data + 0); + if (bmp_filehead != 0x4d42) + return 2; + u32 bmp_recordsize = bmp_load4byte(data + 2); + if (bmp_recordsize != data_size) + return 3; + u32 bmp_dataoffset = bmp_load4byte(data + 10); + bmp->datap = (unsigned char *)data + bmp_dataoffset; + bmp->width = bmp_load4byte(data + 18); + bmp->height = bmp_load4byte(data + 22); + bmp->bpp = bmp_load2byte(data + 28); + return 0; +} + +void bmp_get_size(struct bmp_decdata *bmp, int *width, int *height) +{ + *width = bmp->width; + *height = bmp->height; +} + + +int bmp_show(struct bmp_decdata *bmp, unsigned char *pic, int width + , int height, int depth, int bytes_per_line_dest) +{ + if (bmp->datap == pic) + return 0; + /* now only support 24bpp bmp file */ + if ((depth == 24) && (bmp->bpp == 24)) { + raw_data_format_adjust_24bpp(bmp->datap, pic, width, height, + bytes_per_line_dest); + return 0; + } + return 1; +} diff --git a/bios/seabios/src/bmp.h b/bios/seabios/src/bmp.h new file mode 100644 index 0000000..7ae8e87 --- /dev/null +++ b/bios/seabios/src/bmp.h @@ -0,0 +1,25 @@ +#ifndef BMP_H +#define BMP_H +#include "types.h" + +struct bmp_decdata { + struct tagRGBQUAD *quadp; + unsigned char *datap; + int width; + int height; + int bpp; +}; + +/* allocate decdata struct */ +struct bmp_decdata *bmp_alloc(void); + +/* extract information from bmp file data */ +int bmp_decode(struct bmp_decdata *bmp, unsigned char *data, int data_size); + +/* get bmp properties */ +void bmp_get_size(struct bmp_decdata *bmp, int *width, int *height); + +/* flush flat picture data to *pc */ +int bmp_show(struct bmp_decdata *bmp, unsigned char *pic, int width + , int height, int depth, int bytes_per_line_dest); +#endif diff --git a/bios/seabios/src/boot.c b/bios/seabios/src/boot.c new file mode 100644 index 0000000..119f290 --- /dev/null +++ b/bios/seabios/src/boot.c @@ -0,0 +1,662 @@ +// Code to load disk image and start system boot. +// +// Copyright (C) 2008-2010 Kevin O'Connor +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // dprintf +#include "biosvar.h" // GET_EBDA +#include "config.h" // CONFIG_* +#include "disk.h" // cdrom_boot +#include "bregs.h" // struct bregs +#include "boot.h" // func defs +#include "cmos.h" // inb_cmos +#include "paravirt.h" // romfile_loadfile +#include "pci.h" //pci_bdf_to_* + + +/**************************************************************** + * Boot priority ordering + ****************************************************************/ + +static char **Bootorder; +static int BootorderCount; + +static void +loadBootOrder(void) +{ + if (!CONFIG_BOOTORDER) + return; + + char *f = romfile_loadfile("bootorder", NULL); + if (!f) + return; + + int i = 0; + BootorderCount = 1; + while (f[i]) { + if (f[i] == '\n') + BootorderCount++; + i++; + } + Bootorder = malloc_tmphigh(BootorderCount*sizeof(char*)); + if (!Bootorder) { + warn_noalloc(); + free(f); + BootorderCount = 0; + return; + } + + dprintf(3, "boot order:\n"); + i = 0; + do { + Bootorder[i] = f; + f = strchr(f, '\n'); + if (f) + *(f++) = '\0'; + nullTrailingSpace(Bootorder[i]); + dprintf(3, "%d: %s\n", i+1, Bootorder[i]); + i++; + } while (f); +} + +// See if 'str' starts with 'glob' - if glob contains an '*' character +// it will match any number of characters in str that aren't a '/' or +// the next glob character. +static char * +glob_prefix(const char *glob, const char *str) +{ + for (;;) { + if (!*glob && (!*str || *str == '/')) + return (char*)str; + if (*glob == '*') { + if (!*str || *str == '/' || *str == glob[1]) + glob++; + else + str++; + continue; + } + if (*glob != *str) + return NULL; + glob++; + str++; + } +} + +// Search the bootorder list for the given glob pattern. +static int +find_prio(const char *glob) +{ + dprintf(1, "Searching bootorder for: %s\n", glob); + int i; + for (i = 0; i < BootorderCount; i++) + if (glob_prefix(glob, Bootorder[i])) + return i+1; + return -1; +} + +#define FW_PCI_DOMAIN "/pci@i0cf8" + +static char * +build_pci_path(char *buf, int max, const char *devname, struct pci_device *pci) +{ + // Build the string path of a bdf - for example: /pci@i0cf8/isa@1,2 + char *p = buf; + if (pci->parent) { + p = build_pci_path(p, max, "pci-bridge", pci->parent); + } else { + if (pci->rootbus) + p += snprintf(p, max, "/pci-root@%x", pci->rootbus); + p += snprintf(p, buf+max-p, "%s", FW_PCI_DOMAIN); + } + + int dev = pci_bdf_to_dev(pci->bdf), fn = pci_bdf_to_fn(pci->bdf); + p += snprintf(p, buf+max-p, "/%s@%x", devname, dev); + if (fn) + p += snprintf(p, buf+max-p, ",%x", fn); + return p; +} + +int bootprio_find_pci_device(struct pci_device *pci) +{ + if (!CONFIG_BOOTORDER) + return -1; + // Find pci device - for example: /pci@i0cf8/ethernet@5 + char desc[256]; + build_pci_path(desc, sizeof(desc), "*", pci); + return find_prio(desc); +} + +int bootprio_find_ata_device(struct pci_device *pci, int chanid, int slave) +{ + if (!CONFIG_BOOTORDER) + return -1; + if (!pci) + // support only pci machine for now + return -1; + // Find ata drive - for example: /pci@i0cf8/ide@1,1/drive@1/disk@0 + char desc[256], *p; + p = build_pci_path(desc, sizeof(desc), "*", pci); + snprintf(p, desc+sizeof(desc)-p, "/drive@%x/disk@%x", chanid, slave); + return find_prio(desc); +} + +int bootprio_find_fdc_device(struct pci_device *pci, int port, int fdid) +{ + if (!CONFIG_BOOTORDER) + return -1; + if (!pci) + // support only pci machine for now + return -1; + // Find floppy - for example: /pci@i0cf8/isa@1/fdc@03f1/floppy@0 + char desc[256], *p; + p = build_pci_path(desc, sizeof(desc), "isa", pci); + snprintf(p, desc+sizeof(desc)-p, "/fdc@%04x/floppy@%x", port, fdid); + return find_prio(desc); +} + +int bootprio_find_pci_rom(struct pci_device *pci, int instance) +{ + if (!CONFIG_BOOTORDER) + return -1; + // Find pci rom - for example: /pci@i0cf8/scsi@3:rom2 + char desc[256], *p; + p = build_pci_path(desc, sizeof(desc), "*", pci); + if (instance) + snprintf(p, desc+sizeof(desc)-p, ":rom%d", instance); + return find_prio(desc); +} + +int bootprio_find_named_rom(const char *name, int instance) +{ + if (!CONFIG_BOOTORDER) + return -1; + // Find named rom - for example: /rom@genroms/linuxboot.bin + char desc[256], *p; + p = desc + snprintf(desc, sizeof(desc), "/rom@%s", name); + if (instance) + snprintf(p, desc+sizeof(desc)-p, ":rom%d", instance); + return find_prio(desc); +} + +int bootprio_find_usb(struct pci_device *pci, u64 path) +{ + if (!CONFIG_BOOTORDER) + return -1; + // Find usb - for example: /pci@i0cf8/usb@1,2/hub@1/network@0/ethernet@0 + int i; + char desc[256], *p; + p = build_pci_path(desc, sizeof(desc), "usb", pci); + for (i=56; i>0; i-=8) { + int port = (path >> i) & 0xff; + if (port != 0xff) + p += snprintf(p, desc+sizeof(desc)-p, "/hub@%x", port); + } + snprintf(p, desc+sizeof(desc)-p, "/*@%x", (u32)(path & 0xff)); + return find_prio(desc); +} + + +/**************************************************************** + * Boot setup + ****************************************************************/ + +static int CheckFloppySig = 1; + +#define DEFAULT_PRIO 9999 + +static int DefaultFloppyPrio = 101; +static int DefaultCDPrio = 102; +static int DefaultHDPrio = 103; +static int DefaultBEVPrio = 104; + +void +boot_setup(void) +{ + if (! CONFIG_BOOT) + return; + + SET_EBDA(boot_sequence, 0xffff); + + if (!CONFIG_COREBOOT) { + // On emulators, get boot order from nvram. + if (inb_cmos(CMOS_BIOS_BOOTFLAG1) & 1) + CheckFloppySig = 0; + u32 bootorder = (inb_cmos(CMOS_BIOS_BOOTFLAG2) + | ((inb_cmos(CMOS_BIOS_BOOTFLAG1) & 0xf0) << 4)); + DefaultFloppyPrio = DefaultCDPrio = DefaultHDPrio + = DefaultBEVPrio = DEFAULT_PRIO; + int i; + for (i=101; i<104; i++) { + u32 val = bootorder & 0x0f; + bootorder >>= 4; + switch (val) { + case 1: DefaultFloppyPrio = i; break; + case 2: DefaultHDPrio = i; break; + case 3: DefaultCDPrio = i; break; + case 4: DefaultBEVPrio = i; break; + } + } + } + + loadBootOrder(); +} + + +/**************************************************************** + * BootList handling + ****************************************************************/ + +struct bootentry_s { + int type; + union { + u32 data; + struct segoff_s vector; + struct drive_s *drive; + }; + int priority; + const char *description; + struct bootentry_s *next; +}; +static struct bootentry_s *BootList; + +#define IPL_TYPE_FLOPPY 0x01 +#define IPL_TYPE_HARDDISK 0x02 +#define IPL_TYPE_CDROM 0x03 +#define IPL_TYPE_CBFS 0x20 +#define IPL_TYPE_BEV 0x80 +#define IPL_TYPE_BCV 0x81 + +static void +bootentry_add(int type, int prio, u32 data, const char *desc) +{ + if (! CONFIG_BOOT) + return; + struct bootentry_s *be = malloc_tmp(sizeof(*be)); + if (!be) { + warn_noalloc(); + return; + } + be->type = type; + be->priority = prio; + be->data = data; + be->description = desc ?: "?"; + dprintf(3, "Registering bootable: %s (type:%d prio:%d data:%x)\n" + , be->description, type, prio, data); + + // Add entry in sorted order. + struct bootentry_s **pprev; + for (pprev = &BootList; *pprev; pprev = &(*pprev)->next) { + struct bootentry_s *pos = *pprev; + if (be->priority < pos->priority) + break; + if (be->priority > pos->priority) + continue; + if (be->type < pos->type) + break; + if (be->type > pos->type) + continue; + if (be->type <= IPL_TYPE_CDROM + && (be->drive->type < pos->drive->type + || (be->drive->type == pos->drive->type + && be->drive->cntl_id < pos->drive->cntl_id))) + break; + } + be->next = *pprev; + *pprev = be; +} + +// Return the given priority if it's set - defaultprio otherwise. +static inline int defPrio(int priority, int defaultprio) { + return (priority < 0) ? defaultprio : priority; +} + +// Add a BEV vector for a given pnp compatible option rom. +void +boot_add_bev(u16 seg, u16 bev, u16 desc, int prio) +{ + bootentry_add(IPL_TYPE_BEV, defPrio(prio, DefaultBEVPrio) + , SEGOFF(seg, bev).segoff + , desc ? MAKE_FLATPTR(seg, desc) : "Unknown"); + DefaultBEVPrio = DEFAULT_PRIO; +} + +// Add a bcv entry for an expansion card harddrive or legacy option rom +void +boot_add_bcv(u16 seg, u16 ip, u16 desc, int prio) +{ + bootentry_add(IPL_TYPE_BCV, defPrio(prio, DEFAULT_PRIO) + , SEGOFF(seg, ip).segoff + , desc ? MAKE_FLATPTR(seg, desc) : "Legacy option rom"); +} + +void +boot_add_floppy(struct drive_s *drive_g, const char *desc, int prio) +{ + bootentry_add(IPL_TYPE_FLOPPY, defPrio(prio, DefaultFloppyPrio) + , (u32)drive_g, desc); +} + +void +boot_add_hd(struct drive_s *drive_g, const char *desc, int prio) +{ + bootentry_add(IPL_TYPE_HARDDISK, defPrio(prio, DefaultHDPrio) + , (u32)drive_g, desc); +} + +void +boot_add_cd(struct drive_s *drive_g, const char *desc, int prio) +{ + bootentry_add(IPL_TYPE_CDROM, defPrio(prio, DefaultCDPrio) + , (u32)drive_g, desc); +} + +// Add a CBFS payload entry +void +boot_add_cbfs(void *data, const char *desc, int prio) +{ + bootentry_add(IPL_TYPE_CBFS, defPrio(prio, DEFAULT_PRIO), (u32)data, desc); +} + + +/**************************************************************** + * Boot menu and BCV execution + ****************************************************************/ + +#define DEFAULT_BOOTMENU_WAIT 2500 + +// Show IPL option menu. +static void +interactive_bootmenu(void) +{ + if (! CONFIG_BOOTMENU || ! qemu_cfg_show_boot_menu()) + return; + + while (get_keystroke(0) >= 0) + ; + + printf("Press F12 for boot menu.\n\n"); + + u32 menutime = romfile_loadint("etc/boot-menu-wait", DEFAULT_BOOTMENU_WAIT); + enable_bootsplash(); + int scan_code = get_keystroke(menutime); + disable_bootsplash(); + if (scan_code != 0x86) + /* not F12 */ + return; + + while (get_keystroke(0) >= 0) + ; + + printf("Select boot device:\n\n"); + wait_threads(); + + // Show menu items + struct bootentry_s *pos = BootList; + int maxmenu = 0; + while (pos) { + char desc[60]; + maxmenu++; + printf("%d. %s\n", maxmenu + , strtcpy(desc, pos->description, ARRAY_SIZE(desc))); + pos = pos->next; + } + + // Get key press + for (;;) { + scan_code = get_keystroke(1000); + if (scan_code >= 1 && scan_code <= maxmenu+1) + break; + } + printf("\n"); + if (scan_code == 0x01) + // ESC + return; + + // Find entry and make top priority. + int choice = scan_code - 1; + struct bootentry_s **pprev = &BootList; + while (--choice) + pprev = &(*pprev)->next; + pos = *pprev; + *pprev = pos->next; + pos->next = BootList; + BootList = pos; + pos->priority = 0; +} + +// BEV (Boot Execution Vector) list +struct bev_s { + int type; + u32 vector; +}; +static struct bev_s BEV[20]; +static int BEVCount; +static int HaveHDBoot, HaveFDBoot; + +static void +add_bev(int type, u32 vector) +{ + if (type == IPL_TYPE_HARDDISK && HaveHDBoot++) + return; + if (type == IPL_TYPE_FLOPPY && HaveFDBoot++) + return; + if (BEVCount >= ARRAY_SIZE(BEV)) + return; + struct bev_s *bev = &BEV[BEVCount++]; + bev->type = type; + bev->vector = vector; +} + +// Prepare for boot - show menu and run bcvs. +void +boot_prep(void) +{ + if (! CONFIG_BOOT) { + wait_threads(); + return; + } + + // XXX - show available drives? + + // Allow user to modify BCV/IPL order. + interactive_bootmenu(); + wait_threads(); + + // Map drives and populate BEV list + struct bootentry_s *pos = BootList; + while (pos) { + switch (pos->type) { + case IPL_TYPE_BCV: + call_bcv(pos->vector.seg, pos->vector.offset); + add_bev(IPL_TYPE_HARDDISK, 0); + break; + case IPL_TYPE_FLOPPY: + map_floppy_drive(pos->drive); + add_bev(IPL_TYPE_FLOPPY, 0); + break; + case IPL_TYPE_HARDDISK: + map_hd_drive(pos->drive); + add_bev(IPL_TYPE_HARDDISK, 0); + break; + case IPL_TYPE_CDROM: + map_cd_drive(pos->drive); + // NO BREAK + default: + add_bev(pos->type, pos->data); + break; + } + pos = pos->next; + } + + // If nothing added a floppy/hd boot - add it manually. + add_bev(IPL_TYPE_FLOPPY, 0); + add_bev(IPL_TYPE_HARDDISK, 0); +} + + +/**************************************************************** + * Boot code (int 18/19) + ****************************************************************/ + +// Jump to a bootup entry point. +static void +call_boot_entry(struct segoff_s bootsegip, u8 bootdrv) +{ + dprintf(1, "Booting from %04x:%04x\n", bootsegip.seg, bootsegip.offset); + struct bregs br; + memset(&br, 0, sizeof(br)); + br.flags = F_IF; + br.code = bootsegip; + // Set the magic number in ax and the boot drive in dl. + br.dl = bootdrv; + br.ax = 0xaa55; + call16(&br); +} + +// Boot from a disk (either floppy or harddrive) +static void +boot_disk(u8 bootdrv, int checksig) +{ + u16 bootseg = 0x07c0; + + // Read sector + struct bregs br; + memset(&br, 0, sizeof(br)); + br.flags = F_IF; + br.dl = bootdrv; + br.es = bootseg; + br.ah = 2; + br.al = 1; + br.cl = 1; + call16_int(0x13, &br); + + if (br.flags & F_CF) { + printf("Boot failed: could not read the boot disk\n\n"); + return; + } + + if (checksig) { + struct mbr_s *mbr = (void*)0; + if (GET_FARVAR(bootseg, mbr->signature) != MBR_SIGNATURE) { + printf("Boot failed: not a bootable disk\n\n"); + return; + } + } + + /* Canonicalize bootseg:bootip */ + u16 bootip = (bootseg & 0x0fff) << 4; + bootseg &= 0xf000; + + call_boot_entry(SEGOFF(bootseg, bootip), bootdrv); +} + +// Boot from a CD-ROM +static void +boot_cdrom(struct drive_s *drive_g) +{ + if (! CONFIG_CDROM_BOOT) + return; + printf("Booting from DVD/CD...\n"); + + int status = cdrom_boot(drive_g); + if (status) { + printf("Boot failed: Could not read from CDROM (code %04x)\n", status); + return; + } + + u16 ebda_seg = get_ebda_seg(); + u8 bootdrv = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive); + u16 bootseg = GET_EBDA2(ebda_seg, cdemu.load_segment); + /* Canonicalize bootseg:bootip */ + u16 bootip = (bootseg & 0x0fff) << 4; + bootseg &= 0xf000; + + call_boot_entry(SEGOFF(bootseg, bootip), bootdrv); +} + +// Boot from a CBFS payload +static void +boot_cbfs(struct cbfs_file *file) +{ + if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH) + return; + printf("Booting from CBFS...\n"); + cbfs_run_payload(file); +} + +// Boot from a BEV entry on an optionrom. +static void +boot_rom(u32 vector) +{ + printf("Booting from ROM...\n"); + struct segoff_s so; + so.segoff = vector; + call_boot_entry(so, 0); +} + +// Determine next boot method and attempt a boot using it. +static void +do_boot(u16 seq_nr) +{ + if (! CONFIG_BOOT) + panic("Boot support not compiled in.\n"); + + if (seq_nr >= BEVCount) { + printf("No bootable device.\n"); + // Loop with irqs enabled - this allows ctrl+alt+delete to work. + for (;;) + wait_irq(); + } + + // Boot the given BEV type. + struct bev_s *ie = &BEV[seq_nr]; + switch (ie->type) { + case IPL_TYPE_FLOPPY: + printf("Booting from Floppy...\n"); + boot_disk(0x00, CheckFloppySig); + break; + case IPL_TYPE_HARDDISK: + printf("Booting from Hard Disk...\n"); + boot_disk(0x80, 1); + break; + case IPL_TYPE_CDROM: + boot_cdrom((void*)ie->vector); + break; + case IPL_TYPE_CBFS: + boot_cbfs((void*)ie->vector); + break; + case IPL_TYPE_BEV: + boot_rom(ie->vector); + break; + } + + // Boot failed: invoke the boot recovery function + struct bregs br; + memset(&br, 0, sizeof(br)); + br.flags = F_IF; + call16_int(0x18, &br); +} + +// Boot Failure recovery: try the next device. +void VISIBLE32FLAT +handle_18(void) +{ + debug_serial_setup(); + debug_enter(NULL, DEBUG_HDL_18); + u16 ebda_seg = get_ebda_seg(); + u16 seq = GET_EBDA2(ebda_seg, boot_sequence) + 1; + SET_EBDA2(ebda_seg, boot_sequence, seq); + do_boot(seq); +} + +// INT 19h Boot Load Service Entry Point +void VISIBLE32FLAT +handle_19(void) +{ + debug_serial_setup(); + debug_enter(NULL, DEBUG_HDL_19); + SET_EBDA(boot_sequence, 0); + do_boot(0); +} diff --git a/bios/seabios/src/boot.h b/bios/seabios/src/boot.h new file mode 100644 index 0000000..d776aa1 --- /dev/null +++ b/bios/seabios/src/boot.h @@ -0,0 +1,23 @@ +// Storage for boot definitions. +#ifndef __BOOT_H +#define __BOOT_H + +// boot.c +void boot_setup(void); +void boot_add_bev(u16 seg, u16 bev, u16 desc, int prio); +void boot_add_bcv(u16 seg, u16 ip, u16 desc, int prio); +struct drive_s; +void boot_add_floppy(struct drive_s *drive_g, const char *desc, int prio); +void boot_add_hd(struct drive_s *drive_g, const char *desc, int prio); +void boot_add_cd(struct drive_s *drive_g, const char *desc, int prio); +void boot_add_cbfs(void *data, const char *desc, int prio); +void boot_prep(void); +struct pci_device; +int bootprio_find_pci_device(struct pci_device *pci); +int bootprio_find_ata_device(struct pci_device *pci, int chanid, int slave); +int bootprio_find_fdc_device(struct pci_device *pci, int port, int fdid); +int bootprio_find_pci_rom(struct pci_device *pci, int instance); +int bootprio_find_named_rom(const char *name, int instance); +int bootprio_find_usb(struct pci_device *pci, u64 path); + +#endif // __BOOT_H diff --git a/bios/seabios/src/bootsplash.c b/bios/seabios/src/bootsplash.c new file mode 100644 index 0000000..9c33b80 --- /dev/null +++ b/bios/seabios/src/bootsplash.c @@ -0,0 +1,309 @@ +// Option rom scanning code. +// +// Copyright (C) 2009-2010 coresystems GmbH +// Copyright (C) 2010 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "bregs.h" // struct bregs +#include "farptr.h" // FLATPTR_TO_SEG +#include "config.h" // CONFIG_* +#include "util.h" // dprintf +#include "jpeg.h" // splash +#include "biosvar.h" // SET_EBDA +#include "paravirt.h" // romfile_find +#include "bmp.h" + +/**************************************************************** + * VESA structures + ****************************************************************/ + +struct vesa_info { + u32 vesa_signature; + u16 vesa_version; + struct segoff_s oem_string_ptr; + u8 capabilities[4]; + struct segoff_s video_mode_ptr; + u16 total_memory; + u16 oem_software_rev; + struct segoff_s oem_vendor_name_ptr; + struct segoff_s oem_product_name_ptr; + struct segoff_s oem_product_rev_ptr; + u8 reserved[222]; + u8 oem_data[256]; +} PACKED; + +#define VESA_SIGNATURE 0x41534556 // VESA +#define VBE2_SIGNATURE 0x32454256 // VBE2 + +struct vesa_mode_info { + u16 mode_attributes; + u8 win_a_attributes; + u8 win_b_attributes; + u16 win_granularity; + u16 win_size; + u16 win_a_segment; + u16 win_b_segment; + u32 win_func_ptr; + u16 bytes_per_scanline; + u16 x_resolution; + u16 y_resolution; + u8 x_charsize; + u8 y_charsize; + u8 number_of_planes; + u8 bits_per_pixel; + u8 number_of_banks; + u8 memory_model; + u8 bank_size; + u8 number_of_image_pages; + u8 reserved_page; + u8 red_mask_size; + u8 red_mask_pos; + u8 green_mask_size; + u8 green_mask_pos; + u8 blue_mask_size; + u8 blue_mask_pos; + u8 reserved_mask_size; + u8 reserved_mask_pos; + u8 direct_color_mode_info; + void *phys_base_ptr; + u32 offscreen_mem_offset; + u16 offscreen_mem_size; + u8 reserved[206]; +} PACKED; + + +/**************************************************************** + * Helper functions + ****************************************************************/ + +// Call int10 vga handler. +static void +call16_int10(struct bregs *br) +{ + br->flags = F_IF; + start_preempt(); + call16_int(0x10, br); + finish_preempt(); +} + + +/**************************************************************** + * VGA text / graphics console + ****************************************************************/ + +void +enable_vga_console(void) +{ + dprintf(1, "Turning on vga text mode console\n"); + struct bregs br; + + /* Enable VGA text mode */ + memset(&br, 0, sizeof(br)); + br.ax = 0x0003; + call16_int10(&br); + + // Write to screen. + printf("SeaBIOS (version %s)\n\n", VERSION); +} + +static int +find_videomode(struct vesa_info *vesa_info, struct vesa_mode_info *mode_info + , int width, int height, int bpp_req) +{ + dprintf(3, "Finding vesa mode with dimensions %d/%d\n", width, height); + u16 *videomodes = SEGOFF_TO_FLATPTR(vesa_info->video_mode_ptr); + for (;; videomodes++) { + u16 videomode = *videomodes; + if (videomode == 0xffff) { + dprintf(1, "Unable to find vesa video mode dimensions %d/%d\n" + , width, height); + return -1; + } + struct bregs br; + memset(&br, 0, sizeof(br)); + br.ax = 0x4f01; + br.cx = (1 << 14) | videomode; + br.di = FLATPTR_TO_OFFSET(mode_info); + br.es = FLATPTR_TO_SEG(mode_info); + call16_int10(&br); + if (br.ax != 0x4f) { + dprintf(1, "get_mode failed.\n"); + continue; + } + if (mode_info->x_resolution != width + || mode_info->y_resolution != height) + continue; + u8 depth = mode_info->bits_per_pixel; + if (bpp_req == 0) { + if (depth != 16 && depth != 24 && depth != 32) + continue; + } else { + if (depth != bpp_req) + continue; + } + return videomode; + } +} + +static int BootsplashActive; + +void +enable_bootsplash(void) +{ + if (!CONFIG_BOOTSPLASH) + return; + /* splash picture can be bmp or jpeg file */ + dprintf(3, "Checking for bootsplash\n"); + u8 type = 0; /* 0 means jpg, 1 means bmp, default is 0=jpg */ + int filesize; + u8 *filedata = romfile_loadfile("bootsplash.jpg", &filesize); + if (!filedata) { + filedata = romfile_loadfile("bootsplash.bmp", &filesize); + if (!filedata) + return; + type = 1; + } + dprintf(3, "start showing bootsplash\n"); + + u8 *picture = NULL; /* data buff used to be flushed to the video buf */ + struct jpeg_decdata *jpeg = NULL; + struct bmp_decdata *bmp = NULL; + struct vesa_info *vesa_info = malloc_tmplow(sizeof(*vesa_info)); + struct vesa_mode_info *mode_info = malloc_tmplow(sizeof(*mode_info)); + if (!vesa_info || !mode_info) { + warn_noalloc(); + goto done; + } + + /* Check whether we have a VESA 2.0 compliant BIOS */ + memset(vesa_info, 0, sizeof(struct vesa_info)); + vesa_info->vesa_signature = VBE2_SIGNATURE; + struct bregs br; + memset(&br, 0, sizeof(br)); + br.ax = 0x4f00; + br.di = FLATPTR_TO_OFFSET(vesa_info); + br.es = FLATPTR_TO_SEG(vesa_info); + call16_int10(&br); + if (vesa_info->vesa_signature != VESA_SIGNATURE) { + dprintf(1,"No VBE2 found.\n"); + goto done; + } + + /* Print some debugging information about our card. */ + char *vendor = SEGOFF_TO_FLATPTR(vesa_info->oem_vendor_name_ptr); + char *product = SEGOFF_TO_FLATPTR(vesa_info->oem_product_name_ptr); + dprintf(3, "VESA %d.%d\nVENDOR: %s\nPRODUCT: %s\n", + vesa_info->vesa_version>>8, vesa_info->vesa_version&0xff, + vendor, product); + + int ret, width, height; + int bpp_require = 0; + if (type == 0) { + jpeg = jpeg_alloc(); + if (!jpeg) { + warn_noalloc(); + goto done; + } + /* Parse jpeg and get image size. */ + dprintf(5, "Decoding bootsplash.jpg\n"); + ret = jpeg_decode(jpeg, filedata); + if (ret) { + dprintf(1, "jpeg_decode failed with return code %d...\n", ret); + goto done; + } + jpeg_get_size(jpeg, &width, &height); + } else { + bmp = bmp_alloc(); + if (!bmp) { + warn_noalloc(); + goto done; + } + /* Parse bmp and get image size. */ + dprintf(5, "Decoding bootsplash.bmp\n"); + ret = bmp_decode(bmp, filedata, filesize); + if (ret) { + dprintf(1, "bmp_decode failed with return code %d...\n", ret); + goto done; + } + bmp_get_size(bmp, &width, &height); + bpp_require = 24; + } + /* jpeg would use 16 or 24 bpp video mode, BMP use 24bpp mode only */ + + // Try to find a graphics mode with the corresponding dimensions. + int videomode = find_videomode(vesa_info, mode_info, width, height, + bpp_require); + if (videomode < 0) { + dprintf(1, "failed to find a videomode with %dx%d %dbpp (0=any).\n", + width, height, bpp_require); + goto done; + } + void *framebuffer = mode_info->phys_base_ptr; + int depth = mode_info->bits_per_pixel; + dprintf(3, "mode: %04x\n", videomode); + dprintf(3, "framebuffer: %p\n", framebuffer); + dprintf(3, "bytes per scanline: %d\n", mode_info->bytes_per_scanline); + dprintf(3, "bits per pixel: %d\n", depth); + + // Allocate space for image and decompress it. + int imagesize = height * mode_info->bytes_per_scanline; + picture = malloc_tmphigh(imagesize); + if (!picture) { + warn_noalloc(); + goto done; + } + + if (type == 0) { + dprintf(5, "Decompressing bootsplash.jpg\n"); + ret = jpeg_show(jpeg, picture, width, height, depth, + mode_info->bytes_per_scanline); + if (ret) { + dprintf(1, "jpeg_show failed with return code %d...\n", ret); + goto done; + } + } else { + dprintf(5, "Decompressing bootsplash.bmp\n"); + ret = bmp_show(bmp, picture, width, height, depth, + mode_info->bytes_per_scanline); + if (ret) { + dprintf(1, "bmp_show failed with return code %d...\n", ret); + goto done; + } + } + + /* Switch to graphics mode */ + dprintf(5, "Switching to graphics mode\n"); + memset(&br, 0, sizeof(br)); + br.ax = 0x4f02; + br.bx = (1 << 14) | videomode; + call16_int10(&br); + if (br.ax != 0x4f) { + dprintf(1, "set_mode failed.\n"); + goto done; + } + + /* Show the picture */ + dprintf(5, "Showing bootsplash picture\n"); + iomemcpy(framebuffer, picture, imagesize); + dprintf(5, "Bootsplash copy complete\n"); + BootsplashActive = 1; + +done: + free(filedata); + free(picture); + free(vesa_info); + free(mode_info); + free(jpeg); + free(bmp); + return; +} + +void +disable_bootsplash(void) +{ + if (!CONFIG_BOOTSPLASH || !BootsplashActive) + return; + BootsplashActive = 0; + enable_vga_console(); +} diff --git a/bios/seabios/src/bregs.h b/bios/seabios/src/bregs.h new file mode 100644 index 0000000..f026fa8 --- /dev/null +++ b/bios/seabios/src/bregs.h @@ -0,0 +1,96 @@ +// Structure layout of cpu registers the the bios uses. +// +// Copyright (C) 2008 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#ifndef __BREGS_H +#define __BREGS_H + +// CPU flag bitdefs +#define F_CF (1<<0) +#define F_ZF (1<<6) +#define F_IF (1<<9) + +// CR0 flags +#define CR0_PG (1<<31) // Paging +#define CR0_CD (1<<30) // Cache disable +#define CR0_NW (1<<29) // Not Write-through +#define CR0_PE (1<<0) // Protection enable + + +#ifndef __ASSEMBLY__ + +#include "farptr.h" // struct segoff_s + +/**************************************************************** + * Registers saved/restored in romlayout.S + ****************************************************************/ + +#include "types.h" // u16 + +#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; }; } + +// Layout of registers passed in to irq handlers. Note that this +// layout corresponds to code in romlayout.S - don't change it here +// without also updating the assembler code. +struct bregs { + u16 ds; + u16 es; + UREG(edi, di, di8u, di8l); + UREG(esi, si, si8u, si8l); + UREG(ebp, bp, bp8u, bp8l); + UREG(ebx, bx, bh, bl); + UREG(edx, dx, dh, dl); + UREG(ecx, cx, ch, cl); + UREG(eax, ax, ah, al); + struct segoff_s code; + u16 flags; +} PACKED; + + +/**************************************************************** + * Helper functions + ****************************************************************/ + +static inline void +set_cf(struct bregs *regs, int cond) +{ + if (cond) + regs->flags |= F_CF; + else + regs->flags &= ~F_CF; +} + +// Frequently used return codes +#define RET_EUNSUPPORTED 0x86 + +static inline void +set_success(struct bregs *regs) +{ + set_cf(regs, 0); +} + +static inline void +set_code_success(struct bregs *regs) +{ + regs->ah = 0; + set_cf(regs, 0); +} + +static inline void +set_invalid_silent(struct bregs *regs) +{ + set_cf(regs, 1); +} + +static inline void +set_code_invalid_silent(struct bregs *regs, u8 code) +{ + regs->ah = code; + set_cf(regs, 1); +} + +#endif // !__ASSEMBLY__ + +#endif // bregs.h diff --git a/bios/seabios/src/cdrom.c b/bios/seabios/src/cdrom.c new file mode 100644 index 0000000..6351fec --- /dev/null +++ b/bios/seabios/src/cdrom.c @@ -0,0 +1,377 @@ +// Support for booting from cdroms (the "El Torito" spec). +// +// Copyright (C) 2008,2009 Kevin O'Connor +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "disk.h" // cdrom_13 +#include "util.h" // memset +#include "bregs.h" // struct bregs +#include "biosvar.h" // GET_EBDA +#include "ata.h" // ATA_CMD_REQUEST_SENSE +#include "blockcmd.h" // CDB_CMD_REQUEST_SENSE + + +/**************************************************************** + * CD emulation + ****************************************************************/ + +struct drive_s *cdemu_drive_gf VAR16VISIBLE; + +static int +cdemu_read(struct disk_op_s *op) +{ + u16 ebda_seg = get_ebda_seg(); + struct drive_s *drive_g; + drive_g = GLOBALFLAT2GLOBAL(GET_EBDA2(ebda_seg, cdemu.emulated_drive_gf)); + struct disk_op_s dop; + dop.drive_g = drive_g; + dop.command = op->command; + dop.lba = GET_EBDA2(ebda_seg, cdemu.ilba) + op->lba / 4; + + int count = op->count; + op->count = 0; + u8 *cdbuf_fl = GET_GLOBAL(bounce_buf_fl); + + if (op->lba & 3) { + // Partial read of first block. + dop.count = 1; + dop.buf_fl = cdbuf_fl; + int ret = process_op(&dop); + if (ret) + return ret; + u8 thiscount = 4 - (op->lba & 3); + if (thiscount > count) + thiscount = count; + count -= thiscount; + memcpy_fl(op->buf_fl, cdbuf_fl + (op->lba & 3) * 512, thiscount * 512); + op->buf_fl += thiscount * 512; + op->count += thiscount; + dop.lba++; + } + + if (count > 3) { + // Read n number of regular blocks. + dop.count = count / 4; + dop.buf_fl = op->buf_fl; + int ret = process_op(&dop); + op->count += dop.count * 4; + if (ret) + return ret; + u8 thiscount = count & ~3; + count &= 3; + op->buf_fl += thiscount * 512; + dop.lba += thiscount / 4; + } + + if (count) { + // Partial read on last block. + dop.count = 1; + dop.buf_fl = cdbuf_fl; + int ret = process_op(&dop); + if (ret) + return ret; + u8 thiscount = count; + memcpy_fl(op->buf_fl, cdbuf_fl, thiscount * 512); + op->count += thiscount; + } + + return DISK_RET_SUCCESS; +} + +int +process_cdemu_op(struct disk_op_s *op) +{ + if (!CONFIG_CDROM_EMU) + return 0; + + switch (op->command) { + case CMD_READ: + return cdemu_read(op); + case CMD_WRITE: + case CMD_FORMAT: + return DISK_RET_EWRITEPROTECT; + case CMD_VERIFY: + case CMD_RESET: + case CMD_SEEK: + case CMD_ISREADY: + return DISK_RET_SUCCESS; + default: + op->count = 0; + return DISK_RET_EPARAM; + } +} + +void +cdemu_setup(void) +{ + if (!CONFIG_CDROM_EMU) + return; + if (!CDCount) + return; + if (bounce_buf_init() < 0) + return; + + struct drive_s *drive_g = malloc_fseg(sizeof(*drive_g)); + if (!drive_g) { + warn_noalloc(); + free(drive_g); + return; + } + cdemu_drive_gf = drive_g; + memset(drive_g, 0, sizeof(*drive_g)); + drive_g->type = DTYPE_CDEMU; + drive_g->blksize = DISK_SECTOR_SIZE; + drive_g->sectors = (u64)-1; +} + +struct eltorito_s { + u8 size; + u8 media; + u8 emulated_drive; + u8 controller_index; + u32 ilba; + u16 device_spec; + u16 buffer_segment; + u16 load_segment; + u16 sector_count; + u8 cylinders; + u8 sectors; + u8 heads; +}; + +#define SET_INT13ET(regs,var,val) \ + SET_FARVAR((regs)->ds, ((struct eltorito_s*)((regs)->si+0))->var, (val)) + +// ElTorito - Terminate disk emu +void +cdemu_134b(struct bregs *regs) +{ + // FIXME ElTorito Hardcoded + u16 ebda_seg = get_ebda_seg(); + SET_INT13ET(regs, size, 0x13); + SET_INT13ET(regs, media, GET_EBDA2(ebda_seg, cdemu.media)); + SET_INT13ET(regs, emulated_drive + , GET_EBDA2(ebda_seg, cdemu.emulated_extdrive)); + struct drive_s *drive_gf = GET_EBDA2(ebda_seg, cdemu.emulated_drive_gf); + u8 cntl_id = 0; + if (drive_gf) + cntl_id = GET_GLOBALFLAT(drive_gf->cntl_id); + SET_INT13ET(regs, controller_index, cntl_id / 2); + SET_INT13ET(regs, device_spec, cntl_id % 2); + SET_INT13ET(regs, ilba, GET_EBDA2(ebda_seg, cdemu.ilba)); + SET_INT13ET(regs, buffer_segment, GET_EBDA2(ebda_seg, cdemu.buffer_segment)); + SET_INT13ET(regs, load_segment, GET_EBDA2(ebda_seg, cdemu.load_segment)); + SET_INT13ET(regs, sector_count, GET_EBDA2(ebda_seg, cdemu.sector_count)); + SET_INT13ET(regs, cylinders, GET_EBDA2(ebda_seg, cdemu.lchs.cylinders)); + SET_INT13ET(regs, sectors, GET_EBDA2(ebda_seg, cdemu.lchs.spt)); + SET_INT13ET(regs, heads, GET_EBDA2(ebda_seg, cdemu.lchs.heads)); + + // If we have to terminate emulation + if (regs->al == 0x00) { + // FIXME ElTorito Various. Should be handled accordingly to spec + SET_EBDA2(ebda_seg, cdemu.active, 0x00); // bye bye + + // XXX - update floppy/hd count. + } + + disk_ret(regs, DISK_RET_SUCCESS); +} + + +/**************************************************************** + * CD booting + ****************************************************************/ + +static int +atapi_is_ready(struct disk_op_s *op) +{ + dprintf(6, "atapi_is_ready (drive=%p)\n", op->drive_g); + + /* Retry READ CAPACITY for 5 seconds unless MEDIUM NOT PRESENT is + * reported by the device. If the device reports "IN PROGRESS", + * 30 seconds is added. */ + struct cdbres_read_capacity info; + int in_progress = 0; + u64 end = calc_future_tsc(5000); + for (;;) { + if (check_tsc(end)) { + dprintf(1, "read capacity failed\n"); + return -1; + } + + int ret = cdb_read_capacity(op, &info); + if (!ret) + // Success + break; + + struct cdbres_request_sense sense; + ret = cdb_get_sense(op, &sense); + if (ret) + // Error - retry. + continue; + + // Sense succeeded. + if (sense.asc == 0x3a) { /* MEDIUM NOT PRESENT */ + dprintf(1, "Device reports MEDIUM NOT PRESENT\n"); + return -1; + } + + if (sense.asc == 0x04 && sense.ascq == 0x01 && !in_progress) { + /* IN PROGRESS OF BECOMING READY */ + printf("Waiting for device to detect medium... "); + /* Allow 30 seconds more */ + end = calc_future_tsc(30000); + in_progress = 1; + } + } + + u32 blksize = ntohl(info.blksize), sectors = ntohl(info.sectors); + if (blksize != GET_GLOBAL(op->drive_g->blksize)) { + printf("Unsupported sector size %u\n", blksize); + return -1; + } + + dprintf(6, "sectors=%u\n", sectors); + printf("%dMB medium detected\n", sectors>>(20-11)); + return 0; +} + +int +cdrom_boot(struct drive_s *drive_g) +{ + struct disk_op_s dop; + int cdid = getDriveId(EXTTYPE_CD, drive_g); + memset(&dop, 0, sizeof(dop)); + dop.drive_g = drive_g; + if (!dop.drive_g || cdid < 0) + return 1; + + int ret = atapi_is_ready(&dop); + if (ret) + dprintf(1, "atapi_is_ready returned %d\n", ret); + + // Read the Boot Record Volume Descriptor + u8 buffer[2048]; + dop.lba = 0x11; + dop.count = 1; + dop.buf_fl = MAKE_FLATPTR(GET_SEG(SS), buffer); + ret = cdb_read(&dop); + if (ret) + return 3; + + // Validity checks + if (buffer[0]) + return 4; + if (strcmp((char*)&buffer[1], "CD001\001EL TORITO SPECIFICATION") != 0) + return 5; + + // ok, now we calculate the Boot catalog address + u32 lba = *(u32*)&buffer[0x47]; + + // And we read the Boot Catalog + dop.lba = lba; + dop.count = 1; + ret = cdb_read(&dop); + if (ret) + return 7; + + // Validation entry + if (buffer[0x00] != 0x01) + return 8; // Header + if (buffer[0x01] != 0x00) + return 9; // Platform + if (buffer[0x1E] != 0x55) + return 10; // key 1 + if (buffer[0x1F] != 0xAA) + return 10; // key 2 + + // Initial/Default Entry + if (buffer[0x20] != 0x88) + return 11; // Bootable + + u16 ebda_seg = get_ebda_seg(); + u8 media = buffer[0x21]; + SET_EBDA2(ebda_seg, cdemu.media, media); + + SET_EBDA2(ebda_seg, cdemu.emulated_drive_gf, dop.drive_g); + + u16 boot_segment = *(u16*)&buffer[0x22]; + if (!boot_segment) + boot_segment = 0x07C0; + SET_EBDA2(ebda_seg, cdemu.load_segment, boot_segment); + SET_EBDA2(ebda_seg, cdemu.buffer_segment, 0x0000); + + u16 nbsectors = *(u16*)&buffer[0x26]; + SET_EBDA2(ebda_seg, cdemu.sector_count, nbsectors); + + lba = *(u32*)&buffer[0x28]; + SET_EBDA2(ebda_seg, cdemu.ilba, lba); + + // And we read the image in memory + dop.lba = lba; + dop.count = DIV_ROUND_UP(nbsectors, 4); + dop.buf_fl = MAKE_FLATPTR(boot_segment, 0); + ret = cdb_read(&dop); + if (ret) + return 12; + + if (media == 0) { + // No emulation requested - return success. + SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, EXTSTART_CD + cdid); + return 0; + } + + // Emulation of a floppy/harddisk requested + if (! CONFIG_CDROM_EMU || !cdemu_drive_gf) + return 13; + + // Set emulated drive id and increase bios installed hardware + // number of devices + if (media < 4) { + // Floppy emulation + SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, 0x00); + // XXX - get and set actual floppy count. + SETBITS_BDA(equipment_list_flags, 0x41); + + switch (media) { + case 0x01: // 1.2M floppy + SET_EBDA2(ebda_seg, cdemu.lchs.spt, 15); + SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80); + SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2); + break; + case 0x02: // 1.44M floppy + SET_EBDA2(ebda_seg, cdemu.lchs.spt, 18); + SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80); + SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2); + break; + case 0x03: // 2.88M floppy + SET_EBDA2(ebda_seg, cdemu.lchs.spt, 36); + SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80); + SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2); + break; + } + } else { + // Harddrive emulation + SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, 0x80); + SET_BDA(hdcount, GET_BDA(hdcount) + 1); + + // Peak at partition table to get chs. + struct mbr_s *mbr = (void*)0; + u8 sptcyl = GET_FARVAR(boot_segment, mbr->partitions[0].last.sptcyl); + u8 cyllow = GET_FARVAR(boot_segment, mbr->partitions[0].last.cyllow); + u8 heads = GET_FARVAR(boot_segment, mbr->partitions[0].last.heads); + + SET_EBDA2(ebda_seg, cdemu.lchs.spt, sptcyl & 0x3f); + SET_EBDA2(ebda_seg, cdemu.lchs.cylinders + , ((sptcyl<<2)&0x300) + cyllow + 1); + SET_EBDA2(ebda_seg, cdemu.lchs.heads, heads + 1); + } + + // everything is ok, so from now on, the emulation is active + SET_EBDA2(ebda_seg, cdemu.active, 0x01); + dprintf(6, "cdemu media=%d\n", media); + + return 0; +} diff --git a/bios/seabios/src/clock.c b/bios/seabios/src/clock.c new file mode 100644 index 0000000..fcdc698 --- /dev/null +++ b/bios/seabios/src/clock.c @@ -0,0 +1,650 @@ +// 16bit code to handle system clocks. +// +// Copyright (C) 2008-2010 Kevin O'Connor +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "biosvar.h" // SET_BDA +#include "util.h" // debug_enter +#include "disk.h" // floppy_tick +#include "cmos.h" // inb_cmos +#include "pic.h" // eoi_pic1 +#include "bregs.h" // struct bregs +#include "biosvar.h" // GET_GLOBAL +#include "usb-hid.h" // usb_check_event + +// RTC register flags +#define RTC_A_UIP 0x80 + +#define RTC_B_SET 0x80 +#define RTC_B_PIE 0x40 +#define RTC_B_AIE 0x20 +#define RTC_B_UIE 0x10 +#define RTC_B_BIN 0x04 +#define RTC_B_24HR 0x02 +#define RTC_B_DSE 0x01 + + +// Bits for PORT_PS2_CTRLB +#define PPCB_T2GATE (1<<0) +#define PPCB_SPKR (1<<1) +#define PPCB_T2OUT (1<<5) + +// Bits for PORT_PIT_MODE +#define PM_SEL_TIMER0 (0<<6) +#define PM_SEL_TIMER1 (1<<6) +#define PM_SEL_TIMER2 (2<<6) +#define PM_SEL_READBACK (3<<6) +#define PM_ACCESS_LATCH (0<<4) +#define PM_ACCESS_LOBYTE (1<<4) +#define PM_ACCESS_HIBYTE (2<<4) +#define PM_ACCESS_WORD (3<<4) +#define PM_MODE0 (0<<1) +#define PM_MODE1 (1<<1) +#define PM_MODE2 (2<<1) +#define PM_MODE3 (3<<1) +#define PM_MODE4 (4<<1) +#define PM_MODE5 (5<<1) +#define PM_CNT_BINARY (0<<0) +#define PM_CNT_BCD (1<<0) + + +/**************************************************************** + * TSC timer + ****************************************************************/ + +#define CALIBRATE_COUNT 0x800 // Approx 1.7ms + +u32 cpu_khz VAR16VISIBLE; + +static void +calibrate_tsc(void) +{ + // Setup "timer2" + u8 orig = inb(PORT_PS2_CTRLB); + outb((orig & ~PPCB_SPKR) | PPCB_T2GATE, PORT_PS2_CTRLB); + /* binary, mode 0, LSB/MSB, Ch 2 */ + outb(PM_SEL_TIMER2|PM_ACCESS_WORD|PM_MODE0|PM_CNT_BINARY, PORT_PIT_MODE); + /* LSB of ticks */ + outb(CALIBRATE_COUNT & 0xFF, PORT_PIT_COUNTER2); + /* MSB of ticks */ + outb(CALIBRATE_COUNT >> 8, PORT_PIT_COUNTER2); + + u64 start = rdtscll(); + while ((inb(PORT_PS2_CTRLB) & PPCB_T2OUT) == 0) + ; + u64 end = rdtscll(); + + // Restore PORT_PS2_CTRLB + outb(orig, PORT_PS2_CTRLB); + + // Store calibrated cpu khz. + u64 diff = end - start; + dprintf(6, "tsc calibrate start=%u end=%u diff=%u\n" + , (u32)start, (u32)end, (u32)diff); + u32 hz = diff * PIT_TICK_RATE / CALIBRATE_COUNT; + SET_GLOBAL(cpu_khz, hz / 1000); + + dprintf(1, "CPU Mhz=%u\n", hz / 1000000); +} + +static void +tscdelay(u64 diff) +{ + u64 start = rdtscll(); + u64 end = start + diff; + while (!check_tsc(end)) + cpu_relax(); +} + +static void +tscsleep(u64 diff) +{ + u64 start = rdtscll(); + u64 end = start + diff; + while (!check_tsc(end)) + yield(); +} + +void ndelay(u32 count) { + tscdelay(count * GET_GLOBAL(cpu_khz) / 1000000); +} +void udelay(u32 count) { + tscdelay(count * GET_GLOBAL(cpu_khz) / 1000); +} +void mdelay(u32 count) { + tscdelay(count * GET_GLOBAL(cpu_khz)); +} + +void nsleep(u32 count) { + tscsleep(count * GET_GLOBAL(cpu_khz) / 1000000); +} +void usleep(u32 count) { + tscsleep(count * GET_GLOBAL(cpu_khz) / 1000); +} +void msleep(u32 count) { + tscsleep(count * GET_GLOBAL(cpu_khz)); +} + +// Return the TSC value that is 'msecs' time in the future. +u64 +calc_future_tsc(u32 msecs) +{ + u32 khz = GET_GLOBAL(cpu_khz); + return rdtscll() + ((u64)khz * msecs); +} +u64 +calc_future_tsc_usec(u32 usecs) +{ + u32 khz = GET_GLOBAL(cpu_khz); + return rdtscll() + ((u64)(khz/1000) * usecs); +} + + +/**************************************************************** + * Init + ****************************************************************/ + +static int +rtc_updating(void) +{ + // This function checks to see if the update-in-progress bit + // is set in CMOS Status Register A. If not, it returns 0. + // If it is set, it tries to wait until there is a transition + // to 0, and will return 0 if such a transition occurs. A -1 + // is returned only after timing out. The maximum period + // that this bit should be set is constrained to (1984+244) + // useconds, but we wait for longer just to be sure. + + if ((inb_cmos(CMOS_STATUS_A) & RTC_A_UIP) == 0) + return 0; + u64 end = calc_future_tsc(15); + for (;;) { + if ((inb_cmos(CMOS_STATUS_A) & RTC_A_UIP) == 0) + return 0; + if (check_tsc(end)) + // update-in-progress never transitioned to 0 + return -1; + yield(); + } +} + +static void +pit_setup(void) +{ + // timer0: binary count, 16bit count, mode 2 + outb(PM_SEL_TIMER0|PM_ACCESS_WORD|PM_MODE2|PM_CNT_BINARY, PORT_PIT_MODE); + // maximum count of 0000H = 18.2Hz + outb(0x0, PORT_PIT_COUNTER0); + outb(0x0, PORT_PIT_COUNTER0); +} + +static void +init_rtc(void) +{ + outb_cmos(0x26, CMOS_STATUS_A); // 32,768Khz src, 976.5625us updates + u8 regB = inb_cmos(CMOS_STATUS_B); + outb_cmos((regB & RTC_B_DSE) | RTC_B_24HR, CMOS_STATUS_B); + inb_cmos(CMOS_STATUS_C); + inb_cmos(CMOS_STATUS_D); +} + +static u32 +bcd2bin(u8 val) +{ + return (val & 0xf) + ((val >> 4) * 10); +} + +void +timer_setup(void) +{ + dprintf(3, "init timer\n"); + calibrate_tsc(); + pit_setup(); + + init_rtc(); + rtc_updating(); + u32 seconds = bcd2bin(inb_cmos(CMOS_RTC_SECONDS)); + u32 minutes = bcd2bin(inb_cmos(CMOS_RTC_MINUTES)); + u32 hours = bcd2bin(inb_cmos(CMOS_RTC_HOURS)); + u32 ticks = (hours * 60 + minutes) * 60 + seconds; + ticks = ((u64)ticks * PIT_TICK_RATE) / PIT_TICK_INTERVAL; + SET_BDA(timer_counter, ticks); + + enable_hwirq(0, FUNC16(entry_08)); + enable_hwirq(8, FUNC16(entry_70)); +} + + +/**************************************************************** + * Standard clock functions + ****************************************************************/ + +#define TICKS_PER_DAY (u32)((u64)60*60*24*PIT_TICK_RATE / PIT_TICK_INTERVAL) + +// Calculate the timer value at 'count' number of full timer ticks in +// the future. +u32 +calc_future_timer_ticks(u32 count) +{ + return (GET_BDA(timer_counter) + count + 1) % TICKS_PER_DAY; +} + +// Return the timer value that is 'msecs' time in the future. +u32 +calc_future_timer(u32 msecs) +{ + if (!msecs) + return GET_BDA(timer_counter); + u32 kticks = DIV_ROUND_UP((u64)msecs * PIT_TICK_RATE, PIT_TICK_INTERVAL); + u32 ticks = DIV_ROUND_UP(kticks, 1000); + return calc_future_timer_ticks(ticks); +} + +// Check if the given timer value has passed. +int +check_timer(u32 end) +{ + return (((GET_BDA(timer_counter) + TICKS_PER_DAY - end) % TICKS_PER_DAY) + < (TICKS_PER_DAY/2)); +} + +// get current clock count +static void +handle_1a00(struct bregs *regs) +{ + yield(); + u32 ticks = GET_BDA(timer_counter); + regs->cx = ticks >> 16; + regs->dx = ticks; + regs->al = GET_BDA(timer_rollover); + SET_BDA(timer_rollover, 0); // reset flag + set_success(regs); +} + +// Set Current Clock Count +static void +handle_1a01(struct bregs *regs) +{ + u32 ticks = (regs->cx << 16) | regs->dx; + SET_BDA(timer_counter, ticks); + SET_BDA(timer_rollover, 0); // reset flag + // XXX - should use set_code_success()? + regs->ah = 0; + set_success(regs); +} + +// Read CMOS Time +static void +handle_1a02(struct bregs *regs) +{ + if (rtc_updating()) { + set_invalid(regs); + return; + } + + regs->dh = inb_cmos(CMOS_RTC_SECONDS); + regs->cl = inb_cmos(CMOS_RTC_MINUTES); + regs->ch = inb_cmos(CMOS_RTC_HOURS); + regs->dl = inb_cmos(CMOS_STATUS_B) & RTC_B_DSE; + regs->ah = 0; + regs->al = regs->ch; + set_success(regs); +} + +// Set CMOS Time +static void +handle_1a03(struct bregs *regs) +{ + // Using a debugger, I notice the following masking/setting + // of bits in Status Register B, by setting Reg B to + // a few values and getting its value after INT 1A was called. + // + // try#1 try#2 try#3 + // before 1111 1101 0111 1101 0000 0000 + // after 0110 0010 0110 0010 0000 0010 + // + // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1 + // My assumption: RegB = ((RegB & 01100000b) | 00000010b) + if (rtc_updating()) { + init_rtc(); + // fall through as if an update were not in progress + } + outb_cmos(regs->dh, CMOS_RTC_SECONDS); + outb_cmos(regs->cl, CMOS_RTC_MINUTES); + outb_cmos(regs->ch, CMOS_RTC_HOURS); + // Set Daylight Savings time enabled bit to requested value + u8 val8 = ((inb_cmos(CMOS_STATUS_B) & (RTC_B_PIE|RTC_B_AIE)) + | RTC_B_24HR | (regs->dl & RTC_B_DSE)); + outb_cmos(val8, CMOS_STATUS_B); + regs->ah = 0; + regs->al = val8; // val last written to Reg B + set_success(regs); +} + +// Read CMOS Date +static void +handle_1a04(struct bregs *regs) +{ + regs->ah = 0; + if (rtc_updating()) { + set_invalid(regs); + return; + } + regs->cl = inb_cmos(CMOS_RTC_YEAR); + regs->dh = inb_cmos(CMOS_RTC_MONTH); + regs->dl = inb_cmos(CMOS_RTC_DAY_MONTH); + if (CONFIG_COREBOOT) { + if (regs->cl > 0x80) + regs->ch = 0x19; + else + regs->ch = 0x20; + } else { + regs->ch = inb_cmos(CMOS_CENTURY); + } + regs->al = regs->ch; + set_success(regs); +} + +// Set CMOS Date +static void +handle_1a05(struct bregs *regs) +{ + // Using a debugger, I notice the following masking/setting + // of bits in Status Register B, by setting Reg B to + // a few values and getting its value after INT 1A was called. + // + // try#1 try#2 try#3 try#4 + // before 1111 1101 0111 1101 0000 0010 0000 0000 + // after 0110 1101 0111 1101 0000 0010 0000 0000 + // + // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1 + // My assumption: RegB = (RegB & 01111111b) + if (rtc_updating()) { + init_rtc(); + set_invalid(regs); + return; + } + outb_cmos(regs->cl, CMOS_RTC_YEAR); + outb_cmos(regs->dh, CMOS_RTC_MONTH); + outb_cmos(regs->dl, CMOS_RTC_DAY_MONTH); + if (!CONFIG_COREBOOT) + outb_cmos(regs->ch, CMOS_CENTURY); + // clear halt-clock bit + u8 val8 = inb_cmos(CMOS_STATUS_B) & ~RTC_B_SET; + outb_cmos(val8, CMOS_STATUS_B); + regs->ah = 0; + regs->al = val8; // AL = val last written to Reg B + set_success(regs); +} + +// Set Alarm Time in CMOS +static void +handle_1a06(struct bregs *regs) +{ + // Using a debugger, I notice the following masking/setting + // of bits in Status Register B, by setting Reg B to + // a few values and getting its value after INT 1A was called. + // + // try#1 try#2 try#3 + // before 1101 1111 0101 1111 0000 0000 + // after 0110 1111 0111 1111 0010 0000 + // + // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1 + // My assumption: RegB = ((RegB & 01111111b) | 00100000b) + u8 val8 = inb_cmos(CMOS_STATUS_B); // Get Status Reg B + regs->ax = 0; + if (val8 & RTC_B_AIE) { + // Alarm interrupt enabled already + set_invalid(regs); + return; + } + if (rtc_updating()) { + init_rtc(); + // fall through as if an update were not in progress + } + outb_cmos(regs->dh, CMOS_RTC_SECONDS_ALARM); + outb_cmos(regs->cl, CMOS_RTC_MINUTES_ALARM); + outb_cmos(regs->ch, CMOS_RTC_HOURS_ALARM); + // enable Status Reg B alarm bit, clear halt clock bit + outb_cmos((val8 & ~RTC_B_SET) | RTC_B_AIE, CMOS_STATUS_B); + set_success(regs); +} + +// Turn off Alarm +static void +handle_1a07(struct bregs *regs) +{ + // Using a debugger, I notice the following masking/setting + // of bits in Status Register B, by setting Reg B to + // a few values and getting its value after INT 1A was called. + // + // try#1 try#2 try#3 try#4 + // before 1111 1101 0111 1101 0010 0000 0010 0010 + // after 0100 0101 0101 0101 0000 0000 0000 0010 + // + // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1 + // My assumption: RegB = (RegB & 01010111b) + u8 val8 = inb_cmos(CMOS_STATUS_B); // Get Status Reg B + // clear clock-halt bit, disable alarm bit + outb_cmos(val8 & ~(RTC_B_SET|RTC_B_AIE), CMOS_STATUS_B); + regs->ah = 0; + regs->al = val8; // val last written to Reg B + set_success(regs); +} + +// Unsupported +static void +handle_1aXX(struct bregs *regs) +{ + set_unimplemented(regs); +} + +// INT 1Ah Time-of-day Service Entry Point +void VISIBLE16 +handle_1a(struct bregs *regs) +{ + debug_enter(regs, DEBUG_HDL_1a); + switch (regs->ah) { + case 0x00: handle_1a00(regs); break; + case 0x01: handle_1a01(regs); break; + case 0x02: handle_1a02(regs); break; + case 0x03: handle_1a03(regs); break; + case 0x04: handle_1a04(regs); break; + case 0x05: handle_1a05(regs); break; + case 0x06: handle_1a06(regs); break; + case 0x07: handle_1a07(regs); break; + case 0xb1: handle_1ab1(regs); break; + default: handle_1aXX(regs); break; + } +} + +// INT 08h System Timer ISR Entry Point +void VISIBLE16 +handle_08(void) +{ + debug_isr(DEBUG_ISR_08); + + floppy_tick(); + + u32 counter = GET_BDA(timer_counter); + counter++; + // compare to one days worth of timer ticks at 18.2 hz + if (counter >= TICKS_PER_DAY) { + // 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); + + usb_check_event(); + + // chain to user timer tick INT #0x1c + u32 eax=0, flags; + call16_simpint(0x1c, &eax, &flags); + + eoi_pic1(); +} + + +/**************************************************************** + * Periodic timer + ****************************************************************/ + +void +useRTC(void) +{ + u16 ebda_seg = get_ebda_seg(); + int count = GET_EBDA2(ebda_seg, RTCusers); + SET_EBDA2(ebda_seg, RTCusers, count+1); + if (count) + return; + // Turn on the Periodic Interrupt timer + u8 bRegister = inb_cmos(CMOS_STATUS_B); + outb_cmos(bRegister | RTC_B_PIE, CMOS_STATUS_B); +} + +void +releaseRTC(void) +{ + u16 ebda_seg = get_ebda_seg(); + int count = GET_EBDA2(ebda_seg, RTCusers); + SET_EBDA2(ebda_seg, RTCusers, count-1); + if (count != 1) + return; + // Clear the Periodic Interrupt. + u8 bRegister = inb_cmos(CMOS_STATUS_B); + outb_cmos(bRegister & ~RTC_B_PIE, CMOS_STATUS_B); +} + +static int +set_usertimer(u32 usecs, u16 seg, u16 offset) +{ + if (GET_BDA(rtc_wait_flag) & RWS_WAIT_PENDING) + return -1; + + // Interval not already set. + SET_BDA(rtc_wait_flag, RWS_WAIT_PENDING); // Set status byte. + SET_BDA(user_wait_complete_flag, SEGOFF(seg, offset)); + SET_BDA(user_wait_timeout, usecs); + useRTC(); + return 0; +} + +static void +clear_usertimer(void) +{ + if (!(GET_BDA(rtc_wait_flag) & RWS_WAIT_PENDING)) + return; + // Turn off status byte. + SET_BDA(rtc_wait_flag, 0); + releaseRTC(); +} + +#define RET_ECLOCKINUSE 0x83 + +// Wait for CX:DX microseconds +void +handle_1586(struct bregs *regs) +{ + // Use the rtc to wait for the specified time. + u8 statusflag = 0; + u32 count = (regs->cx << 16) | regs->dx; + int ret = set_usertimer(count, GET_SEG(SS), (u32)&statusflag); + if (ret) { + set_code_invalid(regs, RET_ECLOCKINUSE); + return; + } + while (!statusflag) + wait_irq(); + set_success(regs); +} + +// Set Interval requested. +static void +handle_158300(struct bregs *regs) +{ + int ret = set_usertimer((regs->cx << 16) | regs->dx, regs->es, regs->bx); + if (ret) + // Interval already set. + set_code_invalid(regs, RET_EUNSUPPORTED); + else + set_success(regs); +} + +// Clear interval requested +static void +handle_158301(struct bregs *regs) +{ + clear_usertimer(); + set_success(regs); +} + +static void +handle_1583XX(struct bregs *regs) +{ + set_code_unimplemented(regs, RET_EUNSUPPORTED); + regs->al--; +} + +void +handle_1583(struct bregs *regs) +{ + switch (regs->al) { + case 0x00: handle_158300(regs); break; + case 0x01: handle_158301(regs); break; + default: handle_1583XX(regs); break; + } +} + +#define USEC_PER_RTC DIV_ROUND_CLOSEST(1000000, 1024) + +// int70h: IRQ8 - CMOS RTC +void VISIBLE16 +handle_70(void) +{ + debug_isr(DEBUG_ISR_70); + + // Check which modes are enabled and have occurred. + u8 registerB = inb_cmos(CMOS_STATUS_B); + u8 registerC = inb_cmos(CMOS_STATUS_C); + + if (!(registerB & (RTC_B_PIE|RTC_B_AIE))) + goto done; + if (registerC & RTC_B_AIE) { + // Handle Alarm Interrupt. + u32 eax=0, flags; + call16_simpint(0x4a, &eax, &flags); + } + if (!(registerC & RTC_B_PIE)) + goto done; + + // Handle Periodic Interrupt. + + check_preempt(); + + if (!GET_BDA(rtc_wait_flag)) + goto done; + + // Wait Interval (Int 15, AH=83) active. + u32 time = GET_BDA(user_wait_timeout); // Time left in microseconds. + if (time < USEC_PER_RTC) { + // Done waiting - write to specified flag byte. + struct segoff_s segoff = GET_BDA(user_wait_complete_flag); + u16 ptr_seg = segoff.seg; + u8 *ptr_far = (u8*)(segoff.offset+0); + u8 oldval = GET_FARVAR(ptr_seg, *ptr_far); + SET_FARVAR(ptr_seg, *ptr_far, oldval | 0x80); + + clear_usertimer(); + } else { + // Continue waiting. + time -= USEC_PER_RTC; + SET_BDA(user_wait_timeout, time); + } + +done: + eoi_pic2(); +} diff --git a/bios/seabios/src/cmos.h b/bios/seabios/src/cmos.h new file mode 100644 index 0000000..e4b6462 --- /dev/null +++ b/bios/seabios/src/cmos.h @@ -0,0 +1,74 @@ +// Definitions for X86 CMOS non-volatile memory access. +// +// Copyright (C) 2008 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. +#ifndef __CMOS_H +#define __CMOS_H + +#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_RTC_DAY_WEEK 0x06 +#define CMOS_RTC_DAY_MONTH 0x07 +#define CMOS_RTC_MONTH 0x08 +#define CMOS_RTC_YEAR 0x09 +#define CMOS_STATUS_A 0x0a +#define CMOS_STATUS_B 0x0b +#define CMOS_STATUS_C 0x0c +#define CMOS_STATUS_D 0x0d +#define CMOS_RESET_CODE 0x0f +#define CMOS_FLOPPY_DRIVE_TYPE 0x10 +#define CMOS_DISK_DATA 0x12 +#define CMOS_EQUIPMENT_INFO 0x14 +#define CMOS_DISK_DRIVE1_TYPE 0x19 +#define CMOS_DISK_DRIVE2_TYPE 0x1a +#define CMOS_DISK_DRIVE1_CYL 0x1b +#define CMOS_DISK_DRIVE2_CYL 0x24 +#define CMOS_MEM_EXTMEM_LOW 0x30 +#define CMOS_MEM_EXTMEM_HIGH 0x31 +#define CMOS_CENTURY 0x32 +#define CMOS_MEM_EXTMEM2_LOW 0x34 +#define CMOS_MEM_EXTMEM2_HIGH 0x35 +#define CMOS_BIOS_BOOTFLAG1 0x38 +#define CMOS_BIOS_DISKTRANSFLAG 0x39 +#define CMOS_BIOS_BOOTFLAG2 0x3d +#define CMOS_MEM_HIGHMEM_LOW 0x5b +#define CMOS_MEM_HIGHMEM_MID 0x5c +#define CMOS_MEM_HIGHMEM_HIGH 0x5d +#define CMOS_BIOS_SMP_COUNT 0x5f + +// 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 + +#ifndef __ASSEMBLY__ + +#include "ioport.h" // inb, outb + +static inline u8 +inb_cmos(u8 reg) +{ + reg |= NMI_DISABLE_BIT; + outb(reg, PORT_CMOS_INDEX); + return inb(PORT_CMOS_DATA); +} + +static inline void +outb_cmos(u8 val, u8 reg) +{ + reg |= NMI_DISABLE_BIT; + outb(reg, PORT_CMOS_INDEX); + outb(val, PORT_CMOS_DATA); +} + +#endif // !__ASSEMBLY__ + +#endif // cmos.h diff --git a/bios/seabios/src/config.h b/bios/seabios/src/config.h new file mode 100644 index 0000000..b0187a4 --- /dev/null +++ b/bios/seabios/src/config.h @@ -0,0 +1,103 @@ +#ifndef __CONFIG_H +#define __CONFIG_H + +#include "autoconf.h" + +// Configuration definitions. + +//#define CONFIG_APPNAME "QEMU" +//#define CONFIG_CPUNAME8 "QEMUCPU " +//#define CONFIG_APPNAME6 "QEMU " +//#define CONFIG_APPNAME4 "QEMU" +#define CONFIG_APPNAME "Bochs" +#define CONFIG_CPUNAME8 "BOCHSCPU" +#define CONFIG_APPNAME6 "BOCHS " +#define CONFIG_APPNAME4 "BXPC" + +// Maximum number of map entries in the e820 map +#define CONFIG_MAX_E820 32 +// Space to reserve in f-segment for dynamic allocations +#define CONFIG_MAX_BIOSTABLE 2048 +// Space to reserve in high-memory for tables +#define CONFIG_MAX_HIGHTABLE (64*1024) +// Largest supported externaly facing drive id +#define CONFIG_MAX_EXTDRIVE 16 +// Number of bytes the smbios may be and still live in the f-segment +#define BUILD_MAX_SMBIOS_FSEG 600 + +#define CONFIG_MODEL_ID 0xFC +#define CONFIG_SUBMODEL_ID 0x00 +#define CONFIG_BIOS_REVISION 0x01 + +// Various memory addresses used by the code. +#define BUILD_STACK_ADDR 0x7000 +#define BUILD_S3RESUME_STACK_ADDR 0x1000 +#define BUILD_AP_BOOT_ADDR 0x10000 +#define BUILD_EBDA_MINIMUM 0x90000 +#define BUILD_LOWRAM_END 0xa0000 +#define BUILD_ROM_START 0xc0000 +#define BUILD_BIOS_ADDR 0xf0000 +#define BUILD_BIOS_SIZE 0x10000 +// 32KB for shadow ram copying (works around emulator deficiencies) +#define BUILD_BIOS_TMP_ADDR 0x30000 +#define BUILD_SMM_INIT_ADDR 0x38000 +#define BUILD_SMM_ADDR 0xa8000 +#define BUILD_SMM_SIZE 0x8000 +#define BUILD_MAX_HIGHMEM 0xe0000000 + +#define BUILD_PCIMEM_START 0xe0000000 +#define BUILD_PCIMEM_END 0xfec00000 /* IOAPIC is mapped at */ + +#define BUILD_IOAPIC_ADDR 0xfec00000 +#define BUILD_HPET_ADDRESS 0xfed00000 +#define BUILD_APIC_ADDR 0xfee00000 + +// Important real-mode segments +#define SEG_IVT 0x0000 +#define SEG_BDA 0x0040 +#define SEG_BIOS 0xf000 + +// Segment definitions in protected mode (see rombios32_gdt in misc.c) +#define SEG32_MODE32_CS (1 << 3) +#define SEG32_MODE32_DS (2 << 3) +#define SEG32_MODE16_CS (3 << 3) +#define SEG32_MODE16_DS (4 << 3) +#define SEG32_MODE16BIG_CS (5 << 3) +#define SEG32_MODE16BIG_DS (6 << 3) + +// Debugging levels. If non-zero and CONFIG_DEBUG_LEVEL is greater +// than the specified value, then the corresponding irq handler will +// report every enter event. +#define DEBUG_ISR_02 1 +#define DEBUG_HDL_05 1 +#define DEBUG_ISR_08 20 +#define DEBUG_ISR_09 9 +#define DEBUG_ISR_0e 9 +#define DEBUG_HDL_10 20 +#define DEBUG_HDL_11 2 +#define DEBUG_HDL_12 2 +#define DEBUG_HDL_13 10 +#define DEBUG_HDL_14 2 +#define DEBUG_HDL_15 9 +#define DEBUG_HDL_16 9 +#define DEBUG_HDL_17 2 +#define DEBUG_HDL_18 1 +#define DEBUG_HDL_19 1 +#define DEBUG_HDL_1a 9 +#define DEBUG_HDL_40 1 +#define DEBUG_ISR_70 9 +#define DEBUG_ISR_74 9 +#define DEBUG_ISR_75 1 +#define DEBUG_ISR_76 10 +#define DEBUG_ISR_hwpic1 5 +#define DEBUG_ISR_hwpic2 5 +#define DEBUG_HDL_pnp 1 +#define DEBUG_HDL_pmm 1 +#define DEBUG_HDL_pcibios32 9 +#define DEBUG_HDL_apm 9 + +#define DEBUG_unimplemented 2 +#define DEBUG_invalid 3 +#define DEBUG_thread 2 + +#endif // config.h diff --git a/bios/seabios/src/coreboot.c b/bios/seabios/src/coreboot.c new file mode 100644 index 0000000..ee9dd8b --- /dev/null +++ b/bios/seabios/src/coreboot.c @@ -0,0 +1,542 @@ +// Coreboot interface support. +// +// Copyright (C) 2008,2009 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "memmap.h" // add_e820 +#include "util.h" // dprintf +#include "biosvar.h" // GET_EBDA +#include "lzmadecode.h" // LzmaDecode +#include "smbios.h" // smbios_init +#include "boot.h" // boot_add_cbfs + + +/**************************************************************** + * Memory map + ****************************************************************/ + +struct cb_header { + u32 signature; + u32 header_bytes; + u32 header_checksum; + u32 table_bytes; + u32 table_checksum; + u32 table_entries; +}; + +#define CB_SIGNATURE 0x4f49424C // "LBIO" + +struct cb_memory_range { + u64 start; + u64 size; + u32 type; +}; + +#define CB_MEM_TABLE 16 + +struct cb_memory { + u32 tag; + u32 size; + struct cb_memory_range map[0]; +}; + +#define CB_TAG_MEMORY 0x01 + +#define MEM_RANGE_COUNT(_rec) \ + (((_rec)->size - sizeof(*(_rec))) / sizeof((_rec)->map[0])) + +struct cb_mainboard { + u32 tag; + u32 size; + u8 vendor_idx; + u8 part_idx; + char strings[0]; +}; + +#define CB_TAG_MAINBOARD 0x0003 + +struct cb_forward { + u32 tag; + u32 size; + u64 forward; +}; + +#define CB_TAG_FORWARD 0x11 + +static u16 +ipchksum(char *buf, int count) +{ + u16 *p = (u16*)buf; + u32 sum = 0; + while (count > 1) { + sum += *p++; + count -= 2; + } + if (count) + sum += *(u8*)p; + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + return ~sum; +} + +// Try to locate the coreboot header in a given address range. +static struct cb_header * +find_cb_header(char *addr, int len) +{ + char *end = addr + len; + for (; addr < end; addr += 16) { + struct cb_header *cbh = (struct cb_header *)addr; + if (cbh->signature != CB_SIGNATURE) + continue; + if (! cbh->table_bytes) + continue; + if (ipchksum(addr, sizeof(*cbh)) != 0) + continue; + if (ipchksum(addr + sizeof(*cbh), cbh->table_bytes) + != cbh->table_checksum) + continue; + return cbh; + } + return NULL; +} + +// Try to find the coreboot memory table in the given coreboot table. +static void * +find_cb_subtable(struct cb_header *cbh, u32 tag) +{ + char *tbl = (char *)cbh + sizeof(*cbh); + int i; + for (i=0; itable_entries; i++) { + struct cb_memory *cbm = (struct cb_memory *)tbl; + tbl += cbm->size; + if (cbm->tag == tag) + return cbm; + } + return NULL; +} + +static struct cb_memory *CBMemTable; +const char *CBvendor, *CBpart; + +// Populate max ram and e820 map info by scanning for a coreboot table. +static void +coreboot_fill_map(void) +{ + dprintf(3, "Attempting to find coreboot table\n"); + + // Find coreboot table. + struct cb_header *cbh = find_cb_header(0, 0x1000); + if (!cbh) + goto fail; + struct cb_forward *cbf = find_cb_subtable(cbh, CB_TAG_FORWARD); + if (cbf) { + dprintf(3, "Found coreboot table forwarder.\n"); + cbh = find_cb_header((char *)((u32)cbf->forward), 0x100); + if (!cbh) + goto fail; + } + dprintf(3, "Now attempting to find coreboot memory map\n"); + struct cb_memory *cbm = CBMemTable = find_cb_subtable(cbh, CB_TAG_MEMORY); + if (!cbm) + goto fail; + + u64 maxram = 0, maxram_over4G = 0; + int i, count = MEM_RANGE_COUNT(cbm); + for (i=0; imap[i]; + u32 type = m->type; + if (type == CB_MEM_TABLE) { + type = E820_RESERVED; + } else if (type == E820_ACPI || type == E820_RAM) { + u64 end = m->start + m->size; + if (end > 0x100000000ull) { + end -= 0x100000000ull; + if (end > maxram_over4G) + maxram_over4G = end; + } else if (end > maxram) + maxram = end; + } + add_e820(m->start, m->size, type); + } + + RamSize = maxram; + RamSizeOver4G = maxram_over4G; + + // Ughh - coreboot likes to set a map at 0x0000-0x1000, but this + // confuses grub. So, override it. + add_e820(0, 16*1024, E820_RAM); + + struct cb_mainboard *cbmb = find_cb_subtable(cbh, CB_TAG_MAINBOARD); + if (cbmb) { + CBvendor = &cbmb->strings[cbmb->vendor_idx]; + CBpart = &cbmb->strings[cbmb->part_idx]; + dprintf(1, "Found mainboard %s %s\n", CBvendor, CBpart); + } + + return; + +fail: + // No table found.. Use 16Megs as a dummy value. + dprintf(1, "Unable to find coreboot table!\n"); + RamSize = 16*1024*1024; + RamSizeOver4G = 0; + add_e820(0, 16*1024*1024, E820_RAM); + return; +} + + +/**************************************************************** + * BIOS table copying + ****************************************************************/ + +// Attempt to find (and relocate) any standard bios tables found in a +// given address range. +static void +scan_tables(u32 start, u32 size) +{ + void *p = (void*)ALIGN(start, 16); + void *end = (void*)start + size; + for (; pmap[i]; + if (m->type == CB_MEM_TABLE) + scan_tables(m->start, m->size); + } + + // XXX - create a dummy smbios table for now. + if (!SMBiosAddr) + smbios_init(); +} + + +/**************************************************************** + * ulzma + ****************************************************************/ + +// Uncompress data in flash to an area of memory. +static int +ulzma(u8 *dst, u32 maxlen, const u8 *src, u32 srclen) +{ + dprintf(3, "Uncompressing data %d@%p to %d@%p\n", srclen, src, maxlen, dst); + CLzmaDecoderState state; + int ret = LzmaDecodeProperties(&state.Properties, src, LZMA_PROPERTIES_SIZE); + if (ret != LZMA_RESULT_OK) { + dprintf(1, "LzmaDecodeProperties error - %d\n", ret); + return -1; + } + u8 scratch[15980]; + int need = (LzmaGetNumProbs(&state.Properties) * sizeof(CProb)); + if (need > sizeof(scratch)) { + dprintf(1, "LzmaDecode need %d have %d\n", need, (unsigned int)sizeof(scratch)); + return -1; + } + state.Probs = (CProb *)scratch; + + u32 dstlen = *(u32*)(src + LZMA_PROPERTIES_SIZE); + if (dstlen > maxlen) { + dprintf(1, "LzmaDecode too large (max %d need %d)\n", maxlen, dstlen); + return -1; + } + u32 inProcessed, outProcessed; + ret = LzmaDecode(&state, src + LZMA_PROPERTIES_SIZE + 8, srclen + , &inProcessed, dst, dstlen, &outProcessed); + if (ret) { + dprintf(1, "LzmaDecode returned %d\n", ret); + return -1; + } + return dstlen; +} + + +/**************************************************************** + * Coreboot flash format + ****************************************************************/ + +#define CBFS_HEADER_MAGIC 0x4F524243 +#define CBFS_HEADPTR_ADDR 0xFFFFFFFc +#define CBFS_VERSION1 0x31313131 + +struct cbfs_header { + u32 magic; + u32 version; + u32 romsize; + u32 bootblocksize; + u32 align; + u32 offset; + u32 pad[2]; +} PACKED; + +static struct cbfs_header *CBHDR; + +static void +cbfs_setup(void) +{ + if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH) + return; + + CBHDR = *(void **)CBFS_HEADPTR_ADDR; + if (CBHDR->magic != htonl(CBFS_HEADER_MAGIC)) { + dprintf(1, "Unable to find CBFS (ptr=%p; got %x not %x)\n" + , CBHDR, CBHDR->magic, htonl(CBFS_HEADER_MAGIC)); + CBHDR = NULL; + return; + } + + dprintf(1, "Found CBFS header at %p\n", CBHDR); +} + +#define CBFS_FILE_MAGIC 0x455649484352414cLL // LARCHIVE + +struct cbfs_file { + u64 magic; + u32 len; + u32 type; + u32 checksum; + u32 offset; + char filename[0]; +} PACKED; + +// Verify a cbfs entry looks valid. +static struct cbfs_file * +cbfs_verify(struct cbfs_file *file) +{ + if (file < (struct cbfs_file *)(0xFFFFFFFF - ntohl(CBHDR->romsize))) + return NULL; + u64 magic = file->magic; + if (magic == CBFS_FILE_MAGIC) { + dprintf(5, "Found CBFS file %s\n", file->filename); + return file; + } + return NULL; +} + +// Return the first file in the CBFS archive +static struct cbfs_file * +cbfs_getfirst(void) +{ + if (! CBHDR) + return NULL; + return cbfs_verify((void *)(0 - ntohl(CBHDR->romsize) + ntohl(CBHDR->offset))); +} + +// Return the file after the given file. +static struct cbfs_file * +cbfs_getnext(struct cbfs_file *file) +{ + file = (void*)file + ALIGN(ntohl(file->len) + ntohl(file->offset), ntohl(CBHDR->align)); + return cbfs_verify(file); +} + +// Find the file with the given filename. +struct cbfs_file * +cbfs_findfile(const char *fname) +{ + dprintf(3, "Searching CBFS for %s\n", fname); + struct cbfs_file *file; + for (file = cbfs_getfirst(); file; file = cbfs_getnext(file)) + if (strcmp(fname, file->filename) == 0) + return file; + return NULL; +} + +// Find next file with the given filename prefix. +struct cbfs_file * +cbfs_findprefix(const char *prefix, struct cbfs_file *last) +{ + if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH) + return NULL; + + dprintf(3, "Searching CBFS for prefix %s\n", prefix); + int len = strlen(prefix); + struct cbfs_file *file; + if (! last) + file = cbfs_getfirst(); + else + file = cbfs_getnext(last); + for (; file; file = cbfs_getnext(file)) + if (memcmp(prefix, file->filename, len) == 0) + return file; + return NULL; +} + +// Find a file with the given filename (possibly with ".lzma" extension). +struct cbfs_file * +cbfs_finddatafile(const char *fname) +{ + int fnlen = strlen(fname); + struct cbfs_file *file = NULL; + for (;;) { + file = cbfs_findprefix(fname, file); + if (!file) + return NULL; + if (file->filename[fnlen] == '\0' + || strcmp(&file->filename[fnlen], ".lzma") == 0) + return file; + } +} + +// Determine whether the file has a ".lzma" extension. +static int +cbfs_iscomp(struct cbfs_file *file) +{ + int fnamelen = strlen(file->filename); + return fnamelen > 5 && strcmp(&file->filename[fnamelen-5], ".lzma") == 0; +} + +// Return the filename of a given file. +const char * +cbfs_filename(struct cbfs_file *file) +{ + return file->filename; +} + +// Determine the uncompressed size of a datafile. +u32 +cbfs_datasize(struct cbfs_file *file) +{ + void *src = (void*)file + ntohl(file->offset); + if (cbfs_iscomp(file)) + return *(u32*)(src + LZMA_PROPERTIES_SIZE); + return ntohl(file->len); +} + +// Copy a file to memory (uncompressing if necessary) +int +cbfs_copyfile(struct cbfs_file *file, void *dst, u32 maxlen) +{ + if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH || !file) + return -1; + + u32 size = ntohl(file->len); + void *src = (void*)file + ntohl(file->offset); + if (cbfs_iscomp(file)) { + // Compressed - copy to temp ram and uncompress it. + void *temp = malloc_tmphigh(size); + if (!temp) + return -1; + iomemcpy(temp, src, size); + int ret = ulzma(dst, maxlen, temp, size); + yield(); + free(temp); + return ret; + } + + // Not compressed. + dprintf(3, "Copying data %d@%p to %d@%p\n", size, src, maxlen, dst); + if (size > maxlen) { + warn_noalloc(); + return -1; + } + iomemcpy(dst, src, size); + return size; +} + +struct cbfs_payload_segment { + u32 type; + u32 compression; + u32 offset; + u64 load_addr; + u32 len; + u32 mem_len; +} PACKED; + +#define PAYLOAD_SEGMENT_BSS 0x20535342 +#define PAYLOAD_SEGMENT_ENTRY 0x52544E45 + +#define CBFS_COMPRESS_NONE 0 +#define CBFS_COMPRESS_LZMA 1 + +struct cbfs_payload { + struct cbfs_payload_segment segments[1]; +}; + +void +cbfs_run_payload(struct cbfs_file *file) +{ + if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH || !file) + return; + dprintf(1, "Run %s\n", file->filename); + struct cbfs_payload *pay = (void*)file + ntohl(file->offset); + struct cbfs_payload_segment *seg = pay->segments; + for (;;) { + void *src = (void*)pay + ntohl(seg->offset); + void *dest = (void*)ntohl((u32)seg->load_addr); + u32 src_len = ntohl(seg->len); + u32 dest_len = ntohl(seg->mem_len); + switch (seg->type) { + case PAYLOAD_SEGMENT_BSS: + dprintf(3, "BSS segment %d@%p\n", dest_len, dest); + memset(dest, 0, dest_len); + break; + case PAYLOAD_SEGMENT_ENTRY: { + dprintf(1, "Calling addr %p\n", dest); + void (*func)() = dest; + func(); + return; + } + default: + dprintf(3, "Segment %x %d@%p -> %d@%p\n" + , seg->type, src_len, src, dest_len, dest); + if (seg->compression == htonl(CBFS_COMPRESS_NONE)) { + if (src_len > dest_len) + src_len = dest_len; + memcpy(dest, src, src_len); + } else if (CONFIG_LZMA + && seg->compression == htonl(CBFS_COMPRESS_LZMA)) { + int ret = ulzma(dest, dest_len, src, src_len); + if (ret < 0) + return; + src_len = ret; + } else { + dprintf(1, "No support for compression type %x\n" + , seg->compression); + return; + } + if (dest_len > src_len) + memset(dest + src_len, 0, dest_len - src_len); + break; + } + seg++; + } +} + +// Register payloads in "img/" directory with boot system. +void +cbfs_payload_setup(void) +{ + struct cbfs_file *file = NULL; + for (;;) { + file = cbfs_findprefix("img/", file); + if (!file) + break; + const char *filename = cbfs_filename(file); + char *desc = znprintf(MAXDESCSIZE, "Payload [%s]", &filename[4]); + boot_add_cbfs(file, desc, bootprio_find_named_rom(filename, 0)); + } +} + +void +coreboot_setup(void) +{ + coreboot_fill_map(); + cbfs_setup(); +} diff --git a/bios/seabios/src/disk.c b/bios/seabios/src/disk.c new file mode 100644 index 0000000..8f7c61f --- /dev/null +++ b/bios/seabios/src/disk.c @@ -0,0 +1,896 @@ +// 16bit code to access hard drives. +// +// Copyright (C) 2008 Kevin O'Connor +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "disk.h" // floppy_13 +#include "biosvar.h" // SET_BDA +#include "config.h" // CONFIG_* +#include "util.h" // debug_enter +#include "pic.h" // eoi_pic2 +#include "bregs.h" // struct bregs +#include "pci.h" // pci_bdf_to_bus +#include "ata.h" // ATA_CB_DC + + +/**************************************************************** + * Helper functions + ****************************************************************/ + +void +__disk_ret(struct bregs *regs, u32 linecode, const char *fname) +{ + u8 code = linecode; + if (regs->dl < EXTSTART_HD) + SET_BDA(floppy_last_status, code); + else + SET_BDA(disk_last_status, code); + if (code) + __set_code_invalid(regs, linecode, fname); + else + set_code_success(regs); +} + +void +__disk_ret_unimplemented(struct bregs *regs, u32 linecode, const char *fname) +{ + u8 code = linecode; + if (regs->dl < EXTSTART_HD) + SET_BDA(floppy_last_status, code); + else + SET_BDA(disk_last_status, code); + __set_code_unimplemented(regs, linecode, fname); +} + +static void +__disk_stub(struct bregs *regs, int lineno, const char *fname) +{ + __warn_unimplemented(regs, lineno, fname); + __disk_ret(regs, DISK_RET_SUCCESS | (lineno << 8), fname); +} + +#define DISK_STUB(regs) \ + __disk_stub((regs), __LINE__, __func__) + +// Get the cylinders/heads/sectors for the given drive. +static void +fillLCHS(struct drive_s *drive_g, u16 *nlc, u16 *nlh, u16 *nlspt) +{ + if (CONFIG_CDROM_EMU + && drive_g == GLOBALFLAT2GLOBAL(GET_GLOBAL(cdemu_drive_gf))) { + // Emulated drive - get info from ebda. (It's not possible to + // populate the geometry directly in the driveid because the + // geometry is only known after the bios segment is made + // read-only). + u16 ebda_seg = get_ebda_seg(); + *nlc = GET_EBDA2(ebda_seg, cdemu.lchs.cylinders); + *nlh = GET_EBDA2(ebda_seg, cdemu.lchs.heads); + *nlspt = GET_EBDA2(ebda_seg, cdemu.lchs.spt); + return; + } + *nlc = GET_GLOBAL(drive_g->lchs.cylinders); + *nlh = GET_GLOBAL(drive_g->lchs.heads); + *nlspt = GET_GLOBAL(drive_g->lchs.spt); +} + +// Perform read/write/verify using old-style chs accesses +static void +basic_access(struct bregs *regs, struct drive_s *drive_g, u16 command) +{ + struct disk_op_s dop; + dop.drive_g = drive_g; + dop.command = command; + + u8 count = regs->al; + u16 cylinder = regs->ch | ((((u16)regs->cl) << 2) & 0x300); + u16 sector = regs->cl & 0x3f; + u16 head = regs->dh; + + if (count > 128 || count == 0 || sector == 0) { + warn_invalid(regs); + disk_ret(regs, DISK_RET_EPARAM); + return; + } + dop.count = count; + + u16 nlc, nlh, nlspt; + fillLCHS(drive_g, &nlc, &nlh, &nlspt); + + // sanity check on cyl heads, sec + if (cylinder >= nlc || head >= nlh || sector > nlspt) { + warn_invalid(regs); + disk_ret(regs, DISK_RET_EPARAM); + return; + } + + // translate lchs to lba + dop.lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt) + + (u32)sector - 1); + + dop.buf_fl = MAKE_FLATPTR(regs->es, regs->bx); + + int status = send_disk_op(&dop); + + regs->al = dop.count; + + disk_ret(regs, status); +} + +// Perform read/write/verify using new-style "int13ext" accesses. +static void +extended_access(struct bregs *regs, struct drive_s *drive_g, u16 command) +{ + struct disk_op_s dop; + // Get lba and check. + dop.lba = GET_INT13EXT(regs, lba); + dop.command = command; + dop.drive_g = drive_g; + if (dop.lba >= GET_GLOBAL(drive_g->sectors)) { + warn_invalid(regs); + disk_ret(regs, DISK_RET_EPARAM); + return; + } + + dop.buf_fl = SEGOFF_TO_FLATPTR(GET_INT13EXT(regs, data)); + dop.count = GET_INT13EXT(regs, count); + + int status = send_disk_op(&dop); + + SET_INT13EXT(regs, count, dop.count); + + disk_ret(regs, status); +} + + +/**************************************************************** + * Hard Drive functions + ****************************************************************/ + +// disk controller reset +static void +disk_1300(struct bregs *regs, struct drive_s *drive_g) +{ + struct disk_op_s dop; + dop.drive_g = drive_g; + dop.command = CMD_RESET; + int status = send_disk_op(&dop); + disk_ret(regs, status); +} + +// read disk status +static void +disk_1301(struct bregs *regs, struct drive_s *drive_g) +{ + u8 v; + if (regs->dl < EXTSTART_HD) + // Floppy + v = GET_BDA(floppy_last_status); + else + v = GET_BDA(disk_last_status); + regs->ah = v; + set_cf(regs, v); + // XXX - clear disk_last_status? +} + +// read disk sectors +static void +disk_1302(struct bregs *regs, struct drive_s *drive_g) +{ + basic_access(regs, drive_g, CMD_READ); +} + +// write disk sectors +static void +disk_1303(struct bregs *regs, struct drive_s *drive_g) +{ + basic_access(regs, drive_g, CMD_WRITE); +} + +// verify disk sectors +static void +disk_1304(struct bregs *regs, struct drive_s *drive_g) +{ + basic_access(regs, drive_g, CMD_VERIFY); +} + +// format disk track +static void +disk_1305(struct bregs *regs, struct drive_s *drive_g) +{ + debug_stub(regs); + + u16 nlc, nlh, nlspt; + fillLCHS(drive_g, &nlc, &nlh, &nlspt); + + u8 num_sectors = regs->al; + u8 head = regs->dh; + + if (head >= nlh || num_sectors == 0 || num_sectors > nlspt) { + disk_ret(regs, DISK_RET_EPARAM); + return; + } + + struct disk_op_s dop; + dop.drive_g = drive_g; + dop.command = CMD_FORMAT; + dop.lba = head; + dop.count = num_sectors; + dop.buf_fl = MAKE_FLATPTR(regs->es, regs->bx); + int status = send_disk_op(&dop); + disk_ret(regs, status); +} + +// read disk drive parameters +static void +disk_1308(struct bregs *regs, struct drive_s *drive_g) +{ + u16 ebda_seg = get_ebda_seg(); + // Get logical geometry from table + u16 nlc, nlh, nlspt; + fillLCHS(drive_g, &nlc, &nlh, &nlspt); + nlc--; + nlh--; + u8 count; + if (regs->dl < EXTSTART_HD) { + // Floppy + count = GET_GLOBAL(FloppyCount); + + if (CONFIG_CDROM_EMU + && drive_g == GLOBALFLAT2GLOBAL(GET_GLOBAL(cdemu_drive_gf))) + regs->bx = GET_EBDA2(ebda_seg, cdemu.media) * 2; + else + regs->bx = GET_GLOBAL(drive_g->floppy_type); + + // set es & di to point to 11 byte diskette param table in ROM + regs->es = SEG_BIOS; + regs->di = (u32)&diskette_param_table2; + } else if (regs->dl < EXTSTART_CD) { + // Hard drive + count = GET_BDA(hdcount); + nlc--; // last sector reserved + } else { + // Not supported on CDROM + disk_ret(regs, DISK_RET_EPARAM); + return; + } + + if (CONFIG_CDROM_EMU && GET_EBDA2(ebda_seg, cdemu.active)) { + u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive); + if (((emudrive ^ regs->dl) & 0x80) == 0) + // Note extra drive due to emulation. + count++; + if (regs->dl < EXTSTART_HD && count > 2) + // Max of two floppy drives. + count = 2; + } + + regs->al = 0; + regs->ch = nlc & 0xff; + regs->cl = ((nlc >> 2) & 0xc0) | (nlspt & 0x3f); + regs->dh = nlh; + + disk_ret(regs, DISK_RET_SUCCESS); + regs->dl = count; +} + +// initialize drive parameters +static void +disk_1309(struct bregs *regs, struct drive_s *drive_g) +{ + DISK_STUB(regs); +} + +// seek to specified cylinder +static void +disk_130c(struct bregs *regs, struct drive_s *drive_g) +{ + DISK_STUB(regs); +} + +// alternate disk reset +static void +disk_130d(struct bregs *regs, struct drive_s *drive_g) +{ + DISK_STUB(regs); +} + +// check drive ready +static void +disk_1310(struct bregs *regs, struct drive_s *drive_g) +{ + // should look at 40:8E also??? + + struct disk_op_s dop; + dop.drive_g = drive_g; + dop.command = CMD_ISREADY; + int status = send_disk_op(&dop); + disk_ret(regs, status); +} + +// recalibrate +static void +disk_1311(struct bregs *regs, struct drive_s *drive_g) +{ + DISK_STUB(regs); +} + +// controller internal diagnostic +static void +disk_1314(struct bregs *regs, struct drive_s *drive_g) +{ + DISK_STUB(regs); +} + +// read disk drive size +static void +disk_1315(struct bregs *regs, struct drive_s *drive_g) +{ + disk_ret(regs, DISK_RET_SUCCESS); + if (regs->dl < EXTSTART_HD || regs->dl >= EXTSTART_CD) { + // Floppy or cdrom + regs->ah = 1; + return; + } + // Hard drive + + // Get logical geometry from table + u16 nlc, nlh, nlspt; + fillLCHS(drive_g, &nlc, &nlh, &nlspt); + + // Compute sector count seen by int13 + u32 lba = (u32)(nlc - 1) * (u32)nlh * (u32)nlspt; + regs->cx = lba >> 16; + regs->dx = lba & 0xffff; + regs->ah = 3; // hard disk accessible +} + +static void +disk_1316(struct bregs *regs, struct drive_s *drive_g) +{ + if (regs->dl >= EXTSTART_HD) { + // Hard drive + disk_ret(regs, DISK_RET_EPARAM); + return; + } + disk_ret(regs, DISK_RET_ECHANGED); +} + +// IBM/MS installation check +static void +disk_1341(struct bregs *regs, struct drive_s *drive_g) +{ + regs->bx = 0xaa55; // install check + regs->cx = 0x0007; // ext disk access and edd, removable supported + disk_ret(regs, DISK_RET_SUCCESS); + regs->ah = 0x30; // EDD 3.0 +} + +// IBM/MS extended read +static void +disk_1342(struct bregs *regs, struct drive_s *drive_g) +{ + extended_access(regs, drive_g, CMD_READ); +} + +// IBM/MS extended write +static void +disk_1343(struct bregs *regs, struct drive_s *drive_g) +{ + extended_access(regs, drive_g, CMD_WRITE); +} + +// IBM/MS verify +static void +disk_1344(struct bregs *regs, struct drive_s *drive_g) +{ + extended_access(regs, drive_g, CMD_VERIFY); +} + +// lock +static void +disk_134500(struct bregs *regs, struct drive_s *drive_g) +{ + u16 ebda_seg = get_ebda_seg(); + int cdid = regs->dl - EXTSTART_CD; + u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[cdid]); + if (locks == 0xff) { + regs->al = 1; + disk_ret(regs, DISK_RET_ETOOMANYLOCKS); + return; + } + SET_EBDA2(ebda_seg, cdrom_locks[cdid], locks + 1); + regs->al = 1; + disk_ret(regs, DISK_RET_SUCCESS); +} + +// unlock +static void +disk_134501(struct bregs *regs, struct drive_s *drive_g) +{ + u16 ebda_seg = get_ebda_seg(); + int cdid = regs->dl - EXTSTART_CD; + u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[cdid]); + if (locks == 0x00) { + regs->al = 0; + disk_ret(regs, DISK_RET_ENOTLOCKED); + return; + } + locks--; + SET_EBDA2(ebda_seg, cdrom_locks[cdid], locks); + regs->al = (locks ? 1 : 0); + disk_ret(regs, DISK_RET_SUCCESS); +} + +// status +static void +disk_134502(struct bregs *regs, struct drive_s *drive_g) +{ + int cdid = regs->dl - EXTSTART_CD; + u8 locks = GET_EBDA(cdrom_locks[cdid]); + regs->al = (locks ? 1 : 0); + disk_ret(regs, DISK_RET_SUCCESS); +} + +static void +disk_1345XX(struct bregs *regs, struct drive_s *drive_g) +{ + disk_ret_unimplemented(regs, DISK_RET_EPARAM); +} + +// IBM/MS lock/unlock drive +static void +disk_1345(struct bregs *regs, struct drive_s *drive_g) +{ + if (regs->dl < EXTSTART_CD) { + // Always success for HD + disk_ret(regs, DISK_RET_SUCCESS); + return; + } + + switch (regs->al) { + case 0x00: disk_134500(regs, drive_g); break; + case 0x01: disk_134501(regs, drive_g); break; + case 0x02: disk_134502(regs, drive_g); break; + default: disk_1345XX(regs, drive_g); break; + } +} + +// IBM/MS eject media +static void +disk_1346(struct bregs *regs, struct drive_s *drive_g) +{ + if (regs->dl < EXTSTART_CD) { + // Volume Not Removable + disk_ret(regs, DISK_RET_ENOTREMOVABLE); + return; + } + + int cdid = regs->dl - EXTSTART_CD; + u8 locks = GET_EBDA(cdrom_locks[cdid]); + if (locks != 0) { + disk_ret(regs, DISK_RET_ELOCKED); + return; + } + + // FIXME should handle 0x31 no media in device + // FIXME should handle 0xb5 valid request failed + + // Call removable media eject + struct bregs br; + memset(&br, 0, sizeof(br)); + br.ah = 0x52; + br.dl = regs->dl; + call16_int(0x15, &br); + + if (br.ah || br.flags & F_CF) { + disk_ret(regs, DISK_RET_ELOCKED); + return; + } + disk_ret(regs, DISK_RET_SUCCESS); +} + +// IBM/MS extended seek +static void +disk_1347(struct bregs *regs, struct drive_s *drive_g) +{ + extended_access(regs, drive_g, CMD_SEEK); +} + +// IBM/MS get drive parameters +static void +disk_1348(struct bregs *regs, struct drive_s *drive_g) +{ + u16 size = GET_INT13DPT(regs, size); + u16 t13 = size == 74; + + // Buffer is too small + if (size < 26) { + disk_ret(regs, DISK_RET_EPARAM); + return; + } + + // EDD 1.x + + u8 type = GET_GLOBAL(drive_g->type); + u16 npc = GET_GLOBAL(drive_g->pchs.cylinders); + u16 nph = GET_GLOBAL(drive_g->pchs.heads); + u16 npspt = GET_GLOBAL(drive_g->pchs.spt); + u64 lba = GET_GLOBAL(drive_g->sectors); + u16 blksize = GET_GLOBAL(drive_g->blksize); + + dprintf(DEBUG_HDL_13, "disk_1348 size=%d t=%d chs=%d,%d,%d lba=%d bs=%d\n" + , size, type, npc, nph, npspt, (u32)lba, blksize); + + SET_INT13DPT(regs, size, 26); + if (type == DTYPE_ATAPI) { + // 0x74 = removable, media change, lockable, max values + SET_INT13DPT(regs, infos, 0x74); + SET_INT13DPT(regs, cylinders, 0xffffffff); + SET_INT13DPT(regs, heads, 0xffffffff); + SET_INT13DPT(regs, spt, 0xffffffff); + SET_INT13DPT(regs, sector_count, (u64)-1); + } else { + if (lba > (u64)npspt*nph*0x3fff) { + SET_INT13DPT(regs, infos, 0x00); // geometry is invalid + SET_INT13DPT(regs, cylinders, 0x3fff); + } else { + SET_INT13DPT(regs, infos, 0x02); // geometry is valid + SET_INT13DPT(regs, cylinders, (u32)npc); + } + SET_INT13DPT(regs, heads, (u32)nph); + SET_INT13DPT(regs, spt, (u32)npspt); + SET_INT13DPT(regs, sector_count, lba); + } + SET_INT13DPT(regs, blksize, blksize); + + if (size < 30 || + (type != DTYPE_ATA && type != DTYPE_ATAPI && type != DTYPE_VIRTIO)) { + disk_ret(regs, DISK_RET_SUCCESS); + return; + } + + // EDD 2.x + + int bdf; + u16 iobase1 = 0; + u64 device_path = 0; + u8 channel = 0; + SET_INT13DPT(regs, size, 30); + if (type == DTYPE_ATA || type == DTYPE_ATAPI) { + u16 ebda_seg = get_ebda_seg(); + + SET_INT13DPT(regs, dpte_segment, ebda_seg); + SET_INT13DPT(regs, dpte_offset + , offsetof(struct extended_bios_data_area_s, dpte)); + + // Fill in dpte + struct atadrive_s *adrive_g = container_of( + drive_g, struct atadrive_s, drive); + struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf); + u8 slave = GET_GLOBAL(adrive_g->slave); + u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2); + u8 irq = GET_GLOBALFLAT(chan_gf->irq); + iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); + bdf = GET_GLOBALFLAT(chan_gf->pci_bdf); + device_path = slave; + channel = GET_GLOBALFLAT(chan_gf->chanid); + + u16 options = 0; + if (type == DTYPE_ATA) { + u8 translation = GET_GLOBAL(drive_g->translation); + if (translation != TRANSLATION_NONE) { + options |= 1<<3; // CHS translation + if (translation == TRANSLATION_LBA) + options |= 1<<9; + if (translation == TRANSLATION_RECHS) + options |= 3<<9; + } + } else { + // ATAPI + options |= 1<<5; // removable device + options |= 1<<6; // atapi device + } + options |= 1<<4; // lba translation + if (CONFIG_ATA_PIO32) + options |= 1<<7; + + SET_EBDA2(ebda_seg, dpte.iobase1, iobase1); + SET_EBDA2(ebda_seg, dpte.iobase2, iobase2 + ATA_CB_DC); + SET_EBDA2(ebda_seg, dpte.prefix, ((slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) + | ATA_CB_DH_LBA)); + SET_EBDA2(ebda_seg, dpte.unused, 0xcb); + SET_EBDA2(ebda_seg, dpte.irq, irq); + SET_EBDA2(ebda_seg, dpte.blkcount, 1); + SET_EBDA2(ebda_seg, dpte.dma, 0); + SET_EBDA2(ebda_seg, dpte.pio, 0); + SET_EBDA2(ebda_seg, dpte.options, options); + SET_EBDA2(ebda_seg, dpte.reserved, 0); + SET_EBDA2(ebda_seg, dpte.revision, 0x11); + + u8 sum = checksum_far( + ebda_seg, (void*)offsetof(struct extended_bios_data_area_s, dpte), 15); + SET_EBDA2(ebda_seg, dpte.checksum, -sum); + } else { + SET_INT13DPT(regs, dpte_segment, 0); + SET_INT13DPT(regs, dpte_offset, 0); + bdf = GET_GLOBAL(drive_g->cntl_id); + } + + if (size < 66) { + disk_ret(regs, DISK_RET_SUCCESS); + return; + } + + // EDD 3.x + SET_INT13DPT(regs, key, 0xbedd); + SET_INT13DPT(regs, dpi_length, t13 ? 44 : 36); + SET_INT13DPT(regs, reserved1, 0); + SET_INT13DPT(regs, reserved2, 0); + + if (bdf != -1) { + SET_INT13DPT(regs, host_bus[0], 'P'); + SET_INT13DPT(regs, host_bus[1], 'C'); + SET_INT13DPT(regs, host_bus[2], 'I'); + SET_INT13DPT(regs, host_bus[3], ' '); + + u32 path = (pci_bdf_to_bus(bdf) | (pci_bdf_to_dev(bdf) << 8) + | (pci_bdf_to_fn(bdf) << 16)); + if (t13) + path |= channel << 24; + + SET_INT13DPT(regs, iface_path, path); + } else { + // ISA + SET_INT13DPT(regs, host_bus[0], 'I'); + SET_INT13DPT(regs, host_bus[1], 'S'); + SET_INT13DPT(regs, host_bus[2], 'A'); + SET_INT13DPT(regs, host_bus[3], ' '); + + SET_INT13DPT(regs, iface_path, iobase1); + } + + if (type != DTYPE_VIRTIO) { + SET_INT13DPT(regs, iface_type[0], 'A'); + SET_INT13DPT(regs, iface_type[1], 'T'); + SET_INT13DPT(regs, iface_type[2], 'A'); + SET_INT13DPT(regs, iface_type[3], ' '); + } else { + SET_INT13DPT(regs, iface_type[0], 'S'); + SET_INT13DPT(regs, iface_type[1], 'C'); + SET_INT13DPT(regs, iface_type[2], 'S'); + SET_INT13DPT(regs, iface_type[3], 'I'); + } + SET_INT13DPT(regs, iface_type[4], ' '); + SET_INT13DPT(regs, iface_type[5], ' '); + SET_INT13DPT(regs, iface_type[6], ' '); + SET_INT13DPT(regs, iface_type[7], ' '); + + if (t13) { + SET_INT13DPT(regs, t13.device_path[0], device_path); + SET_INT13DPT(regs, t13.device_path[1], 0); + + SET_INT13DPT(regs, t13.checksum + , -checksum_far(regs->ds, (void*)(regs->si+30), 43)); + } else { + SET_INT13DPT(regs, phoenix.device_path, device_path); + + SET_INT13DPT(regs, phoenix.checksum + , -checksum_far(regs->ds, (void*)(regs->si+30), 35)); + } + + disk_ret(regs, DISK_RET_SUCCESS); +} + +// IBM/MS extended media change +static void +disk_1349(struct bregs *regs, struct drive_s *drive_g) +{ + if (regs->dl < EXTSTART_CD) { + // Always success for HD + disk_ret(regs, DISK_RET_SUCCESS); + return; + } + set_invalid(regs); + // always send changed ?? + regs->ah = DISK_RET_ECHANGED; +} + +static void +disk_134e01(struct bregs *regs, struct drive_s *drive_g) +{ + disk_ret(regs, DISK_RET_SUCCESS); +} + +static void +disk_134e03(struct bregs *regs, struct drive_s *drive_g) +{ + disk_ret(regs, DISK_RET_SUCCESS); +} + +static void +disk_134e04(struct bregs *regs, struct drive_s *drive_g) +{ + disk_ret(regs, DISK_RET_SUCCESS); +} + +static void +disk_134e06(struct bregs *regs, struct drive_s *drive_g) +{ + disk_ret(regs, DISK_RET_SUCCESS); +} + +static void +disk_134eXX(struct bregs *regs, struct drive_s *drive_g) +{ + disk_ret(regs, DISK_RET_EPARAM); +} + +// IBM/MS set hardware configuration +static void +disk_134e(struct bregs *regs, struct drive_s *drive_g) +{ + switch (regs->al) { + case 0x01: disk_134e01(regs, drive_g); break; + case 0x03: disk_134e03(regs, drive_g); break; + case 0x04: disk_134e04(regs, drive_g); break; + case 0x06: disk_134e06(regs, drive_g); break; + default: disk_134eXX(regs, drive_g); break; + } +} + +static void +disk_13XX(struct bregs *regs, struct drive_s *drive_g) +{ + disk_ret_unimplemented(regs, DISK_RET_EPARAM); +} + +static void +disk_13(struct bregs *regs, struct drive_s *drive_g) +{ + //debug_stub(regs); + + // clear completion flag + SET_BDA(disk_interrupt_flag, 0); + + switch (regs->ah) { + case 0x00: disk_1300(regs, drive_g); break; + case 0x01: disk_1301(regs, drive_g); break; + case 0x02: disk_1302(regs, drive_g); break; + case 0x03: disk_1303(regs, drive_g); break; + case 0x04: disk_1304(regs, drive_g); break; + case 0x05: disk_1305(regs, drive_g); break; + case 0x08: disk_1308(regs, drive_g); break; + case 0x09: disk_1309(regs, drive_g); break; + case 0x0c: disk_130c(regs, drive_g); break; + case 0x0d: disk_130d(regs, drive_g); break; + case 0x10: disk_1310(regs, drive_g); break; + case 0x11: disk_1311(regs, drive_g); break; + case 0x14: disk_1314(regs, drive_g); break; + case 0x15: disk_1315(regs, drive_g); break; + case 0x16: disk_1316(regs, drive_g); break; + case 0x41: disk_1341(regs, drive_g); break; + case 0x42: disk_1342(regs, drive_g); break; + case 0x43: disk_1343(regs, drive_g); break; + case 0x44: disk_1344(regs, drive_g); break; + case 0x45: disk_1345(regs, drive_g); break; + case 0x46: disk_1346(regs, drive_g); break; + case 0x47: disk_1347(regs, drive_g); break; + case 0x48: disk_1348(regs, drive_g); break; + case 0x49: disk_1349(regs, drive_g); break; + case 0x4e: disk_134e(regs, drive_g); break; + default: disk_13XX(regs, drive_g); break; + } +} + +static void +floppy_13(struct bregs *regs, struct drive_s *drive_g) +{ + // Only limited commands are supported on floppies. + switch (regs->ah) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x08: + case 0x15: + case 0x16: + disk_13(regs, drive_g); + break; + default: disk_13XX(regs, drive_g); break; + } +} + + +/**************************************************************** + * Entry points + ****************************************************************/ + +static void +handle_legacy_disk(struct bregs *regs, u8 extdrive) +{ + if (! CONFIG_DRIVES) { + // XXX - support handle_1301 anyway? + disk_ret(regs, DISK_RET_EPARAM); + return; + } + + if (extdrive < EXTSTART_HD) { + struct drive_s *drive_g = getDrive(EXTTYPE_FLOPPY, extdrive); + if (!drive_g) + goto fail; + floppy_13(regs, drive_g); + return; + } + + struct drive_s *drive_g; + if (extdrive >= EXTSTART_CD) + drive_g = getDrive(EXTTYPE_CD, extdrive - EXTSTART_CD); + else + drive_g = getDrive(EXTTYPE_HD, extdrive - EXTSTART_HD); + if (!drive_g) + goto fail; + disk_13(regs, drive_g); + return; + +fail: + // XXX - support 1301/1308/1315 anyway? + disk_ret(regs, DISK_RET_EPARAM); +} + +void VISIBLE16 +handle_40(struct bregs *regs) +{ + debug_enter(regs, DEBUG_HDL_40); + handle_legacy_disk(regs, regs->dl); +} + +// INT 13h Fixed Disk Services Entry Point +void VISIBLE16 +handle_13(struct bregs *regs) +{ + debug_enter(regs, DEBUG_HDL_13); + u8 extdrive = regs->dl; + + if (CONFIG_CDROM_EMU) { + if (regs->ah == 0x4b) { + cdemu_134b(regs); + return; + } + u16 ebda_seg = get_ebda_seg(); + if (GET_EBDA2(ebda_seg, cdemu.active)) { + u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive); + if (extdrive == emudrive) { + // Access to an emulated drive. + struct drive_s *cdemu_g; + cdemu_g = GLOBALFLAT2GLOBAL(GET_GLOBAL(cdemu_drive_gf)); + if (regs->ah > 0x16) { + // Only old-style commands supported. + disk_13XX(regs, cdemu_g); + return; + } + disk_13(regs, cdemu_g); + return; + } + if (extdrive < EXTSTART_CD && ((emudrive ^ extdrive) & 0x80) == 0) + // Adjust id to make room for emulated drive. + extdrive--; + } + } + handle_legacy_disk(regs, extdrive); +} + +// record completion in BIOS task complete flag +void VISIBLE16 +handle_76(void) +{ + debug_isr(DEBUG_ISR_76); + SET_BDA(disk_interrupt_flag, 0xff); + eoi_pic2(); +} + +// Old Fixed Disk Parameter Table (newer tables are in the ebda). +struct fdpt_s OldFDPT VAR16FIXED(0xe401); diff --git a/bios/seabios/src/disk.h b/bios/seabios/src/disk.h new file mode 100644 index 0000000..ac33518 --- /dev/null +++ b/bios/seabios/src/disk.h @@ -0,0 +1,261 @@ +// Definitions for X86 bios disks. +// +// Copyright (C) 2008 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. +#ifndef __DISK_H +#define __DISK_H + +#include "types.h" // u8 +#include "config.h" // CONFIG_* +#include "farptr.h" // struct segoff_s + +#define DISK_RET_SUCCESS 0x00 +#define DISK_RET_EPARAM 0x01 +#define DISK_RET_EADDRNOTFOUND 0x02 +#define DISK_RET_EWRITEPROTECT 0x03 +#define DISK_RET_ECHANGED 0x06 +#define DISK_RET_EBOUNDARY 0x09 +#define DISK_RET_EBADTRACK 0x0c +#define DISK_RET_ECONTROLLER 0x20 +#define DISK_RET_ETIMEOUT 0x80 +#define DISK_RET_ENOTLOCKED 0xb0 +#define DISK_RET_ELOCKED 0xb1 +#define DISK_RET_ENOTREMOVABLE 0xb2 +#define DISK_RET_ETOOMANYLOCKS 0xb4 +#define DISK_RET_EMEDIA 0xC0 +#define DISK_RET_ENOTREADY 0xAA + + +/**************************************************************** + * Interface structs + ****************************************************************/ + +// Bios disk structures. +struct int13ext_s { + u8 size; + u8 reserved; + u16 count; + struct segoff_s data; + u64 lba; +} PACKED; + +#define GET_INT13EXT(regs,var) \ + GET_FARVAR((regs)->ds, ((struct int13ext_s*)((regs)->si+0))->var) +#define SET_INT13EXT(regs,var,val) \ + SET_FARVAR((regs)->ds, ((struct int13ext_s*)((regs)->si+0))->var, (val)) + +// Disk Physical Table definition +struct int13dpt_s { + u16 size; + u16 infos; + u32 cylinders; + u32 heads; + u32 spt; + u64 sector_count; + u16 blksize; + u16 dpte_offset; + u16 dpte_segment; + u16 key; + u8 dpi_length; + u8 reserved1; + u16 reserved2; + u8 host_bus[4]; + u8 iface_type[8]; + u64 iface_path; + union { + struct { + u64 device_path; + u8 reserved3; + u8 checksum; + } phoenix; + struct { + u64 device_path[2]; + u8 reserved3; + u8 checksum; + } t13; + }; +} PACKED; + +#define GET_INT13DPT(regs,var) \ + GET_FARVAR((regs)->ds, ((struct int13dpt_s*)((regs)->si+0))->var) +#define SET_INT13DPT(regs,var,val) \ + SET_FARVAR((regs)->ds, ((struct int13dpt_s*)((regs)->si+0))->var, (val)) + +// Floppy "Disk Base Table" +struct floppy_dbt_s { + u8 specify1; + u8 specify2; + u8 shutoff_ticks; + u8 bps_code; + u8 sectors; + u8 interblock_len; + u8 data_len; + u8 gap_len; + u8 fill_byte; + u8 settle_time; + u8 startup_time; +} PACKED; + +struct floppy_ext_dbt_s { + struct floppy_dbt_s dbt; + // Extra fields + u8 max_track; + u8 data_rate; + u8 drive_type; +} PACKED; + +// Helper function for setting up a return code. +struct bregs; +void __disk_ret(struct bregs *regs, u32 linecode, const char *fname); +#define disk_ret(regs, code) \ + __disk_ret((regs), (code) | (__LINE__ << 8), __func__) +void __disk_ret_unimplemented(struct bregs *regs, u32 linecode + , const char *fname); +#define disk_ret_unimplemented(regs, code) \ + __disk_ret_unimplemented((regs), (code) | (__LINE__ << 8), __func__) + + +/**************************************************************** + * Master boot record + ****************************************************************/ + +struct packed_chs_s { + u8 heads; + u8 sptcyl; + u8 cyllow; +}; + +struct partition_s { + u8 status; + struct packed_chs_s first; + u8 type; + struct packed_chs_s last; + u32 lba; + u32 count; +} PACKED; + +struct mbr_s { + u8 code[440]; + // 0x01b8 + u32 diskseg; + // 0x01bc + u16 null; + // 0x01be + struct partition_s partitions[4]; + // 0x01fe + u16 signature; +} PACKED; + +#define MBR_SIGNATURE 0xaa55 + + +/**************************************************************** + * Disk command request + ****************************************************************/ + +struct disk_op_s { + u64 lba; + void *buf_fl; + struct drive_s *drive_g; + u16 count; + u8 command; +}; + +#define CMD_RESET 0x00 +#define CMD_READ 0x02 +#define CMD_WRITE 0x03 +#define CMD_VERIFY 0x04 +#define CMD_FORMAT 0x05 +#define CMD_SEEK 0x07 +#define CMD_ISREADY 0x10 + + +/**************************************************************** + * Global storage + ****************************************************************/ + +struct chs_s { + u16 heads; // # heads + u16 cylinders; // # cylinders + u16 spt; // # sectors / track +}; + +struct drive_s { + u8 type; // Driver type (DTYPE_*) + u8 floppy_type; // Type of floppy (only for floppy drives). + struct chs_s lchs; // Logical CHS + u64 sectors; // Total sectors count + u32 cntl_id; // Unique id for a given driver type. + u8 removable; // Is media removable (currently unused) + + // Info for EDD calls + u8 translation; // type of translation + u16 blksize; // block size + struct chs_s pchs; // Physical CHS +}; + +#define DISK_SECTOR_SIZE 512 +#define CDROM_SECTOR_SIZE 2048 + +#define DTYPE_NONE 0x00 +#define DTYPE_FLOPPY 0x01 +#define DTYPE_ATA 0x02 +#define DTYPE_ATAPI 0x03 +#define DTYPE_RAMDISK 0x04 +#define DTYPE_CDEMU 0x05 +#define DTYPE_USB 0x06 +#define DTYPE_VIRTIO 0x07 +#define DTYPE_AHCI 0x08 + +#define MAXDESCSIZE 80 + +#define TRANSLATION_NONE 0 +#define TRANSLATION_LBA 1 +#define TRANSLATION_LARGE 2 +#define TRANSLATION_RECHS 3 + +#define EXTTYPE_FLOPPY 0 +#define EXTTYPE_HD 1 +#define EXTTYPE_CD 2 + +#define EXTSTART_HD 0x80 +#define EXTSTART_CD 0xE0 + + +/**************************************************************** + * Function defs + ****************************************************************/ + +// block.c +extern u8 FloppyCount, CDCount; +extern u8 *bounce_buf_fl; +struct drive_s *getDrive(u8 exttype, u8 extdriveoffset); +int getDriveId(u8 exttype, struct drive_s *drive_g); +void map_floppy_drive(struct drive_s *drive_g); +void map_hd_drive(struct drive_s *drive_g); +void map_cd_drive(struct drive_s *drive_g); +int process_op(struct disk_op_s *op); +int send_disk_op(struct disk_op_s *op); +int bounce_buf_init(void); + +// floppy.c +extern struct floppy_ext_dbt_s diskette_param_table2; +void floppy_setup(void); +struct drive_s *init_floppy(int floppyid, int ftype); +int find_floppy_type(u32 size); +int process_floppy_op(struct disk_op_s *op); +void floppy_tick(void); + +// cdrom.c +extern struct drive_s *cdemu_drive_gf; +int process_cdemu_op(struct disk_op_s *op); +void cdemu_setup(void); +void cdemu_134b(struct bregs *regs); +int cdrom_boot(struct drive_s *drive_g); + +// ramdisk.c +void ramdisk_setup(void); +int process_ramdisk_op(struct disk_op_s *op); + +#endif // disk.h diff --git a/bios/seabios/src/entryfuncs.S b/bios/seabios/src/entryfuncs.S new file mode 100644 index 0000000..afc5e61 --- /dev/null +++ b/bios/seabios/src/entryfuncs.S @@ -0,0 +1,173 @@ +// Macros for entering C code +// +// Copyright (C) 2008,2009 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + + +/**************************************************************** + * Entry macros + ****************************************************************/ + + // Call a C function - this does the minimal work necessary to + // call into C. It sets up %ds, backs up %es, and backs up + // those registers that are call clobbered by the C compiler. + .macro ENTRY cfunc + cli // In case something far-calls instead of using "int" + cld + pushl %eax // Save registers clobbered by C code + pushl %ecx + pushl %edx + pushw %es + pushw %ds + movw %ss, %ax // Move %ss to %ds + movw %ax, %ds + pushl %esp // Backup %esp, then clear high bits + movzwl %sp, %esp + calll \cfunc + popl %esp // Restore %esp (including high bits) + popw %ds // Restore registers saved above + popw %es + popl %edx + popl %ecx + popl %eax + .endm + + // As above, but get calling function from stack. + .macro ENTRY_ST + cli + cld + pushl %ecx + pushl %edx + pushw %es + pushw %ds + movw %ss, %cx // Move %ss to %ds + movw %cx, %ds + pushl %esp // Backup %esp, then clear high bits + movzwl %sp, %esp + movl 16(%esp), %ecx // Get calling function + movl %eax, 16(%esp) // Save %eax + calll *%ecx + popl %esp // Restore %esp (including high bits) + popw %ds // Restore registers saved above + popw %es + popl %edx + popl %ecx + popl %eax + .endm + + // Call a C function with current register list as an + // argument. This backs up the registers and sets %eax + // to point to the backup. On return, the registers are + // restored from the structure. + .macro ENTRY_ARG cfunc + cli + cld + pushl %eax // Save registers (matches struct bregs) + pushl %ecx + pushl %edx + pushl %ebx + pushl %ebp + pushl %esi + pushl %edi + pushw %es + pushw %ds + movw %ss, %ax // Move %ss to %ds + movw %ax, %ds + movl %esp, %ebx // Backup %esp, then zero high bits + movzwl %sp, %esp + movl %esp, %eax // First arg is pointer to struct bregs + calll \cfunc + movl %ebx, %esp // Restore %esp (including high bits) + popw %ds // Restore registers (from struct bregs) + popw %es + popl %edi + popl %esi + popl %ebp + popl %ebx + popl %edx + popl %ecx + popl %eax + .endm + + // As above, but get calling function from stack. + .macro ENTRY_ARG_ST + cli + cld + pushl %ecx + pushl %edx + pushl %ebx + pushl %ebp + pushl %esi + pushl %edi + pushw %es + pushw %ds + movw %ss, %cx // Move %ss to %ds + movw %cx, %ds + movl %esp, %ebx // Backup %esp, then zero high bits + movzwl %sp, %esp + movl 28(%esp), %ecx // Get calling function + movl %eax, 28(%esp) // Save %eax + movl %esp, %eax // First arg is pointer to struct bregs + calll *%ecx + movl %ebx, %esp // Restore %esp (including high bits) + popw %ds // Restore registers (from struct bregs) + popw %es + popl %edi + popl %esi + popl %ebp + popl %ebx + popl %edx + popl %ecx + popl %eax + .endm + + // Same as ENTRY_ARG, but don't mangle %esp + .macro ENTRY_ARG_ESP cfunc + cli + cld + pushl %eax // Save registers (matches struct bregs) + pushl %ecx + pushl %edx + pushl %ebx + pushl %ebp + pushl %esi + pushl %edi + pushw %es + pushw %ds + movw %ss, %ax // Move %ss to %ds + movw %ax, %ds + movl %esp, %eax // First arg is pointer to struct bregs + calll \cfunc + popw %ds // Restore registers (from struct bregs) + popw %es + popl %edi + popl %esi + popl %ebp + popl %ebx + popl %edx + popl %ecx + popl %eax + .endm + + // Reset stack, transition to 32bit mode, and call a C function. + // Clobbers %ax + .macro ENTRY_INTO32 cfunc + xorw %ax, %ax + movw %ax, %ss + movl $ BUILD_STACK_ADDR , %esp + movl $ \cfunc , %edx + jmp transition32 + .endm + + // Declare a function + .macro DECLFUNC func + .section .text.asm.\func + .global \func + .endm + + // Declare an exported function + .macro EXPORTFUNC func + .section .text.asm.export.\func + .global \func + .endm diff --git a/bios/seabios/src/farptr.h b/bios/seabios/src/farptr.h new file mode 100644 index 0000000..3dbf545 --- /dev/null +++ b/bios/seabios/src/farptr.h @@ -0,0 +1,204 @@ +// Code to access multiple segments within gcc. +// +// Copyright (C) 2008,2009 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. +#ifndef __FARPTR_H +#define __FARPTR_H + +#include "ioport.h" // insb + +// Dummy definitions used to make sure gcc understands dependencies +// between SET_SEG and GET/READ/WRITE_SEG macros. +extern u16 __segment_ES, __segment_CS, __segment_DS, __segment_SS; +extern u16 __segment_FS, __segment_GS; + +// Low level macros for reading/writing memory via a segment selector. +#define READ8_SEG(prefix, SEG, value, var) \ + __asm__(prefix "movb %%" #SEG ":%1, %b0" : "=Qi"(value) \ + : "m"(var), "m"(__segment_ ## SEG)) +#define READ16_SEG(prefix, SEG, value, var) \ + __asm__(prefix "movw %%" #SEG ":%1, %w0" : "=ri"(value) \ + : "m"(var), "m"(__segment_ ## SEG)) +#define READ32_SEG(prefix, SEG, value, var) \ + __asm__(prefix "movl %%" #SEG ":%1, %0" : "=ri"(value) \ + : "m"(var), "m"(__segment_ ## SEG)) +#define READ64_SEG(prefix, SEG, value, var) do { \ + union u64_u32_u __value; \ + union u64_u32_u *__r64_ptr = (union u64_u32_u *)&(var); \ + READ32_SEG(prefix, SEG, __value.hi, __r64_ptr->hi); \ + READ32_SEG(prefix, SEG, __value.lo, __r64_ptr->lo); \ + *(u64*)&(value) = __value.val; \ + } while (0) +#define WRITE8_SEG(prefix, SEG, var, value) \ + __asm__(prefix "movb %b1, %%" #SEG ":%0" : "=m"(var) \ + : "Q"(value), "m"(__segment_ ## SEG)) +#define WRITE16_SEG(prefix, SEG, var, value) \ + __asm__(prefix "movw %w1, %%" #SEG ":%0" : "=m"(var) \ + : "r"(value), "m"(__segment_ ## SEG)) +#define WRITE32_SEG(prefix, SEG, var, value) \ + __asm__(prefix "movl %1, %%" #SEG ":%0" : "=m"(var) \ + : "r"(value), "m"(__segment_ ## SEG)) +#define WRITE64_SEG(prefix, SEG, var, value) do { \ + union u64_u32_u __value; \ + union u64_u32_u *__w64_ptr = (union u64_u32_u *)&(var); \ + typeof(var) __value_tmp = (value); \ + __value.val = *(u64*)&__value_tmp; \ + WRITE32_SEG(prefix, SEG, __w64_ptr->hi, __value.hi); \ + WRITE32_SEG(prefix, SEG, __w64_ptr->lo, __value.lo); \ + } while (0) + +// Macros for automatically choosing the appropriate memory size +// access method. +extern void __force_link_error__unknown_type(void); + +#define __GET_VAR(prefix, seg, var) ({ \ + typeof(var) __val; \ + if (sizeof(__val) == 1) \ + READ8_SEG(prefix, seg, __val, var); \ + else if (sizeof(__val) == 2) \ + READ16_SEG(prefix, seg, __val, var); \ + else if (sizeof(__val) == 4) \ + READ32_SEG(prefix, seg, __val, var); \ + else if (sizeof(__val) == 8) \ + READ64_SEG(prefix, seg, __val, var); \ + else \ + __force_link_error__unknown_type(); \ + __val; }) + +#define __SET_VAR(prefix, seg, var, val) do { \ + if (sizeof(var) == 1) \ + WRITE8_SEG(prefix, seg, var, (val)); \ + else if (sizeof(var) == 2) \ + WRITE16_SEG(prefix, seg, var, (val)); \ + else if (sizeof(var) == 4) \ + WRITE32_SEG(prefix, seg, var, (val)); \ + else if (sizeof(var) == 8) \ + WRITE64_SEG(prefix, seg, var, (val)); \ + else \ + __force_link_error__unknown_type(); \ + } while (0) + +// Low level macros for getting/setting a segment register. +#define __SET_SEG(SEG, value) \ + __asm__("movw %w1, %%" #SEG : "=m"(__segment_ ## SEG) \ + : "rm"(value)) +#define __GET_SEG(SEG) ({ \ + u16 __seg; \ + __asm__("movw %%" #SEG ", %w0" : "=rm"(__seg) \ + : "m"(__segment_ ## SEG)); \ + __seg;}) + +// Macros for accessing a variable in another segment. (They +// automatically update the %es segment and then make the appropriate +// access.) +#define __GET_FARVAR(seg, var) ({ \ + SET_SEG(ES, (seg)); \ + GET_VAR(ES, (var)); }) +#define __SET_FARVAR(seg, var, val) do { \ + typeof(var) __sfv_val = (val); \ + SET_SEG(ES, (seg)); \ + SET_VAR(ES, (var), __sfv_val); \ + } while (0) + +// Macros for accesssing a 32bit flat mode pointer from 16bit real +// mode. (They automatically update the %es segment, break the +// pointer into segment/offset, and then make the access.) +#define __GET_FLATPTR(ptr) ({ \ + typeof(&(ptr)) __ptr = &(ptr); \ + GET_FARVAR(FLATPTR_TO_SEG(__ptr) \ + , *(typeof(__ptr))FLATPTR_TO_OFFSET(__ptr)); }) +#define __SET_FLATPTR(ptr, val) do { \ + typeof (&(ptr)) __ptr = &(ptr); \ + SET_FARVAR(FLATPTR_TO_SEG(__ptr) \ + , *(typeof(__ptr))FLATPTR_TO_OFFSET(__ptr) \ + , (val)); \ + } while (0) + +// Macros for converting to/from 32bit flat mode pointers to their +// equivalent 16bit segment/offset values. +#define FLATPTR_TO_SEG(p) (((u32)(p)) >> 4) +#define FLATPTR_TO_OFFSET(p) (((u32)(p)) & 0xf) +#define MAKE_FLATPTR(seg,off) ((void*)(((u32)(seg)<<4)+(u32)(off))) + + +#if MODESEGMENT == 1 + +// Definitions when using segmented mode. +#define GET_FARVAR(seg, var) __GET_FARVAR((seg), (var)) +#define SET_FARVAR(seg, var, val) __SET_FARVAR((seg), (var), (val)) +#define GET_VAR(seg, var) __GET_VAR("", seg, (var)) +#define SET_VAR(seg, var, val) __SET_VAR("", seg, (var), (val)) +#define SET_SEG(SEG, value) __SET_SEG(SEG, (value)) +#define GET_SEG(SEG) __GET_SEG(SEG) +#define GET_FLATPTR(ptr) __GET_FLATPTR(ptr) +#define SET_FLATPTR(ptr, val) __SET_FLATPTR((ptr), (val)) + +static inline void insb_fl(u16 port, void *ptr_fl, u16 count) { + SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl)); + insb(port, (u8*)FLATPTR_TO_OFFSET(ptr_fl), count); +} +static inline void insw_fl(u16 port, void *ptr_fl, u16 count) { + SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl)); + insw(port, (u16*)FLATPTR_TO_OFFSET(ptr_fl), count); +} +static inline void insl_fl(u16 port, void *ptr_fl, u16 count) { + SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl)); + insl(port, (u32*)FLATPTR_TO_OFFSET(ptr_fl), count); +} +static inline void outsb_fl(u16 port, void *ptr_fl, u16 count) { + SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl)); + outsb(port, (u8*)FLATPTR_TO_OFFSET(ptr_fl), count); +} +static inline void outsw_fl(u16 port, void *ptr_fl, u16 count) { + SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl)); + outsw(port, (u16*)FLATPTR_TO_OFFSET(ptr_fl), count); +} +static inline void outsl_fl(u16 port, void *ptr_fl, u16 count) { + SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl)); + outsl(port, (u32*)FLATPTR_TO_OFFSET(ptr_fl), count); +} + +#else + +// In 32-bit flat mode there is no need to mess with the segments. +#define GET_FARVAR(seg, var) \ + (*((typeof(&(var)))MAKE_FLATPTR((seg), &(var)))) +#define SET_FARVAR(seg, var, val) \ + do { GET_FARVAR((seg), (var)) = (val); } while (0) +#define GET_VAR(seg, var) (var) +#define SET_VAR(seg, var, val) do { (var) = (val); } while (0) +#define SET_SEG(SEG, value) ((void)(value)) +#define GET_SEG(SEG) 0 +#define GET_FLATPTR(ptr) (ptr) +#define SET_FLATPTR(ptr, val) do { (ptr) = (val); } while (0) + +#define insb_fl(port, ptr_fl, count) insb(port, ptr_fl, count) +#define insw_fl(port, ptr_fl, count) insw(port, ptr_fl, count) +#define insl_fl(port, ptr_fl, count) insl(port, ptr_fl, count) +#define outsb_fl(port, ptr_fl, count) outsb(port, ptr_fl, count) +#define outsw_fl(port, ptr_fl, count) outsw(port, ptr_fl, count) +#define outsl_fl(port, ptr_fl, count) outsl(port, ptr_fl, count) + +#endif + +// Definition for common 16bit segment/offset pointers. +struct segoff_s { + union { + struct { + u16 offset; + u16 seg; + }; + u32 segoff; + }; +}; +#define SEGOFF(s,o) ({struct segoff_s __so; __so.offset=(o); __so.seg=(s); __so;}) + +static inline struct segoff_s FLATPTR_TO_SEGOFF(void *p) { + return SEGOFF(FLATPTR_TO_SEG(p), FLATPTR_TO_OFFSET(p)); +} +static inline void *SEGOFF_TO_FLATPTR(struct segoff_s so) { + return MAKE_FLATPTR(so.seg, so.offset); +} + +#endif // farptr.h diff --git a/bios/seabios/src/floppy.c b/bios/seabios/src/floppy.c new file mode 100644 index 0000000..383744a --- /dev/null +++ b/bios/seabios/src/floppy.c @@ -0,0 +1,622 @@ +// 16bit code to access floppy drives. +// +// Copyright (C) 2008,2009 Kevin O'Connor +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "types.h" // u8 +#include "disk.h" // DISK_RET_SUCCESS +#include "config.h" // CONFIG_FLOPPY +#include "biosvar.h" // SET_BDA +#include "util.h" // wait_irq +#include "cmos.h" // inb_cmos +#include "pic.h" // eoi_pic1 +#include "bregs.h" // struct bregs +#include "boot.h" // boot_add_floppy +#include "pci.h" // pci_to_bdf +#include "pci_ids.h" // PCI_CLASS_BRIDGE_ISA + +#define FLOPPY_SIZE_CODE 0x02 // 512 byte sectors +#define FLOPPY_DATALEN 0xff // Not used - because size code is 0x02 +#define FLOPPY_MOTOR_TICKS 37 // ~2 seconds +#define FLOPPY_FILLBYTE 0xf6 +#define FLOPPY_GAPLEN 0x1B +#define FLOPPY_FORMAT_GAPLEN 0x6c + +// 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 +struct floppy_ext_dbt_s diskette_param_table2 VAR16VISIBLE = { + .dbt = { + .specify1 = 0xAF, // step rate 12ms, head unload 240ms + .specify2 = 0x02, // head load time 4ms, DMA used + .shutoff_ticks = FLOPPY_MOTOR_TICKS, // ~2 seconds + .bps_code = FLOPPY_SIZE_CODE, + .sectors = 18, + .interblock_len = FLOPPY_GAPLEN, + .data_len = FLOPPY_DATALEN, + .gap_len = FLOPPY_FORMAT_GAPLEN, + .fill_byte = FLOPPY_FILLBYTE, + .settle_time = 0x0F, // 15ms + .startup_time = 0x08, // 1 second + }, + .max_track = 79, // maximum track + .data_rate = 0, // data transfer rate + .drive_type = 4, // drive type in cmos +}; + +// Since no provisions are made for multiple drive types, most +// values in this table are ignored. I set parameters for 1.44M +// floppy here +struct floppy_dbt_s diskette_param_table VAR16FIXED(0xefc7) = { + .specify1 = 0xAF, + .specify2 = 0x02, + .shutoff_ticks = FLOPPY_MOTOR_TICKS, + .bps_code = FLOPPY_SIZE_CODE, + .sectors = 18, + .interblock_len = FLOPPY_GAPLEN, + .data_len = FLOPPY_DATALEN, + .gap_len = FLOPPY_FORMAT_GAPLEN, + .fill_byte = FLOPPY_FILLBYTE, + .settle_time = 0x0F, + .startup_time = 0x08, +}; + +struct floppyinfo_s { + struct chs_s chs; + u8 config_data; + u8 media_state; +}; + +struct floppyinfo_s FloppyInfo[] VAR16VISIBLE = { + // Unknown + { {0, 0, 0}, 0x00, 0x00}, + // 1 - 360KB, 5.25" - 2 heads, 40 tracks, 9 sectors + { {2, 40, 9}, 0x00, 0x25}, + // 2 - 1.2MB, 5.25" - 2 heads, 80 tracks, 15 sectors + { {2, 80, 15}, 0x00, 0x25}, + // 3 - 720KB, 3.5" - 2 heads, 80 tracks, 9 sectors + { {2, 80, 9}, 0x00, 0x17}, + // 4 - 1.44MB, 3.5" - 2 heads, 80 tracks, 18 sectors + { {2, 80, 18}, 0x00, 0x17}, + // 5 - 2.88MB, 3.5" - 2 heads, 80 tracks, 36 sectors + { {2, 80, 36}, 0xCC, 0xD7}, + // 6 - 160k, 5.25" - 1 heads, 40 tracks, 8 sectors + { {1, 40, 8}, 0x00, 0x27}, + // 7 - 180k, 5.25" - 1 heads, 40 tracks, 9 sectors + { {1, 40, 9}, 0x00, 0x27}, + // 8 - 320k, 5.25" - 2 heads, 40 tracks, 8 sectors + { {2, 40, 8}, 0x00, 0x27}, +}; + +struct drive_s * +init_floppy(int floppyid, int ftype) +{ + if (ftype <= 0 || ftype >= ARRAY_SIZE(FloppyInfo)) { + dprintf(1, "Bad floppy type %d\n", ftype); + return NULL; + } + + struct drive_s *drive_g = malloc_fseg(sizeof(*drive_g)); + if (!drive_g) { + warn_noalloc(); + return NULL; + } + memset(drive_g, 0, sizeof(*drive_g)); + drive_g->cntl_id = floppyid; + drive_g->type = DTYPE_FLOPPY; + drive_g->blksize = DISK_SECTOR_SIZE; + drive_g->floppy_type = ftype; + drive_g->sectors = (u64)-1; + + memcpy(&drive_g->lchs, &FloppyInfo[ftype].chs + , sizeof(FloppyInfo[ftype].chs)); + return drive_g; +} + +static void +addFloppy(int floppyid, int ftype) +{ + struct drive_s *drive_g = init_floppy(floppyid, ftype); + if (!drive_g) + return; + char *desc = znprintf(MAXDESCSIZE, "Floppy [drive %c]", 'A' + floppyid); + struct pci_device *pci = pci_find_class(PCI_CLASS_BRIDGE_ISA); /* isa-to-pci bridge */ + int prio = bootprio_find_fdc_device(pci, PORT_FD_BASE, floppyid); + boot_add_floppy(drive_g, desc, prio); +} + +void +floppy_setup(void) +{ + if (! CONFIG_FLOPPY) + return; + dprintf(3, "init floppy drives\n"); + + if (CONFIG_COREBOOT) { + // XXX - disable floppies on coreboot for now. + } else { + u8 type = inb_cmos(CMOS_FLOPPY_DRIVE_TYPE); + if (type & 0xf0) + addFloppy(0, type >> 4); + if (type & 0x0f) + addFloppy(1, type & 0x0f); + } + + outb(0x02, PORT_DMA1_MASK_REG); + + enable_hwirq(6, FUNC16(entry_0e)); +} + +// Find a floppy type that matches a given image size. +int +find_floppy_type(u32 size) +{ + int i; + for (i=1; icylinders * c->heads * c->spt * DISK_SECTOR_SIZE == size) + return i; + } + return -1; +} + + +/**************************************************************** + * Low-level floppy IO + ****************************************************************/ + +static void +floppy_reset_controller(void) +{ + // 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 int +wait_floppy_irq(void) +{ + ASSERT16(); + u8 v; + for (;;) { + if (!GET_BDA(floppy_motor_counter)) + return -1; + v = GET_BDA(floppy_recalibration_status); + if (v & FRS_TIMEOUT) + break; + // Could use wait_irq() here, but that causes issues on + // bochs, so use yield() instead. + yield(); + } + + v &= ~FRS_TIMEOUT; + SET_BDA(floppy_recalibration_status, v); + return 0; +} + +static void +floppy_prepare_controller(u8 floppyid) +{ + 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 (floppyid) + dor = 0x20; + dor |= 0x0c; + dor |= floppyid; + outb(dor, PORT_FD_DOR); + + // reset the disk motor timeout value of INT 08 + SET_BDA(floppy_motor_counter, FLOPPY_MOTOR_TICKS); + + // wait for drive readiness + while ((inb(PORT_FD_STATUS) & 0xc0) != 0x80) + ; + + if (!prev_reset) + wait_floppy_irq(); +} + +static int +floppy_pio(u8 *cmd, u8 cmdlen) +{ + floppy_prepare_controller(cmd[1] & 1); + + // send command to controller + u8 i; + for (i=0; ibuf_fl; + + // check for 64K boundary overrun + u16 end = count - 1; + u32 last_addr = addr + end; + if ((addr >> 16) != (last_addr >> 16)) + 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\n"); + outb(0x06, PORT_DMA1_MASK_REG); + outb(0x00, PORT_DMA1_CLEAR_FF_REG); // clear flip-flop + outb(addr, PORT_DMA_ADDR_2); + outb(addr>>8, PORT_DMA_ADDR_2); + outb(0x00, PORT_DMA1_CLEAR_FF_REG); // clear flip-flop + outb(end, PORT_DMA_CNT_2); + outb(end>>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(addr>>16, PORT_DMA_PAGE_2); + + outb(0x02, PORT_DMA1_MASK_REG); // unmask channel 2 + + int ret = floppy_pio(cmd, cmdlen); + if (ret) + return DISK_RET_ETIMEOUT; + + // check port 3f4 for accessibility to status bytes + if ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0) + return DISK_RET_ECONTROLLER; + + // 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 DISK_RET_SUCCESS; +} + + +/**************************************************************** + * Floppy media sense + ****************************************************************/ + +static inline void +set_diskette_current_cyl(u8 floppyid, u8 cyl) +{ + SET_BDA(floppy_track[floppyid], cyl); +} + +static void +floppy_drive_recal(u8 floppyid) +{ + // send Recalibrate command (2 bytes) to controller + u8 data[12]; + data[0] = 0x07; // 07: Recalibrate + data[1] = floppyid; // 0=drive0, 1=drive1 + floppy_pio(data, 2); + + SETBITS_BDA(floppy_recalibration_status, 1<floppy_type); + SET_BDA(floppy_last_data_rate, GET_GLOBAL(FloppyInfo[ftype].config_data)); + u8 floppyid = GET_GLOBAL(drive_g->cntl_id); + SET_BDA(floppy_media_state[floppyid] + , GET_GLOBAL(FloppyInfo[ftype].media_state)); + return DISK_RET_SUCCESS; +} + +static int +check_recal_drive(struct drive_s *drive_g) +{ + u8 floppyid = GET_GLOBAL(drive_g->cntl_id); + if ((GET_BDA(floppy_recalibration_status) & (1<lba; + + u32 tmp = lba + 1; + u16 nlspt = GET_GLOBAL(op->drive_g->lchs.spt); + *sector = tmp % nlspt; + + tmp /= nlspt; + u16 nlh = GET_GLOBAL(op->drive_g->lchs.heads); + *head = tmp % nlh; + + tmp /= nlh; + *track = tmp; +} + +// diskette controller reset +static int +floppy_reset(struct disk_op_s *op) +{ + u8 floppyid = GET_GLOBAL(op->drive_g->cntl_id); + set_diskette_current_cyl(floppyid, 0); // current cylinder + return DISK_RET_SUCCESS; +} + +// Read Diskette Sectors +static int +floppy_read(struct disk_op_s *op) +{ + int res = check_recal_drive(op->drive_g); + if (res) + goto fail; + + u8 track, sector, head; + lba2chs(op, &track, §or, &head); + + // send read-normal-data command (9 bytes) to controller + u8 floppyid = GET_GLOBAL(op->drive_g->cntl_id); + u8 data[12]; + data[0] = 0xe6; // e6: read normal data + data[1] = (head << 2) | floppyid; // HD DR1 DR2 + data[2] = track; + data[3] = head; + data[4] = sector; + data[5] = FLOPPY_SIZE_CODE; + data[6] = sector + op->count - 1; // last sector to read on track + data[7] = FLOPPY_GAPLEN; + data[8] = FLOPPY_DATALEN; + + res = floppy_cmd(op, op->count * DISK_SECTOR_SIZE, data, 9); + if (res) + goto fail; + + if (data[0] & 0xc0) { + res = DISK_RET_ECONTROLLER; + goto fail; + } + + // ??? should track be new val from return_status[3] ? + set_diskette_current_cyl(floppyid, track); + return DISK_RET_SUCCESS; +fail: + op->count = 0; // no sectors read + return res; +} + +// Write Diskette Sectors +static int +floppy_write(struct disk_op_s *op) +{ + int res = check_recal_drive(op->drive_g); + if (res) + goto fail; + + u8 track, sector, head; + lba2chs(op, &track, §or, &head); + + // send write-normal-data command (9 bytes) to controller + u8 floppyid = GET_GLOBAL(op->drive_g->cntl_id); + u8 data[12]; + data[0] = 0xc5; // c5: write normal data + data[1] = (head << 2) | floppyid; // HD DR1 DR2 + data[2] = track; + data[3] = head; + data[4] = sector; + data[5] = FLOPPY_SIZE_CODE; + data[6] = sector + op->count - 1; // last sector to write on track + data[7] = FLOPPY_GAPLEN; + data[8] = FLOPPY_DATALEN; + + res = floppy_cmd(op, op->count * DISK_SECTOR_SIZE, data, 9); + if (res) + goto fail; + + if (data[0] & 0xc0) { + if (data[1] & 0x02) + res = DISK_RET_EWRITEPROTECT; + else + res = DISK_RET_ECONTROLLER; + goto fail; + } + + // ??? should track be new val from return_status[3] ? + set_diskette_current_cyl(floppyid, track); + return DISK_RET_SUCCESS; +fail: + op->count = 0; // no sectors read + return res; +} + +// Verify Diskette Sectors +static int +floppy_verify(struct disk_op_s *op) +{ + int res = check_recal_drive(op->drive_g); + if (res) + goto fail; + + u8 track, sector, head; + lba2chs(op, &track, §or, &head); + + // ??? should track be new val from return_status[3] ? + u8 floppyid = GET_GLOBAL(op->drive_g->cntl_id); + set_diskette_current_cyl(floppyid, track); + return DISK_RET_SUCCESS; +fail: + op->count = 0; // no sectors read + return res; +} + +// format diskette track +static int +floppy_format(struct disk_op_s *op) +{ + int ret = check_recal_drive(op->drive_g); + if (ret) + return ret; + + u8 head = op->lba; + + // send format-track command (6 bytes) to controller + u8 floppyid = GET_GLOBAL(op->drive_g->cntl_id); + u8 data[12]; + data[0] = 0x4d; // 4d: format track + data[1] = (head << 2) | floppyid; // HD DR1 DR2 + data[2] = FLOPPY_SIZE_CODE; + data[3] = op->count; // number of sectors per track + data[4] = FLOPPY_FORMAT_GAPLEN; + data[5] = FLOPPY_FILLBYTE; + + ret = floppy_cmd(op, op->count * 4, data, 6); + if (ret) + return ret; + + if (data[0] & 0xc0) { + if (data[1] & 0x02) + return DISK_RET_EWRITEPROTECT; + return DISK_RET_ECONTROLLER; + } + + set_diskette_current_cyl(floppyid, 0); + return DISK_RET_SUCCESS; +} + +int +process_floppy_op(struct disk_op_s *op) +{ + if (!CONFIG_FLOPPY) + return 0; + + switch (op->command) { + case CMD_RESET: + return floppy_reset(op); + case CMD_READ: + return floppy_read(op); + case CMD_WRITE: + return floppy_write(op); + case CMD_VERIFY: + return floppy_verify(op); + case CMD_FORMAT: + return floppy_format(op); + default: + op->count = 0; + return DISK_RET_EPARAM; + } +} + + +/**************************************************************** + * HW irqs + ****************************************************************/ + +// INT 0Eh Diskette Hardware ISR Entry Point +void VISIBLE16 +handle_0e(void) +{ + debug_isr(DEBUG_ISR_0e); + if (! CONFIG_FLOPPY) + goto done; + + 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); + } + // diskette interrupt has occurred + SETBITS_BDA(floppy_recalibration_status, FRS_TIMEOUT); + +done: + eoi_pic1(); +} + +// Called from int08 handler. +void +floppy_tick(void) +{ + if (! CONFIG_FLOPPY) + return; + + // 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/bios/seabios/src/font.c b/bios/seabios/src/font.c new file mode 100644 index 0000000..3f8662f --- /dev/null +++ b/bios/seabios/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 + */ +u8 vgafont8[128*8] VAR16FIXED(0xfa6e) = { + 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/bios/seabios/src/gen-defs.h b/bios/seabios/src/gen-defs.h new file mode 100644 index 0000000..dabf64c --- /dev/null +++ b/bios/seabios/src/gen-defs.h @@ -0,0 +1,19 @@ +// Tool for building defintions accessible from assembler code. This +// is based on code from the Linux Kernel. +#ifndef __GEN_DEFS_H +#define __GEN_DEFS_H + + +#define DEFINE(sym, val) \ + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) + +#define BLANK() \ + asm volatile("\n->" : : ) + +#define OFFSET(sym, str, mem) \ + DEFINE(sym, offsetof(struct str, mem)) + +#define COMMENT(x) \ + asm volatile("\n->#" x) + +#endif // gen-defs.h diff --git a/bios/seabios/src/ioport.h b/bios/seabios/src/ioport.h new file mode 100644 index 0000000..3282fb4 --- /dev/null +++ b/bios/seabios/src/ioport.h @@ -0,0 +1,136 @@ +// Definitions for X86 IO port access. +// +// Copyright (C) 2008 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. +#ifndef __IOPORT_H +#define __IOPORT_H + +#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_CMD 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_PS2_DATA 0x0060 +#define PORT_PS2_CTRLB 0x0061 +#define PORT_PS2_STATUS 0x0064 +#define PORT_CMOS_INDEX 0x0070 +#define PORT_CMOS_DATA 0x0071 +#define PORT_DIAG 0x0080 +#define PORT_DMA_PAGE_2 0x0081 +#define PORT_A20 0x0092 +#define PORT_PIC2_CMD 0x00a0 +#define PORT_PIC2_DATA 0x00a1 +#define PORT_SMI_CMD 0x00b2 +#define PORT_SMI_STATUS 0x00b3 +#define PORT_DMA2_MASK_REG 0x00d4 +#define PORT_DMA2_MODE_REG 0x00d6 +#define PORT_DMA2_MASTER_CLEAR 0x00da +#define PORT_MATH_CLEAR 0x00f0 +#define PORT_ATA2_CMD_BASE 0x0170 +#define PORT_ATA1_CMD_BASE 0x01f0 +#define PORT_LPT2 0x0278 +#define PORT_SERIAL4 0x02e8 +#define PORT_SERIAL2 0x02f8 +#define PORT_ATA2_CTRL_BASE 0x0374 +#define PORT_LPT1 0x0378 +#define PORT_SERIAL3 0x03e8 +#define PORT_ATA1_CTRL_BASE 0x03f4 +#define PORT_FD_BASE 0x03f0 +#define PORT_FD_DOR 0x03f2 +#define PORT_FD_STATUS 0x03f4 +#define PORT_FD_DATA 0x03f5 +#define PORT_HD_DATA 0x03f6 +#define PORT_FD_DIR 0x03f7 +#define PORT_SERIAL1 0x03f8 +#define PORT_PCI_CMD 0x0cf8 +#define PORT_PCI_REBOOT 0x0cf9 +#define PORT_PCI_DATA 0x0cfc +#define PORT_BIOS_DEBUG 0x0402 +#define PORT_QEMU_CFG_CTL 0x0510 +#define PORT_QEMU_CFG_DATA 0x0511 +#define PORT_ACPI_PM_BASE 0xb000 +#define PORT_SMB_BASE 0xb100 +#define PORT_BIOS_APM 0x8900 + +// Serial port offsets +#define SEROFF_DATA 0 +#define SEROFF_DLL 0 +#define SEROFF_IER 1 +#define SEROFF_DLH 1 +#define SEROFF_IIR 2 +#define SEROFF_LCR 3 +#define SEROFF_LSR 5 +#define SEROFF_MSR 6 + +// PORT_A20 bitdefs +#define A20_ENABLE_BIT 0x02 + +// PORT_CMOS_INDEX nmi disable bit +#define NMI_DISABLE_BIT 0x80 + +#ifndef __ASSEMBLY__ + +#include "types.h" // u8 + +static inline void outb(u8 value, u16 port) { + __asm__ __volatile__("outb %b0, %w1" : : "a"(value), "Nd"(port)); +} +static inline void outw(u16 value, u16 port) { + __asm__ __volatile__("outw %w0, %w1" : : "a"(value), "Nd"(port)); +} +static inline void outl(u32 value, u16 port) { + __asm__ __volatile__("outl %0, %w1" : : "a"(value), "Nd"(port)); +} +static inline u8 inb(u16 port) { + u8 value; + __asm__ __volatile__("inb %w1, %b0" : "=a"(value) : "Nd"(port)); + return value; +} +static inline u16 inw(u16 port) { + u16 value; + __asm__ __volatile__("inw %w1, %w0" : "=a"(value) : "Nd"(port)); + return value; +} +static inline u32 inl(u16 port) { + u32 value; + __asm__ __volatile__("inl %w1, %0" : "=a"(value) : "Nd"(port)); + return value; +} + +static inline void insb(u16 port, u8 *data, u32 count) { + asm volatile("rep insb (%%dx), %%es:(%%edi)" + : "+c"(count), "+D"(data) : "d"(port) : "memory"); +} +static inline void insw(u16 port, u16 *data, u32 count) { + asm volatile("rep insw (%%dx), %%es:(%%edi)" + : "+c"(count), "+D"(data) : "d"(port) : "memory"); +} +static inline void insl(u16 port, u32 *data, u32 count) { + asm volatile("rep insl (%%dx), %%es:(%%edi)" + : "+c"(count), "+D"(data) : "d"(port) : "memory"); +} +// XXX - outs not limited to es segment +static inline void outsb(u16 port, u8 *data, u32 count) { + asm volatile("rep outsb %%es:(%%esi), (%%dx)" + : "+c"(count), "+S"(data) : "d"(port) : "memory"); +} +static inline void outsw(u16 port, u16 *data, u32 count) { + asm volatile("rep outsw %%es:(%%esi), (%%dx)" + : "+c"(count), "+S"(data) : "d"(port) : "memory"); +} +static inline void outsl(u16 port, u32 *data, u32 count) { + asm volatile("rep outsl %%es:(%%esi), (%%dx)" + : "+c"(count), "+S"(data) : "d"(port) : "memory"); +} + +#endif // !__ASSEMBLY__ + +#endif // ioport.h diff --git a/bios/seabios/src/jpeg.c b/bios/seabios/src/jpeg.c new file mode 100644 index 0000000..a96a9d7 --- /dev/null +++ b/bios/seabios/src/jpeg.c @@ -0,0 +1,1054 @@ +/* + * Copyright (C) 2001, Novell Inc. + * Copyright (C) 2010 Kevin O'Connor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of Novell nor the names of the contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * a tiny jpeg decoder. + * + * written in August 2001 by Michael Schroeder + * + */ + +#define __LITTLE_ENDIAN +#include "util.h" +#include "jpeg.h" +#define ISHIFT 11 + +#define IFIX(a) ((int)((a) * (1 << ISHIFT) + .5)) +#define IMULT(a, b) (((a) * (b)) >> ISHIFT) +#define ITOINT(a) ((a) >> ISHIFT) + +#ifndef __P +# define __P(x) x +#endif + +/* special markers */ +#define M_BADHUFF -1 +#define M_EOF 0x80 + +struct in { + unsigned char *p; + unsigned int bits; + int left; + int marker; + + int (*func) __P((void *)); + void *data; +}; + +/*********************************/ +struct dec_hufftbl; +struct enc_hufftbl; + +union hufftblp { + struct dec_hufftbl *dhuff; + struct enc_hufftbl *ehuff; +}; + +struct scan { + int dc; /* old dc value */ + + union hufftblp hudc; + union hufftblp huac; + int next; /* when to switch to next scan */ + + int cid; /* component id */ + int hv; /* horiz/vert, copied from comp */ + int tq; /* quant tbl, copied from comp */ +}; + +/*********************************/ + +#define DECBITS 10 /* seems to be the optimum */ + +struct dec_hufftbl { + int maxcode[17]; + int valptr[16]; + unsigned char vals[256]; + unsigned int llvals[1 << DECBITS]; +}; + +static void decode_mcus __P((struct in *, int *, int, struct scan *, int *)); +static int dec_readmarker __P((struct in *)); +static void dec_makehuff __P((struct dec_hufftbl *, int *, unsigned char *)); + +static void setinput __P((struct in *, unsigned char *)); +/*********************************/ + +#undef PREC +#define PREC int + +static void idctqtab __P((unsigned char *, PREC *)); +static void idct __P((int *, int *, PREC *, PREC, int)); +static void scaleidctqtab __P((PREC *, PREC)); + +/*********************************/ + +static void initcol __P((PREC[][64])); + +static void col221111 __P((int *, unsigned char *, int)); +static void col221111_16 __P((int *, unsigned char *, int)); +static void col221111_32 __P((int *, unsigned char *, int)); + +/*********************************/ + +#define ERR_NO_SOI 1 +#define ERR_NOT_8BIT 2 +#define ERR_HEIGHT_MISMATCH 3 +#define ERR_WIDTH_MISMATCH 4 +#define ERR_BAD_WIDTH_OR_HEIGHT 5 +#define ERR_TOO_MANY_COMPPS 6 +#define ERR_ILLEGAL_HV 7 +#define ERR_QUANT_TABLE_SELECTOR 8 +#define ERR_NOT_YCBCR_221111 9 +#define ERR_UNKNOWN_CID_IN_SCAN 10 +#define ERR_NOT_SEQUENTIAL_DCT 11 +#define ERR_WRONG_MARKER 12 +#define ERR_NO_EOI 13 +#define ERR_BAD_TABLES 14 +#define ERR_DEPTH_MISMATCH 15 + +/*********************************/ + +#define M_SOI 0xd8 +#define M_APP0 0xe0 +#define M_DQT 0xdb +#define M_SOF0 0xc0 +#define M_DHT 0xc4 +#define M_DRI 0xdd +#define M_SOS 0xda +#define M_RST0 0xd0 +#define M_EOI 0xd9 +#define M_COM 0xfe + +struct comp { + int cid; + int hv; + int tq; +}; + +#define MAXCOMP 4 +struct jpginfo { + int nc; /* number of components */ + int ns; /* number of scans */ + int dri; /* restart interval */ + int nm; /* mcus til next marker */ + int rm; /* next restart marker */ +}; + +struct jpeg_decdata { + int dcts[6 * 64 + 16]; + int out[64 * 6]; + int dquant[3][64]; + + unsigned char *datap; + struct jpginfo info; + struct comp comps[MAXCOMP]; + struct scan dscans[MAXCOMP]; + unsigned char quant[4][64]; + struct dec_hufftbl dhuff[4]; + struct in in; + + int height, width; +}; + +static int getbyte(struct jpeg_decdata *jpeg) +{ + return *jpeg->datap++; +} + +static int getword(struct jpeg_decdata *jpeg) +{ + int c1, c2; + c1 = *jpeg->datap++; + c2 = *jpeg->datap++; + return c1 << 8 | c2; +} + +static int readtables(struct jpeg_decdata *jpeg, int till) +{ + int m, l, i, j, lq, pq, tq; + int tc, th, tt; + + for (;;) { + if (getbyte(jpeg) != 0xff) + return -1; + if ((m = getbyte(jpeg)) == till) + break; + + switch (m) { + case 0xc2: + return 0; + + case M_DQT: + lq = getword(jpeg); + while (lq > 2) { + pq = getbyte(jpeg); + tq = pq & 15; + if (tq > 3) + return -1; + pq >>= 4; + if (pq != 0) + return -1; + for (i = 0; i < 64; i++) + jpeg->quant[tq][i] = getbyte(jpeg); + lq -= 64 + 1; + } + break; + + case M_DHT: + l = getword(jpeg); + while (l > 2) { + int hufflen[16], k; + unsigned char huffvals[256]; + + tc = getbyte(jpeg); + th = tc & 15; + tc >>= 4; + tt = tc * 2 + th; + if (tc > 1 || th > 1) + return -1; + for (i = 0; i < 16; i++) + hufflen[i] = getbyte(jpeg); + l -= 1 + 16; + k = 0; + for (i = 0; i < 16; i++) { + for (j = 0; j < hufflen[i]; j++) + huffvals[k++] = getbyte(jpeg); + l -= hufflen[i]; + } + dec_makehuff(jpeg->dhuff + tt, hufflen, huffvals); + } + break; + + case M_DRI: + l = getword(jpeg); + jpeg->info.dri = getword(jpeg); + break; + + default: + l = getword(jpeg); + while (l-- > 2) + getbyte(jpeg); + break; + } + } + return 0; +} + +static void dec_initscans(struct jpeg_decdata *jpeg) +{ + int i; + + jpeg->info.nm = jpeg->info.dri + 1; + jpeg->info.rm = M_RST0; + for (i = 0; i < jpeg->info.ns; i++) + jpeg->dscans[i].dc = 0; +} + +static int dec_checkmarker(struct jpeg_decdata *jpeg) +{ + int i; + + if (dec_readmarker(&jpeg->in) != jpeg->info.rm) + return -1; + jpeg->info.nm = jpeg->info.dri; + jpeg->info.rm = (jpeg->info.rm + 1) & ~0x08; + for (i = 0; i < jpeg->info.ns; i++) + jpeg->dscans[i].dc = 0; + return 0; +} + +struct jpeg_decdata *jpeg_alloc(void) +{ + struct jpeg_decdata *jpeg = malloc_tmphigh(sizeof(*jpeg)); + return jpeg; +} + +int jpeg_decode(struct jpeg_decdata *jpeg, unsigned char *buf) +{ + int i, j, m, tac, tdc; + + if (!jpeg || !buf) + return -1; + jpeg->datap = buf; + if (getbyte(jpeg) != 0xff) + return ERR_NO_SOI; + if (getbyte(jpeg) != M_SOI) + return ERR_NO_SOI; + if (readtables(jpeg, M_SOF0)) + return ERR_BAD_TABLES; + getword(jpeg); + i = getbyte(jpeg); + if (i != 8) + return ERR_NOT_8BIT; + jpeg->height = getword(jpeg); + jpeg->width = getword(jpeg); + if ((jpeg->height & 15) || (jpeg->width & 15)) + return ERR_BAD_WIDTH_OR_HEIGHT; + jpeg->info.nc = getbyte(jpeg); + if (jpeg->info.nc > MAXCOMP) + return ERR_TOO_MANY_COMPPS; + for (i = 0; i < jpeg->info.nc; i++) { + int h, v; + jpeg->comps[i].cid = getbyte(jpeg); + jpeg->comps[i].hv = getbyte(jpeg); + v = jpeg->comps[i].hv & 15; + h = jpeg->comps[i].hv >> 4; + jpeg->comps[i].tq = getbyte(jpeg); + if (h > 3 || v > 3) + return ERR_ILLEGAL_HV; + if (jpeg->comps[i].tq > 3) + return ERR_QUANT_TABLE_SELECTOR; + } + if (readtables(jpeg, M_SOS)) + return ERR_BAD_TABLES; + getword(jpeg); + jpeg->info.ns = getbyte(jpeg); + if (jpeg->info.ns != 3) + return ERR_NOT_YCBCR_221111; + for (i = 0; i < 3; i++) { + jpeg->dscans[i].cid = getbyte(jpeg); + tdc = getbyte(jpeg); + tac = tdc & 15; + tdc >>= 4; + if (tdc > 1 || tac > 1) + return ERR_QUANT_TABLE_SELECTOR; + for (j = 0; j < jpeg->info.nc; j++) + if (jpeg->comps[j].cid == jpeg->dscans[i].cid) + break; + if (j == jpeg->info.nc) + return ERR_UNKNOWN_CID_IN_SCAN; + jpeg->dscans[i].hv = jpeg->comps[j].hv; + jpeg->dscans[i].tq = jpeg->comps[j].tq; + jpeg->dscans[i].hudc.dhuff = &jpeg->dhuff[tdc]; + jpeg->dscans[i].huac.dhuff = &jpeg->dhuff[2 + tac]; + } + + i = getbyte(jpeg); + j = getbyte(jpeg); + m = getbyte(jpeg); + + if (i != 0 || j != 63 || m != 0) + return ERR_NOT_SEQUENTIAL_DCT; + + if (jpeg->dscans[0].cid != 1 || jpeg->dscans[1].cid != 2 + || jpeg->dscans[2].cid != 3) + return ERR_NOT_YCBCR_221111; + + if (jpeg->dscans[0].hv != 0x22 || jpeg->dscans[1].hv != 0x11 + || jpeg->dscans[2].hv != 0x11) + return ERR_NOT_YCBCR_221111; + + idctqtab(jpeg->quant[jpeg->dscans[0].tq], jpeg->dquant[0]); + idctqtab(jpeg->quant[jpeg->dscans[1].tq], jpeg->dquant[1]); + idctqtab(jpeg->quant[jpeg->dscans[2].tq], jpeg->dquant[2]); + initcol(jpeg->dquant); + setinput(&jpeg->in, jpeg->datap); + +#if 0 + /* landing zone */ + img[len] = 0; + img[len + 1] = 0xff; + img[len + 2] = M_EOF; +#endif + + dec_initscans(jpeg); + + return 0; +} + +void jpeg_get_size(struct jpeg_decdata *jpeg, int *width, int *height) +{ + *width = jpeg->width; + *height = jpeg->height; +} + +int jpeg_show(struct jpeg_decdata *jpeg, unsigned char *pic, int width + , int height, int depth, int bytes_per_line_dest) +{ + int m, mcusx, mcusy, mx, my, mloffset, jpgbpl; + int max[6]; + + if (jpeg->height != height) + return ERR_HEIGHT_MISMATCH; + if (jpeg->width != width) + return ERR_WIDTH_MISMATCH; + + jpgbpl = width * depth / 8; + mloffset = bytes_per_line_dest > jpgbpl ? bytes_per_line_dest : jpgbpl; + + mcusx = jpeg->width >> 4; + mcusy = jpeg->height >> 4; + + jpeg->dscans[0].next = 6 - 4; + jpeg->dscans[1].next = 6 - 4 - 1; + jpeg->dscans[2].next = 6 - 4 - 1 - 1; /* 411 encoding */ + for (my = 0; my < mcusy; my++) { + for (mx = 0; mx < mcusx; mx++) { + if (jpeg->info.dri && !--jpeg->info.nm) + if (dec_checkmarker(jpeg)) + return ERR_WRONG_MARKER; + + decode_mcus(&jpeg->in, jpeg->dcts, 6, jpeg->dscans, max); + idct(jpeg->dcts, jpeg->out, jpeg->dquant[0], + IFIX(128.5), max[0]); + idct(jpeg->dcts + 64, jpeg->out + 64, jpeg->dquant[0], + IFIX(128.5), max[1]); + idct(jpeg->dcts + 128, jpeg->out + 128, jpeg->dquant[0], + IFIX(128.5), max[2]); + idct(jpeg->dcts + 192, jpeg->out + 192, jpeg->dquant[0], + IFIX(128.5), max[3]); + idct(jpeg->dcts + 256, jpeg->out + 256, jpeg->dquant[1], + IFIX(0.5), max[4]); + idct(jpeg->dcts + 320, jpeg->out + 320, jpeg->dquant[2], + IFIX(0.5), max[5]); + + switch (depth) { + case 32: + col221111_32(jpeg->out, + pic + (my * 16 * mloffset + mx * 16 * 4), + mloffset); + break; + case 24: + col221111(jpeg->out, + pic + (my * 16 * mloffset + mx * 16 * 3), + mloffset); + break; + case 16: + col221111_16(jpeg->out, + pic + (my * 16 * mloffset + mx * 16 * 2), + mloffset); + break; + default: + return ERR_DEPTH_MISMATCH; + break; + } + } + } + + m = dec_readmarker(&jpeg->in); + if (m != M_EOI) + return ERR_NO_EOI; + + return 0; +} + +/****************************************************************/ +/************** huffman decoder ***************/ +/****************************************************************/ + +static int fillbits __P((struct in *, int, unsigned int)); +static int dec_rec2 __P((struct in *, struct dec_hufftbl *, int *, int, int)); + +static void setinput(struct in *in, unsigned char *p) +{ + in->p = p; + in->left = 0; + in->bits = 0; + in->marker = 0; +} + +static int fillbits(struct in *in, int le, unsigned int bi) +{ + int b, m; + + if (in->marker) { + if (le <= 16) + in->bits = bi << 16, le += 16; + return le; + } + while (le <= 24) { + b = *in->p++; + if (b == 0xff && (m = *in->p++) != 0) { + if (m == M_EOF) { + if (in->func && (m = in->func(in->data)) == 0) + continue; + } + in->marker = m; + if (le <= 16) + bi = bi << 16, le += 16; + break; + } + bi = bi << 8 | b; + le += 8; + } + in->bits = bi; /* tmp... 2 return values needed */ + return le; +} + +static int dec_readmarker(struct in *in) +{ + int m; + + in->left = fillbits(in, in->left, in->bits); + if ((m = in->marker) == 0) + return 0; + in->left = 0; + in->marker = 0; + return m; +} + +#define LEBI_DCL int le, bi +#define LEBI_GET(in) (le = in->left, bi = in->bits) +#define LEBI_PUT(in) (in->left = le, in->bits = bi) + +#define GETBITS(in, n) ( \ + (le < (n) ? le = fillbits(in, le, bi), bi = in->bits : 0), \ + (le -= (n)), \ + bi >> le & ((1 << (n)) - 1) \ +) + +#define UNGETBITS(in, n) ( \ + le += (n) \ +) + + +static int dec_rec2(struct in *in, struct dec_hufftbl *hu, int *runp, + int c, int i) +{ + LEBI_DCL; + + LEBI_GET(in); + if (i) { + UNGETBITS(in, i & 127); + *runp = i >> 8 & 15; + i >>= 16; + } else { + for (i = DECBITS; + (c = ((c << 1) | GETBITS(in, 1))) >= (hu->maxcode[i]); i++); + if (i >= 16) { + in->marker = M_BADHUFF; + return 0; + } + i = hu->vals[hu->valptr[i] + c - hu->maxcode[i - 1] * 2]; + *runp = i >> 4; + i &= 15; + } + if (i == 0) { /* sigh, 0xf0 is 11 bit */ + LEBI_PUT(in); + return 0; + } + /* receive part */ + c = GETBITS(in, i); + if (c < (1 << (i - 1))) + c += (-1 << i) + 1; + LEBI_PUT(in); + return c; +} + +#define DEC_REC(in, hu, r, i) ( \ + r = GETBITS(in, DECBITS), \ + i = hu->llvals[r], \ + i & 128 ? \ + ( \ + UNGETBITS(in, i & 127), \ + r = i >> 8 & 15, \ + i >> 16 \ + ) \ + : \ + ( \ + LEBI_PUT(in), \ + i = dec_rec2(in, hu, &r, r, i), \ + LEBI_GET(in), \ + i \ + ) \ +) + +static void decode_mcus(struct in *in, int *dct, int n, struct scan *sc, + int *maxp) +{ + struct dec_hufftbl *hu; + int i, r, t; + LEBI_DCL; + + memset(dct, 0, n * 64 * sizeof(*dct)); + LEBI_GET(in); + while (n-- > 0) { + hu = sc->hudc.dhuff; + *dct++ = (sc->dc += DEC_REC(in, hu, r, t)); + + hu = sc->huac.dhuff; + i = 63; + while (i > 0) { + t = DEC_REC(in, hu, r, t); + if (t == 0 && r == 0) { + dct += i; + break; + } + dct += r; + *dct++ = t; + i -= r + 1; + } + *maxp++ = 64 - i; + if (n == sc->next) + sc++; + } + LEBI_PUT(in); +} + +static void dec_makehuff(struct dec_hufftbl *hu, int *hufflen, + unsigned char *huffvals) +{ + int code, k, i, j, d, x, c, v; + for (i = 0; i < (1 << DECBITS); i++) + hu->llvals[i] = 0; + + /* + * llvals layout: + * + * value v already known, run r, backup u bits: + * vvvvvvvvvvvvvvvv 0000 rrrr 1 uuuuuuu + * value unknown, size b bits, run r, backup u bits: + * 000000000000bbbb 0000 rrrr 0 uuuuuuu + * value and size unknown: + * 0000000000000000 0000 0000 0 0000000 + */ + + code = 0; + k = 0; + for (i = 0; i < 16; i++, code <<= 1) { /* sizes */ + hu->valptr[i] = k; + for (j = 0; j < hufflen[i]; j++) { + hu->vals[k] = *huffvals++; + if (i < DECBITS) { + c = code << (DECBITS - 1 - i); + v = hu->vals[k] & 0x0f; /* size */ + for (d = 1 << (DECBITS - 1 - i); --d >= 0;) { + if (v + i < DECBITS) { /* both fit in table */ + x = d >> (DECBITS - 1 - v - i); + if (v && x < (1 << (v - 1))) + x += (-1 << v) + 1; + x = x << 16 | (hu->vals[k] & 0xf0) << 4 | + (DECBITS - (i + 1 + v)) | 128; + } else + x = v << 16 | (hu->vals[k] & 0xf0) << 4 | + (DECBITS - (i + 1)); + hu->llvals[c | d] = x; + } + } + code++; + k++; + } + hu->maxcode[i] = code; + } + hu->maxcode[16] = 0x20000; /* always terminate decode */ +} + +/****************************************************************/ +/************** idct ***************/ +/****************************************************************/ + +#define ONE ((PREC)IFIX(1.)) +#define S2 ((PREC)IFIX(0.382683432)) +#define C2 ((PREC)IFIX(0.923879532)) +#define C4 ((PREC)IFIX(0.707106781)) + +#define S22 ((PREC)IFIX(2 * 0.382683432)) +#define C22 ((PREC)IFIX(2 * 0.923879532)) +#define IC4 ((PREC)IFIX(1 / 0.707106781)) + +#define C3IC1 ((PREC)IFIX(0.847759065)) /* c3/c1 */ +#define C5IC1 ((PREC)IFIX(0.566454497)) /* c5/c1 */ +#define C7IC1 ((PREC)IFIX(0.198912367)) /* c7/c1 */ + +#define XPP(a,b) (t = a + b, b = a - b, a = t) +#define XMP(a,b) (t = a - b, b = a + b, a = t) +#define XPM(a,b) (t = a + b, b = b - a, a = t) + +#define ROT(a,b,s,c) ( t = IMULT(a + b, s), \ + a = IMULT(a, c - s) + t, \ + b = IMULT(b, c + s) - t) + +#define IDCT \ +( \ + XPP(t0, t1), \ + XMP(t2, t3), \ + t2 = IMULT(t2, IC4) - t3, \ + XPP(t0, t3), \ + XPP(t1, t2), \ + XMP(t4, t7), \ + XPP(t5, t6), \ + XMP(t5, t7), \ + t5 = IMULT(t5, IC4), \ + ROT(t4, t6, S22, C22), \ + t6 -= t7, \ + t5 -= t6, \ + t4 -= t5, \ + XPP(t0, t7), \ + XPP(t1, t6), \ + XPP(t2, t5), \ + XPP(t3, t4) \ +) + +static unsigned char zig2[64] = { + 0, 2, 3, 9, 10, 20, 21, 35, + 14, 16, 25, 31, 39, 46, 50, 57, + 5, 7, 12, 18, 23, 33, 37, 48, + 27, 29, 41, 44, 52, 55, 59, 62, + 15, 26, 30, 40, 45, 51, 56, 58, + 1, 4, 8, 11, 19, 22, 34, 36, + 28, 42, 43, 53, 54, 60, 61, 63, + 6, 13, 17, 24, 32, 38, 47, 49 +}; + +static void idct(int *in, int *out, PREC * quant, PREC off, int max) +{ + PREC t0, t1, t2, t3, t4, t5, t6, t7, t; + PREC tmp[64], *tmpp; + int i, j; + unsigned char *zig2p; + + t0 = off; + if (max == 1) { + t0 += in[0] * quant[0]; + for (i = 0; i < 64; i++) + out[i] = ITOINT(t0); + return; + } + zig2p = zig2; + tmpp = tmp; + for (i = 0; i < 8; i++) { + j = *zig2p++; + t0 += in[j] * quant[j]; + j = *zig2p++; + t5 = in[j] * quant[j]; + j = *zig2p++; + t2 = in[j] * quant[j]; + j = *zig2p++; + t7 = in[j] * quant[j]; + j = *zig2p++; + t1 = in[j] * quant[j]; + j = *zig2p++; + t4 = in[j] * quant[j]; + j = *zig2p++; + t3 = in[j] * quant[j]; + j = *zig2p++; + t6 = in[j] * quant[j]; + IDCT; + tmpp[0 * 8] = t0; + tmpp[1 * 8] = t1; + tmpp[2 * 8] = t2; + tmpp[3 * 8] = t3; + tmpp[4 * 8] = t4; + tmpp[5 * 8] = t5; + tmpp[6 * 8] = t6; + tmpp[7 * 8] = t7; + tmpp++; + t0 = 0; + } + for (i = 0; i < 8; i++) { + t0 = tmp[8 * i + 0]; + t1 = tmp[8 * i + 1]; + t2 = tmp[8 * i + 2]; + t3 = tmp[8 * i + 3]; + t4 = tmp[8 * i + 4]; + t5 = tmp[8 * i + 5]; + t6 = tmp[8 * i + 6]; + t7 = tmp[8 * i + 7]; + IDCT; + out[8 * i + 0] = ITOINT(t0); + out[8 * i + 1] = ITOINT(t1); + out[8 * i + 2] = ITOINT(t2); + out[8 * i + 3] = ITOINT(t3); + out[8 * i + 4] = ITOINT(t4); + out[8 * i + 5] = ITOINT(t5); + out[8 * i + 6] = ITOINT(t6); + out[8 * i + 7] = ITOINT(t7); + } +} + +static unsigned char zig[64] = { + 0, 1, 5, 6, 14, 15, 27, 28, + 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, + 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, + 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, + 35, 36, 48, 49, 57, 58, 62, 63 +}; + +static PREC aaidct[8] = { + IFIX(0.3535533906), IFIX(0.4903926402), + IFIX(0.4619397663), IFIX(0.4157348062), + IFIX(0.3535533906), IFIX(0.2777851165), + IFIX(0.1913417162), IFIX(0.0975451610) +}; + + +static void idctqtab(unsigned char *qin, PREC * qout) +{ + int i, j; + + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + qout[zig[i * 8 + j]] = qin[zig[i * 8 + j]] * + IMULT(aaidct[i], aaidct[j]); +} + +static void scaleidctqtab(PREC * q, PREC sc) +{ + int i; + + for (i = 0; i < 64; i++) + q[i] = IMULT(q[i], sc); +} + +/****************************************************************/ +/************** color decoder ***************/ +/****************************************************************/ + +#define ROUND + +/* + * YCbCr Color transformation: + * + * y:0..255 Cb:-128..127 Cr:-128..127 + * + * R = Y + 1.40200 * Cr + * G = Y - 0.34414 * Cb - 0.71414 * Cr + * B = Y + 1.77200 * Cb + * + * => + * Cr *= 1.40200; + * Cb *= 1.77200; + * Cg = 0.19421 * Cb + .50937 * Cr; + * R = Y + Cr; + * G = Y - Cg; + * B = Y + Cb; + * + * => + * Cg = (50 * Cb + 130 * Cr + 128) >> 8; + */ + +static void initcol(PREC q[][64]) +{ + scaleidctqtab(q[1], IFIX(1.77200)); + scaleidctqtab(q[2], IFIX(1.40200)); +} + +/* This is optimized for the stupid sun SUNWspro compiler. */ +#define STORECLAMP(a,x) \ +( \ + (a) = (x), \ + (unsigned int)(x) >= 256 ? \ + ((a) = (x) < 0 ? 0 : 255) \ + : \ + 0 \ +) + +#define CLAMP(x) ((unsigned int)(x) >= 256 ? ((x) < 0 ? 0 : 255) : (x)) + +#ifdef ROUND + +#define CBCRCG(yin, xin) \ +( \ + cb = outc[0 +yin*8+xin], \ + cr = outc[64+yin*8+xin], \ + cg = (50 * cb + 130 * cr + 128) >> 8 \ +) + +#else + +#define CBCRCG(yin, xin) \ +( \ + cb = outc[0 +yin*8+xin], \ + cr = outc[64+yin*8+xin], \ + cg = (3 * cb + 8 * cr) >> 4 \ +) + +#endif + +#ifdef __LITTLE_ENDIAN +#define PIC(yin, xin, p, xout) \ +( \ + y = outy[(yin) * 8 + xin], \ + STORECLAMP(p[(xout) * 3 + 2], y + cr), \ + STORECLAMP(p[(xout) * 3 + 1], y - cg), \ + STORECLAMP(p[(xout) * 3 + 0], y + cb) \ +) +#else +#define PIC(yin, xin, p, xout) \ +( \ + y = outy[(yin) * 8 + xin], \ + STORECLAMP(p[(xout) * 3 + 0], y + cr), \ + STORECLAMP(p[(xout) * 3 + 1], y - cg), \ + STORECLAMP(p[(xout) * 3 + 2], y + cb) \ +) +#endif + +#ifdef __LITTLE_ENDIAN +#define PIC_16(yin, xin, p, xout, add) \ +( \ + y = outy[(yin) * 8 + xin], \ + y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 8) | \ + ((CLAMP(y - cg + add ) & 0xfc) << 3) | \ + ((CLAMP(y + cb + add*2+1) ) >> 3), \ + p[(xout) * 2 + 0] = y & 0xff, \ + p[(xout) * 2 + 1] = y >> 8 \ +) +#else +#ifdef CONFIG_PPC +#define PIC_16(yin, xin, p, xout, add) \ +( \ + y = outy[(yin) * 8 + xin], \ + y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 7) | \ + ((CLAMP(y - cg + add*2+1) & 0xf8) << 2) | \ + ((CLAMP(y + cb + add*2+1) ) >> 3), \ + p[(xout) * 2 + 0] = y >> 8, \ + p[(xout) * 2 + 1] = y & 0xff \ +) +#else +#define PIC_16(yin, xin, p, xout, add) \ +( \ + y = outy[(yin) * 8 + xin], \ + y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 8) | \ + ((CLAMP(y - cg + add ) & 0xfc) << 3) | \ + ((CLAMP(y + cb + add*2+1) ) >> 3), \ + p[(xout) * 2 + 0] = y >> 8, \ + p[(xout) * 2 + 1] = y & 0xff \ +) +#endif +#endif + +#define PIC_32(yin, xin, p, xout) \ +( \ + y = outy[(yin) * 8 + xin], \ + STORECLAMP(p[(xout) * 4 + 0], y + cr), \ + STORECLAMP(p[(xout) * 4 + 1], y - cg), \ + STORECLAMP(p[(xout) * 4 + 2], y + cb), \ + p[(xout) * 4 + 3] = 0 \ +) + +#define PIC221111(xin) \ +( \ + CBCRCG(0, xin), \ + PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0), \ + PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1), \ + PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0), \ + PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1) \ +) + +#define PIC221111_16(xin) \ +( \ + CBCRCG(0, xin), \ + PIC_16(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0, 3), \ + PIC_16(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1, 0), \ + PIC_16(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0, 1), \ + PIC_16(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1, 2) \ +) + +#define PIC221111_32(xin) \ +( \ + CBCRCG(0, xin), \ + PIC_32(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0), \ + PIC_32(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1), \ + PIC_32(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0), \ + PIC_32(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1) \ +) + +static void col221111(int *out, unsigned char *pic, int width) +{ + int i, j, k; + unsigned char *pic0, *pic1; + int *outy, *outc; + int cr, cg, cb, y; + + pic0 = pic; + pic1 = pic + width; + outy = out; + outc = out + 64 * 4; + for (i = 2; i > 0; i--) { + for (j = 4; j > 0; j--) { + for (k = 0; k < 8; k++) { + PIC221111(k); + } + outc += 8; + outy += 16; + pic0 += 2 * width; + pic1 += 2 * width; + } + outy += 64 * 2 - 16 * 4; + } +} + +static void col221111_16(int *out, unsigned char *pic, int width) +{ + int i, j, k; + unsigned char *pic0, *pic1; + int *outy, *outc; + int cr, cg, cb, y; + + pic0 = pic; + pic1 = pic + width; + outy = out; + outc = out + 64 * 4; + for (i = 2; i > 0; i--) { + for (j = 4; j > 0; j--) { + for (k = 0; k < 8; k++) { + PIC221111_16(k); + } + outc += 8; + outy += 16; + pic0 += 2 * width; + pic1 += 2 * width; + } + outy += 64 * 2 - 16 * 4; + } +} + +static void col221111_32(int *out, unsigned char *pic, int width) +{ + int i, j, k; + unsigned char *pic0, *pic1; + int *outy, *outc; + int cr, cg, cb, y; + + pic0 = pic; + pic1 = pic + width; + outy = out; + outc = out + 64 * 4; + for (i = 2; i > 0; i--) { + for (j = 4; j > 0; j--) { + for (k = 0; k < 8; k++) { + PIC221111_32(k); + } + outc += 8; + outy += 16; + pic0 += 2 * width; + pic1 += 2 * width; + } + outy += 64 * 2 - 16 * 4; + } +} diff --git a/bios/seabios/src/jpeg.h b/bios/seabios/src/jpeg.h new file mode 100644 index 0000000..2d08f45 --- /dev/null +++ b/bios/seabios/src/jpeg.h @@ -0,0 +1,11 @@ +#ifndef __JPEG_H +#define __JPEG_H + +struct jpeg_decdata; +struct jpeg_decdata *jpeg_alloc(void); +int jpeg_decode(struct jpeg_decdata *jpeg, unsigned char *buf); +void jpeg_get_size(struct jpeg_decdata *jpeg, int *width, int *height); +int jpeg_show(struct jpeg_decdata *jpeg, unsigned char *pic, int width + , int height, int depth, int bytes_per_line_dest); + +#endif diff --git a/bios/seabios/src/kbd.c b/bios/seabios/src/kbd.c new file mode 100644 index 0000000..1977c5d --- /dev/null +++ b/bios/seabios/src/kbd.c @@ -0,0 +1,573 @@ +// 16bit code to handle keyboard requests. +// +// Copyright (C) 2008 Kevin O'Connor +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "biosvar.h" // GET_BDA +#include "util.h" // debug_enter +#include "config.h" // CONFIG_* +#include "bregs.h" // struct bregs +#include "ps2port.h" // ps2_kbd_command +#include "usb-hid.h" // usb_kbd_command + +// Bit definitions for BDA kbd_flag[012] +#define KF0_RSHIFT (1<<0) +#define KF0_LSHIFT (1<<1) +#define KF0_CTRLACTIVE (1<<2) +#define KF0_ALTACTIVE (1<<3) +#define KF0_SCROLLACTIVE (1<<4) +#define KF0_NUMACTIVE (1<<5) +#define KF0_CAPSACTIVE (1<<6) + +#define KF1_LCTRL (1<<0) +#define KF1_LALT (1<<1) +#define KF1_PAUSEACTIVE (1<<3) +#define KF1_SCROLL (1<<4) +#define KF1_NUM (1<<5) +#define KF1_CAPS (1<<6) + +#define KF2_LAST_E1 (1<<0) +#define KF2_LAST_E0 (1<<1) +#define KF2_RCTRL (1<<2) +#define KF2_RALT (1<<3) +#define KF2_101KBD (1<<4) + +void +kbd_setup(void) +{ + dprintf(3, "init keyboard\n"); + u16 x = offsetof(struct bios_data_area_s, kbd_buf); + SET_BDA(kbd_flag2, KF2_101KBD); + SET_BDA(kbd_buf_head, x); + SET_BDA(kbd_buf_tail, x); + SET_BDA(kbd_buf_start_offset, x); + + SET_BDA(kbd_buf_end_offset + , x + FIELD_SIZEOF(struct bios_data_area_s, kbd_buf)); +} + +static u8 +enqueue_key(u8 scan_code, u8 ascii_code) +{ + u16 buffer_start = GET_BDA(kbd_buf_start_offset); + u16 buffer_end = GET_BDA(kbd_buf_end_offset); + + u16 buffer_head = GET_BDA(kbd_buf_head); + u16 buffer_tail = GET_BDA(kbd_buf_tail); + + u16 temp_tail = buffer_tail; + buffer_tail += 2; + if (buffer_tail >= buffer_end) + buffer_tail = buffer_start; + + if (buffer_tail == buffer_head) + return 0; + + SET_FARVAR(SEG_BDA, *(u8*)(temp_tail+0), ascii_code); + SET_FARVAR(SEG_BDA, *(u8*)(temp_tail+1), scan_code); + SET_BDA(kbd_buf_tail, buffer_tail); + return 1; +} + +static void +dequeue_key(struct bregs *regs, int incr, int extended) +{ + yield(); + u16 buffer_head; + u16 buffer_tail; + for (;;) { + buffer_head = GET_BDA(kbd_buf_head); + buffer_tail = GET_BDA(kbd_buf_tail); + + if (buffer_head != buffer_tail) + break; + if (!incr) { + regs->flags |= F_ZF; + return; + } + wait_irq(); + } + + u8 ascii_code = GET_FARVAR(SEG_BDA, *(u8*)(buffer_head+0)); + u8 scan_code = GET_FARVAR(SEG_BDA, *(u8*)(buffer_head+1)); + if ((ascii_code == 0xF0 && scan_code != 0) + || (ascii_code == 0xE0 && !extended)) + ascii_code = 0; + regs->ax = (scan_code << 8) | ascii_code; + + if (!incr) { + regs->flags &= ~F_ZF; + return; + } + u16 buffer_start = GET_BDA(kbd_buf_start_offset); + u16 buffer_end = GET_BDA(kbd_buf_end_offset); + + buffer_head += 2; + if (buffer_head >= buffer_end) + buffer_head = buffer_start; + SET_BDA(kbd_buf_head, buffer_head); +} + +static inline int +kbd_command(int command, u8 *param) +{ + if (usb_kbd_active()) + return usb_kbd_command(command, param); + return ps2_kbd_command(command, param); +} + +// read keyboard input +static void +handle_1600(struct bregs *regs) +{ + dequeue_key(regs, 1, 0); +} + +// check keyboard status +static void +handle_1601(struct bregs *regs) +{ + dequeue_key(regs, 0, 0); +} + +// get shift flag status +static void +handle_1602(struct bregs *regs) +{ + yield(); + regs->al = GET_BDA(kbd_flag0); +} + +// store key-stroke into buffer +static void +handle_1605(struct bregs *regs) +{ + regs->al = !enqueue_key(regs->ch, regs->cl); +} + +// GET KEYBOARD FUNCTIONALITY +static void +handle_1609(struct bregs *regs) +{ + // bit Bochs Description + // 7 0 reserved + // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support) + // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support) + // 4 1 INT 16/AH=0Ah supported + // 3 0 INT 16/AX=0306h supported + // 2 0 INT 16/AX=0305h supported + // 1 0 INT 16/AX=0304h supported + // 0 0 INT 16/AX=0300h supported + // + regs->al = 0x30; +} + +// GET KEYBOARD ID +static void +handle_160a(struct bregs *regs) +{ + u8 param[2]; + int ret = kbd_command(ATKBD_CMD_GETID, param); + if (ret) { + regs->bx = 0; + return; + } + regs->bx = (param[1] << 8) | param[0]; +} + +// read MF-II keyboard input +static void +handle_1610(struct bregs *regs) +{ + dequeue_key(regs, 1, 1); +} + +// check MF-II keyboard status +static void +handle_1611(struct bregs *regs) +{ + dequeue_key(regs, 0, 1); +} + +// get extended keyboard status +static void +handle_1612(struct bregs *regs) +{ + yield(); + regs->al = GET_BDA(kbd_flag0); + regs->ah = ((GET_BDA(kbd_flag1) & ~(KF2_RCTRL|KF2_RALT)) + | (GET_BDA(kbd_flag2) & (KF2_RCTRL|KF2_RALT))); + //BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX); +} + +static void +handle_166f(struct bregs *regs) +{ + if (regs->al == 0x08) + // unsupported, aka normal keyboard + regs->ah = 2; +} + +// keyboard capability check called by DOS 5.0+ keyb +static void +handle_1692(struct bregs *regs) +{ + // function int16 ah=0x10-0x12 supported + regs->ah = 0x80; +} + +// 122 keys capability check called by DOS 5.0+ keyb +static void +handle_16a2(struct bregs *regs) +{ + // don't change AH : function int16 ah=0x20-0x22 NOT supported +} + +static void +handle_16XX(struct bregs *regs) +{ + warn_unimplemented(regs); +} + +static void +set_leds(void) +{ + u8 shift_flags = (GET_BDA(kbd_flag0) >> 4) & 0x07; + u8 kbd_led = GET_BDA(kbd_led); + u8 led_flags = kbd_led & 0x07; + if (shift_flags == led_flags) + return; + + int ret = kbd_command(ATKBD_CMD_SETLEDS, &shift_flags); + if (ret) + // Error + return; + kbd_led = (kbd_led & ~0x07) | shift_flags; + SET_BDA(kbd_led, kbd_led); +} + +// INT 16h Keyboard Service Entry Point +void VISIBLE16 +handle_16(struct bregs *regs) +{ + debug_enter(regs, DEBUG_HDL_16); + if (! CONFIG_KEYBOARD) + return; + + // XXX - set_leds should be called from irq handler + set_leds(); + + switch (regs->ah) { + case 0x00: handle_1600(regs); break; + case 0x01: handle_1601(regs); break; + case 0x02: handle_1602(regs); break; + case 0x05: handle_1605(regs); break; + case 0x09: handle_1609(regs); break; + case 0x0a: handle_160a(regs); break; + case 0x10: handle_1610(regs); break; + case 0x11: handle_1611(regs); break; + case 0x12: handle_1612(regs); break; + case 0x92: handle_1692(regs); break; + case 0xa2: handle_16a2(regs); break; + case 0x6f: handle_166f(regs); break; + default: handle_16XX(regs); break; + } +} + +#define none 0 +#define MNUM KF0_NUMACTIVE +#define MCAP KF0_CAPSACTIVE + +static struct scaninfo { + u16 normal; + u16 shift; + u16 control; + u16 alt; + u8 lock_flags; +} scan_to_scanascii[] VAR16 = { + { none, none, none, none, none }, + { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */ + { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */ + { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */ + { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */ + { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */ + { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */ + { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */ + { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */ + { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */ + { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */ + { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */ + { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */ + { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */ + { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */ + { 0x0f09, 0x0f00, none, none, none }, /* tab */ + { 0x1071, 0x1051, 0x1011, 0x1000, MCAP }, /* Q */ + { 0x1177, 0x1157, 0x1117, 0x1100, MCAP }, /* W */ + { 0x1265, 0x1245, 0x1205, 0x1200, MCAP }, /* E */ + { 0x1372, 0x1352, 0x1312, 0x1300, MCAP }, /* R */ + { 0x1474, 0x1454, 0x1414, 0x1400, MCAP }, /* T */ + { 0x1579, 0x1559, 0x1519, 0x1500, MCAP }, /* Y */ + { 0x1675, 0x1655, 0x1615, 0x1600, MCAP }, /* U */ + { 0x1769, 0x1749, 0x1709, 0x1700, MCAP }, /* I */ + { 0x186f, 0x184f, 0x180f, 0x1800, MCAP }, /* O */ + { 0x1970, 0x1950, 0x1910, 0x1900, MCAP }, /* P */ + { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */ + { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */ + { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */ + { none, none, none, none, none }, /* L Ctrl */ + { 0x1e61, 0x1e41, 0x1e01, 0x1e00, MCAP }, /* A */ + { 0x1f73, 0x1f53, 0x1f13, 0x1f00, MCAP }, /* S */ + { 0x2064, 0x2044, 0x2004, 0x2000, MCAP }, /* D */ + { 0x2166, 0x2146, 0x2106, 0x2100, MCAP }, /* F */ + { 0x2267, 0x2247, 0x2207, 0x2200, MCAP }, /* G */ + { 0x2368, 0x2348, 0x2308, 0x2300, MCAP }, /* H */ + { 0x246a, 0x244a, 0x240a, 0x2400, MCAP }, /* J */ + { 0x256b, 0x254b, 0x250b, 0x2500, MCAP }, /* K */ + { 0x266c, 0x264c, 0x260c, 0x2600, MCAP }, /* L */ + { 0x273b, 0x273a, none, none, none }, /* ;: */ + { 0x2827, 0x2822, none, none, none }, /* '" */ + { 0x2960, 0x297e, none, none, none }, /* `~ */ + { none, none, none, none, none }, /* L shift */ + { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */ + { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, MCAP }, /* Z */ + { 0x2d78, 0x2d58, 0x2d18, 0x2d00, MCAP }, /* X */ + { 0x2e63, 0x2e43, 0x2e03, 0x2e00, MCAP }, /* C */ + { 0x2f76, 0x2f56, 0x2f16, 0x2f00, MCAP }, /* V */ + { 0x3062, 0x3042, 0x3002, 0x3000, MCAP }, /* B */ + { 0x316e, 0x314e, 0x310e, 0x3100, MCAP }, /* N */ + { 0x326d, 0x324d, 0x320d, 0x3200, MCAP }, /* M */ + { 0x332c, 0x333c, none, none, none }, /* ,< */ + { 0x342e, 0x343e, none, none, none }, /* .> */ + { 0x352f, 0x353f, none, none, none }, /* /? */ + { none, none, none, none, none }, /* R Shift */ + { 0x372a, 0x372a, none, none, none }, /* * */ + { none, none, none, none, none }, /* L Alt */ + { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */ + { none, none, none, none, none }, /* caps lock */ + { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */ + { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */ + { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */ + { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */ + { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */ + { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */ + { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */ + { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */ + { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */ + { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */ + { none, none, none, none, none }, /* Num Lock */ + { none, none, none, none, none }, /* Scroll Lock */ + { 0x4700, 0x4737, 0x7700, none, MNUM }, /* 7 Home */ + { 0x4800, 0x4838, none, none, MNUM }, /* 8 UP */ + { 0x4900, 0x4939, 0x8400, none, MNUM }, /* 9 PgUp */ + { 0x4a2d, 0x4a2d, none, none, none }, /* - */ + { 0x4b00, 0x4b34, 0x7300, none, MNUM }, /* 4 Left */ + { 0x4c00, 0x4c35, none, none, MNUM }, /* 5 */ + { 0x4d00, 0x4d36, 0x7400, none, MNUM }, /* 6 Right */ + { 0x4e2b, 0x4e2b, none, none, none }, /* + */ + { 0x4f00, 0x4f31, 0x7500, none, MNUM }, /* 1 End */ + { 0x5000, 0x5032, none, none, MNUM }, /* 2 Down */ + { 0x5100, 0x5133, 0x7600, none, MNUM }, /* 3 PgDn */ + { 0x5200, 0x5230, none, none, MNUM }, /* 0 Ins */ + { 0x5300, 0x532e, none, none, MNUM }, /* Del */ + { none, none, none, none, none }, + { none, none, none, none, none }, + { 0x565c, 0x567c, none, none, none }, /* \| */ + { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */ + { 0x8600, 0x8800, 0x8a00, 0x8c00, none }, /* F12 */ +}; + +// Handle a scancode read from the ps2 port. Note that "noinline" is +// used to make sure the call to call16_simpint in process_key doesn't +// have the overhead of this function's stack. +static void noinline +__process_key(u8 scancode) +{ + u8 flags0 = GET_BDA(kbd_flag0); + u8 flags1 = GET_BDA(kbd_flag1); + u8 flags2 = GET_BDA(kbd_flag2); + + if (flags2 & KF2_LAST_E1) { + // Part of "pause" key (sequence is e1 1d 45 e1 9d c5) + if ((scancode & ~0x80) == 0x1d) + // Second key of sequence + return; + // Third key of sequence - clear flag. + flags2 &= ~KF2_LAST_E1; + SET_BDA(kbd_flag2, flags2); + + if (scancode == 0xc5) { + // Final key in sequence. + + // XXX - do actual pause. + } + return; + } + + // XXX - PrtScr should cause int 0x05 + // XXX - Ctrl+Break should cause int 0x1B + // XXX - SysReq should cause int 0x15/0x85 + + switch (scancode) { + case 0x00: + dprintf(1, "KBD: int09 handler: AL=0\n"); + return; + + case 0x3a: /* Caps Lock press */ + flags0 ^= KF0_CAPSACTIVE; + flags1 |= KF1_CAPS; + break; + case 0xba: /* Caps Lock release */ + flags1 &= ~KF1_CAPS; + break; + + case 0x2a: /* L Shift press */ + flags0 |= KF0_LSHIFT; + break; + case 0xaa: /* L Shift release */ + flags0 &= ~KF0_LSHIFT; + break; + + case 0x36: /* R Shift press */ + flags0 |= KF0_RSHIFT; + break; + case 0xb6: /* R Shift release */ + flags0 &= ~KF0_RSHIFT; + break; + + case 0x1d: /* Ctrl press */ + flags0 |= KF0_CTRLACTIVE; + if (flags2 & KF2_LAST_E0) + flags2 |= KF2_RCTRL; + else + flags1 |= KF1_LCTRL; + break; + case 0x9d: /* Ctrl release */ + flags0 &= ~KF0_CTRLACTIVE; + if (flags2 & KF2_LAST_E0) + flags2 &= ~KF2_RCTRL; + else + flags1 &= ~KF1_LCTRL; + break; + + case 0x38: /* Alt press */ + flags0 |= KF0_ALTACTIVE; + if (flags2 & KF2_LAST_E0) + flags2 |= KF2_RALT; + else + flags1 |= KF1_LALT; + break; + case 0xb8: /* Alt release */ + flags0 &= ~KF0_ALTACTIVE; + if (flags2 & KF2_LAST_E0) + flags2 &= ~KF2_RALT; + else + flags1 &= ~KF1_LALT; + break; + + case 0x45: /* Num Lock press */ + flags1 |= KF1_NUM; + flags0 ^= KF0_NUMACTIVE; + break; + case 0xc5: /* Num Lock release */ + flags1 &= ~KF1_NUM; + break; + + case 0x46: /* Scroll Lock press */ + flags1 |= KF1_SCROLL; + flags0 ^= KF0_SCROLLACTIVE; + break; + case 0xc6: /* Scroll Lock release */ + flags1 &= ~KF1_SCROLL; + break; + + case 0xe0: + // Extended key + flags2 |= KF2_LAST_E0; + SET_BDA(kbd_flag2, flags2); + return; + case 0xe1: + // Start of pause key sequence + flags2 |= KF2_LAST_E1; + break; + + default: + if (scancode & 0x80) + // toss key releases + break; + if (scancode == 0x53 + && ((flags0 & (KF0_CTRLACTIVE|KF0_ALTACTIVE)) + == (KF0_CTRLACTIVE|KF0_ALTACTIVE))) { + // Ctrl+alt+del - reset machine. + SET_BDA(soft_reset_flag, 0x1234); + reset_vector(); + } + if (scancode >= ARRAY_SIZE(scan_to_scanascii)) { + dprintf(1, "KBD: int09h_handler(): unknown scancode read: 0x%02x!\n" + , scancode); + return; + } + u8 asciicode; + struct scaninfo *info = &scan_to_scanascii[scancode]; + if (flags0 & KF0_ALTACTIVE) { + asciicode = GET_GLOBAL(info->alt); + scancode = GET_GLOBAL(info->alt) >> 8; + } else if (flags0 & KF0_CTRLACTIVE) { + asciicode = GET_GLOBAL(info->control); + scancode = GET_GLOBAL(info->control) >> 8; + } else if (flags2 & KF2_LAST_E0 + && scancode >= 0x47 && scancode <= 0x53) { + /* extended keys handling */ + asciicode = 0xe0; + scancode = GET_GLOBAL(info->normal) >> 8; + } else if (flags0 & (KF0_RSHIFT|KF0_LSHIFT)) { + /* check if lock state should be ignored because a SHIFT + * key is pressed */ + + if (flags0 & GET_GLOBAL(info->lock_flags)) { + asciicode = GET_GLOBAL(info->normal); + scancode = GET_GLOBAL(info->normal) >> 8; + } else { + asciicode = GET_GLOBAL(info->shift); + scancode = GET_GLOBAL(info->shift) >> 8; + } + } else { + /* check if lock is on */ + if (flags0 & GET_GLOBAL(info->lock_flags)) { + asciicode = GET_GLOBAL(info->shift); + scancode = GET_GLOBAL(info->shift) >> 8; + } else { + asciicode = GET_GLOBAL(info->normal); + scancode = GET_GLOBAL(info->normal) >> 8; + } + } + if (scancode==0 && asciicode==0) + dprintf(1, "KBD: scancode & asciicode are zero?\n"); + enqueue_key(scancode, asciicode); + break; + } + flags2 &= ~KF2_LAST_E0; + + SET_BDA(kbd_flag0, flags0); + SET_BDA(kbd_flag1, flags1); + SET_BDA(kbd_flag2, flags2); +} + +void +process_key(u8 key) +{ + if (!CONFIG_KEYBOARD) + return; + + if (CONFIG_KBD_CALL_INT15_4F) { + // allow for keyboard intercept + u32 eax = (0x4f << 8) | key; + u32 flags; + call16_simpint(0x15, &eax, &flags); + if (!(flags & F_CF)) + return; + key = eax; + } + __process_key(key); +} diff --git a/bios/seabios/src/lzmadecode.c b/bios/seabios/src/lzmadecode.c new file mode 100644 index 0000000..65819b5 --- /dev/null +++ b/bios/seabios/src/lzmadecode.c @@ -0,0 +1,398 @@ +/* + LzmaDecode.c + LZMA Decoder (optimized for Speed version) + + LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01) + http://www.7-zip.org/ + + LZMA SDK is licensed under two licenses: + 1) GNU Lesser General Public License (GNU LGPL) + 2) Common Public License (CPL) + It means that you can select one of these two licenses and + follow rules of that license. + + SPECIAL EXCEPTION: + Igor Pavlov, as the author of this Code, expressly permits you to + statically or dynamically link your Code (or bind by name) to the + interfaces of this file without subjecting your linked Code to the + terms of the CPL or GNU LGPL. Any modifications or additions + to this file, however, are subject to the LGPL or CPL terms. +*/ + +#include "lzmadecode.h" + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +#define RC_READ_BYTE (*Buffer++) + +#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \ + { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }} + + +#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; } + +#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2 + + +#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; } + +#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound) +#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits; +#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits; + +#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \ + { UpdateBit0(p); mi <<= 1; A0; } else \ + { UpdateBit1(p); mi = (mi + mi) + 1; A1; } + +#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;) + +#define RangeDecoderBitTreeDecode(probs, numLevels, res) \ + { int i = numLevels; res = 1; \ + do { CProb *cp = probs + res; RC_GET_BIT(cp, res) } while(--i != 0); \ + res -= (1 << numLevels); } + + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenChoice 0 +#define LenChoice2 (LenChoice + 1) +#define LenLow (LenChoice2 + 1) +#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) +#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + + +#define kNumStates 12 +#define kNumLitStates 7 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 + +#define IsMatch 0 +#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define IsRep0Long (IsRepG2 + kNumStates) +#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) +#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) +#define LenCoder (Align + kAlignTableSize) +#define RepLenCoder (LenCoder + kNumLenProbs) +#define Literal (RepLenCoder + kNumLenProbs) + +#if Literal != LZMA_BASE_SIZE +StopCompilingDueBUG +#endif + +int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size) +{ + unsigned char prop0; + if (size < LZMA_PROPERTIES_SIZE) + return LZMA_RESULT_DATA_ERROR; + prop0 = propsData[0]; + if (prop0 >= (9 * 5 * 5)) + return LZMA_RESULT_DATA_ERROR; + { + for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5)); + for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9); + propsRes->lc = prop0; + /* + unsigned char remainder = (unsigned char)(prop0 / 9); + propsRes->lc = prop0 % 9; + propsRes->pb = remainder / 5; + propsRes->lp = remainder % 5; + */ + } + + return LZMA_RESULT_OK; +} + +#define kLzmaStreamWasFinishedId (-1) + +int LzmaDecode(CLzmaDecoderState *vs, + const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, + unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed) +{ + CProb *p = vs->Probs; + SizeT nowPos = 0; + Byte previousByte = 0; + UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1; + UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1; + int lc = vs->Properties.lc; + + + int state = 0; + UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1; + int len = 0; + const Byte *Buffer; + const Byte *BufferLim; + UInt32 Range; + UInt32 Code; + + *inSizeProcessed = 0; + *outSizeProcessed = 0; + + { + UInt32 i; + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp)); + for (i = 0; i < numProbs; i++) + p[i] = kBitModelTotal >> 1; + } + + RC_INIT(inStream, inSize); + + + while(nowPos < outSize) + { + CProb *prob; + UInt32 bound; + int posState = (int)( + (nowPos + ) + & posStateMask); + + prob = p + IsMatch + (state << kNumPosBitsMax) + posState; + IfBit0(prob) + { + int symbol = 1; + UpdateBit0(prob) + prob = p + Literal + (LZMA_LIT_SIZE * + ((( + (nowPos + ) + & literalPosMask) << lc) + (previousByte >> (8 - lc)))); + + if (state >= kNumLitStates) + { + int matchByte; + matchByte = outStream[nowPos - rep0]; + do + { + int bit; + CProb *probLit; + matchByte <<= 1; + bit = (matchByte & 0x100); + probLit = prob + 0x100 + bit + symbol; + RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break) + } + while (symbol < 0x100); + } + while (symbol < 0x100) + { + CProb *probLit = prob + symbol; + RC_GET_BIT(probLit, symbol) + } + previousByte = (Byte)symbol; + + outStream[nowPos++] = previousByte; + if (state < 4) state = 0; + else if (state < 10) state -= 3; + else state -= 6; + } + else + { + UpdateBit1(prob); + prob = p + IsRep + state; + IfBit0(prob) + { + UpdateBit0(prob); + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + state = state < kNumLitStates ? 0 : 3; + prob = p + LenCoder; + } + else + { + UpdateBit1(prob); + prob = p + IsRepG0 + state; + IfBit0(prob) + { + UpdateBit0(prob); + prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState; + IfBit0(prob) + { + UpdateBit0(prob); + + if (nowPos == 0) + return LZMA_RESULT_DATA_ERROR; + + state = state < kNumLitStates ? 9 : 11; + previousByte = outStream[nowPos - rep0]; + outStream[nowPos++] = previousByte; + + continue; + } + else + { + UpdateBit1(prob); + } + } + else + { + UInt32 distance; + UpdateBit1(prob); + prob = p + IsRepG1 + state; + IfBit0(prob) + { + UpdateBit0(prob); + distance = rep1; + } + else + { + UpdateBit1(prob); + prob = p + IsRepG2 + state; + IfBit0(prob) + { + UpdateBit0(prob); + distance = rep2; + } + else + { + UpdateBit1(prob); + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = state < kNumLitStates ? 8 : 11; + prob = p + RepLenCoder; + } + { + int numBits, offset; + CProb *probLen = prob + LenChoice; + IfBit0(probLen) + { + UpdateBit0(probLen); + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + numBits = kLenNumLowBits; + } + else + { + UpdateBit1(probLen); + probLen = prob + LenChoice2; + IfBit0(probLen) + { + UpdateBit0(probLen); + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + numBits = kLenNumMidBits; + } + else + { + UpdateBit1(probLen); + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + numBits = kLenNumHighBits; + } + } + RangeDecoderBitTreeDecode(probLen, numBits, len); + len += offset; + } + + if (state < 4) + { + int posSlot; + state += kNumLitStates; + prob = p + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits); + RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot); + if (posSlot >= kStartPosModelIndex) + { + int numDirectBits = ((posSlot >> 1) - 1); + rep0 = (2 | ((UInt32)posSlot & 1)); + if (posSlot < kEndPosModelIndex) + { + rep0 <<= numDirectBits; + prob = p + SpecPos + rep0 - posSlot - 1; + } + else + { + numDirectBits -= kNumAlignBits; + do + { + RC_NORMALIZE + Range >>= 1; + rep0 <<= 1; + if (Code >= Range) + { + Code -= Range; + rep0 |= 1; + } + } + while (--numDirectBits != 0); + prob = p + Align; + rep0 <<= kNumAlignBits; + numDirectBits = kNumAlignBits; + } + { + int i = 1; + int mi = 1; + do + { + CProb *prob3 = prob + mi; + RC_GET_BIT2(prob3, mi, ; , rep0 |= i); + i <<= 1; + } + while(--numDirectBits != 0); + } + } + else + rep0 = posSlot; + if (++rep0 == (UInt32)(0)) + { + /* it's for stream version */ + len = kLzmaStreamWasFinishedId; + break; + } + } + + len += kMatchMinLen; + if (rep0 > nowPos) + return LZMA_RESULT_DATA_ERROR; + + + do + { + previousByte = outStream[nowPos - rep0]; + len--; + outStream[nowPos++] = previousByte; + } + while(len != 0 && nowPos < outSize); + } + } + RC_NORMALIZE; + + + *inSizeProcessed = (SizeT)(Buffer - inStream); + *outSizeProcessed = nowPos; + return LZMA_RESULT_OK; +} diff --git a/bios/seabios/src/lzmadecode.h b/bios/seabios/src/lzmadecode.h new file mode 100644 index 0000000..dedde0d --- /dev/null +++ b/bios/seabios/src/lzmadecode.h @@ -0,0 +1,67 @@ +/* + LzmaDecode.h + LZMA Decoder interface + + LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01) + http://www.7-zip.org/ + + LZMA SDK is licensed under two licenses: + 1) GNU Lesser General Public License (GNU LGPL) + 2) Common Public License (CPL) + It means that you can select one of these two licenses and + follow rules of that license. + + SPECIAL EXCEPTION: + Igor Pavlov, as the author of this code, expressly permits you to + statically or dynamically link your code (or bind by name) to the + interfaces of this file without subjecting your linked code to the + terms of the CPL or GNU LGPL. Any modifications or additions + to this file, however, are subject to the LGPL or CPL terms. +*/ + +#ifndef __LZMADECODE_H +#define __LZMADECODE_H + +typedef unsigned char Byte; +typedef unsigned short UInt16; +typedef unsigned int UInt32; +typedef UInt32 SizeT; + +#define CProb UInt16 + +#define LZMA_RESULT_OK 0 +#define LZMA_RESULT_DATA_ERROR 1 + + +#define LZMA_BASE_SIZE 1846 +#define LZMA_LIT_SIZE 768 + +#define LZMA_PROPERTIES_SIZE 5 + +typedef struct _CLzmaProperties +{ + int lc; + int lp; + int pb; +}CLzmaProperties; + +int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size); + +#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp))) + +#define kLzmaNeedInitId (-2) + +typedef struct _CLzmaDecoderState +{ + CLzmaProperties Properties; + CProb *Probs; + + +} CLzmaDecoderState; + + +int LzmaDecode(CLzmaDecoderState *vs, + const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, + unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed); + +#endif diff --git a/bios/seabios/src/memmap.c b/bios/seabios/src/memmap.c new file mode 100644 index 0000000..20ccae0 --- /dev/null +++ b/bios/seabios/src/memmap.c @@ -0,0 +1,141 @@ +// Support for building memory maps suitable for int 15 e820 calls. +// +// Copyright (C) 2008,2009 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "memmap.h" // struct e820entry +#include "util.h" // dprintf.h +#include "biosvar.h" // SET_EBDA + + +/**************************************************************** + * e820 memory map + ****************************************************************/ + +// Remove an entry from the e820_list. +static void +remove_e820(int i) +{ + e820_count--; + memmove(&e820_list[i], &e820_list[i+1] + , sizeof(e820_list[0]) * (e820_count - i)); +} + +// Insert an entry in the e820_list at the given position. +static void +insert_e820(int i, u64 start, u64 size, u32 type) +{ + if (e820_count >= CONFIG_MAX_E820) { + warn_noalloc(); + return; + } + + memmove(&e820_list[i+1], &e820_list[i] + , sizeof(e820_list[0]) * (e820_count - i)); + e820_count++; + struct e820entry *e = &e820_list[i]; + e->start = start; + e->size = size; + e->type = type; +} + +static const char * +e820_type_name(u32 type) +{ + switch (type) { + case E820_RAM: return "RAM"; + case E820_RESERVED: return "RESERVED"; + case E820_ACPI: return "ACPI"; + case E820_NVS: return "NVS"; + case E820_UNUSABLE: return "UNUSABLE"; + case E820_HOLE: return "HOLE"; + default: return "UNKNOWN"; + } +} + +// Show the current e820_list. +static void +dump_map(void) +{ + dprintf(1, "e820 map has %d items:\n", e820_count); + int i; + for (i=0; istart + e->size; + dprintf(1, " %d: %08x%08x - %08x%08x = %d %s\n", i + , (u32)(e->start >> 32), (u32)e->start + , (u32)(e_end >> 32), (u32)e_end + , e->type, e820_type_name(e->type)); + } +} + +// Add a new entry to the list. This scans for overlaps and keeps the +// list sorted. +void +add_e820(u64 start, u64 size, u32 type) +{ + dprintf(8, "Add to e820 map: %08x %08x %d\n", (u32)start, (u32)size, type); + + if (! size) + // Huh? Nothing to do. + return; + + // Find position of new item (splitting existing item if needed). + u64 end = start + size; + int i; + for (i=0; istart + e->size; + if (start > e_end) + continue; + // Found position - check if an existing item needs to be split. + if (start > e->start) { + if (type == e->type) { + // Same type - merge them. + size += start - e->start; + start = e->start; + } else { + // Split existing item. + e->size = start - e->start; + i++; + if (e_end > end) + insert_e820(i, end, e_end - end, e->type); + } + } + break; + } + // Remove/adjust existing items that are overlapping. + while (istart) + // No overlap - done. + break; + u64 e_end = e->start + e->size; + if (end >= e_end) { + // Existing item completely overlapped - remove it. + remove_e820(i); + continue; + } + // Not completely overlapped - adjust its start. + e->start = end; + e->size = e_end - end; + if (type == e->type) { + // Same type - merge them. + size += e->size; + remove_e820(i); + } + break; + } + // Insert new item. + if (type != E820_HOLE) + insert_e820(i, start, size, type); + //dump_map(); +} + +// Report on final memory locations. +void +memmap_finalize(void) +{ + dump_map(); +} diff --git a/bios/seabios/src/memmap.h b/bios/seabios/src/memmap.h new file mode 100644 index 0000000..01c7ddb --- /dev/null +++ b/bios/seabios/src/memmap.h @@ -0,0 +1,32 @@ +#ifndef __E820MAP_H +#define __E820MAP_H + +#include "types.h" // u64 + +#define E820_RAM 1 +#define E820_RESERVED 2 +#define E820_ACPI 3 +#define E820_NVS 4 +#define E820_UNUSABLE 5 +#define E820_HOLE ((u32)-1) // Useful for removing entries + +struct e820entry { + u64 start; + u64 size; + u32 type; +}; + +void add_e820(u64 start, u64 size, u32 type); +void memmap_finalize(void); + +// A typical OS page size +#define PAGE_SIZE 4096 + +// e820 map storage (defined in system.c) +extern struct e820entry e820_list[]; +extern int e820_count; + +// Space for exported bios tables (defined in misc.c) +extern char BiosTableSpace[]; + +#endif // e820map.h diff --git a/bios/seabios/src/misc.c b/bios/seabios/src/misc.c new file mode 100644 index 0000000..9db49e3 --- /dev/null +++ b/bios/seabios/src/misc.c @@ -0,0 +1,190 @@ +// Code for misc 16bit handlers and variables. +// +// Copyright (C) 2008,2009 Kevin O'Connor +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "bregs.h" // struct bregs +#include "biosvar.h" // GET_BDA +#include "util.h" // debug_enter +#include "pic.h" // enable_hwirq + +// Amount of continuous ram under 4Gig +u32 RamSize VAR16VISIBLE; +// Amount of continuous ram >4Gig +u64 RamSizeOver4G; +// Space for bios tables built an run-time. +char BiosTableSpace[CONFIG_MAX_BIOSTABLE] __aligned(MALLOC_MIN_ALIGN) VAR16VISIBLE; + + +/**************************************************************** + * Misc 16bit ISRs + ****************************************************************/ + +// INT 12h Memory Size Service Entry Point +void VISIBLE16 +handle_12(struct bregs *regs) +{ + debug_enter(regs, DEBUG_HDL_12); + regs->ax = GET_BDA(mem_size_kb); +} + +// INT 11h Equipment List Service Entry Point +void VISIBLE16 +handle_11(struct bregs *regs) +{ + debug_enter(regs, DEBUG_HDL_11); + regs->ax = GET_BDA(equipment_list_flags); +} + +// INT 05h Print Screen Service Entry Point +void VISIBLE16 +handle_05(struct bregs *regs) +{ + debug_enter(regs, DEBUG_HDL_05); +} + +// INT 10h Video Support Service Entry Point +void VISIBLE16 +handle_10(struct bregs *regs) +{ + debug_enter(regs, DEBUG_HDL_10); + // dont do anything, since the VGA BIOS handles int10h requests +} + +// NMI handler +void VISIBLE16 +handle_02(void) +{ + debug_isr(DEBUG_ISR_02); +} + +void +mathcp_setup(void) +{ + dprintf(3, "math cp init\n"); + // 80x87 coprocessor installed + SETBITS_BDA(equipment_list_flags, 0x02); + enable_hwirq(13, FUNC16(entry_75)); +} + +// INT 75 - IRQ13 - MATH COPROCESSOR EXCEPTION +void VISIBLE16 +handle_75(void) +{ + debug_isr(DEBUG_ISR_75); + + // clear irq13 + outb(0, PORT_MATH_CLEAR); + // clear interrupt + eoi_pic2(); + // legacy nmi call + u32 eax=0, flags; + call16_simpint(0x02, &eax, &flags); +} + + +/**************************************************************** + * BIOS_CONFIG_TABLE + ****************************************************************/ + +// DMA channel 3 used by hard disk BIOS +#define CBT_F1_DMA3USED (1<<7) +// 2nd interrupt controller (8259) installed +#define CBT_F1_2NDPIC (1<<6) +// Real-Time Clock installed +#define CBT_F1_RTC (1<<5) +// INT 15/AH=4Fh called upon INT 09h +#define CBT_F1_INT154F (1<<4) +// wait for external event (INT 15/AH=41h) supported +#define CBT_F1_WAITEXT (1<<3) +// extended BIOS area allocated (usually at top of RAM) +#define CBT_F1_EBDA (1<<2) +// bus is Micro Channel instead of ISA +#define CBT_F1_MCA (1<<1) +// system has dual bus (Micro Channel + ISA) +#define CBT_F1_MCAISA (1<<0) + +// INT 16/AH=09h (keyboard functionality) supported +#define CBT_F2_INT1609 (1<<6) + +struct bios_config_table_s BIOS_CONFIG_TABLE VAR16FIXED(0xe6f5) = { + .size = sizeof(BIOS_CONFIG_TABLE) - 2, + .model = CONFIG_MODEL_ID, + .submodel = CONFIG_SUBMODEL_ID, + .biosrev = CONFIG_BIOS_REVISION, + .feature1 = ( + CBT_F1_2NDPIC | CBT_F1_RTC | CBT_F1_EBDA + | (CONFIG_KBD_CALL_INT15_4F ? CBT_F1_INT154F : 0)), + .feature2 = CBT_F2_INT1609, + .feature3 = 0, + .feature4 = 0, + .feature5 = 0, +}; + + +/**************************************************************** + * GDT and IDT tables + ****************************************************************/ + +// Real mode IDT descriptor +struct descloc_s rmode_IDT_info VAR16VISIBLE = { + .length = sizeof(struct rmode_IVT) - 1, + .addr = (u32)MAKE_FLATPTR(SEG_IVT, 0), +}; + +// Dummy IDT that forces a machine shutdown if an irq happens in +// protected mode. +u8 dummy_IDT VAR16VISIBLE; + +// Protected mode IDT descriptor +struct descloc_s pmode_IDT_info VAR16VISIBLE = { + .length = sizeof(dummy_IDT) - 1, + .addr = (u32)MAKE_FLATPTR(SEG_BIOS, &dummy_IDT), +}; + +// GDT +u64 rombios32_gdt[] VAR16VISIBLE __aligned(8) = { + // First entry can't be used. + 0x0000000000000000LL, + // 32 bit flat code segment (SEG32_MODE32_CS) + GDT_GRANLIMIT(0xffffffff) | GDT_CODE | GDT_B, + // 32 bit flat data segment (SEG32_MODE32_DS) + GDT_GRANLIMIT(0xffffffff) | GDT_DATA | GDT_B, + // 16 bit code segment base=0xf0000 limit=0xffff (SEG32_MODE16_CS) + GDT_LIMIT(BUILD_BIOS_SIZE-1) | GDT_CODE | GDT_BASE(BUILD_BIOS_ADDR), + // 16 bit data segment base=0x0 limit=0xffff (SEG32_MODE16_DS) + GDT_LIMIT(0x0ffff) | GDT_DATA, + // 16 bit code segment base=0xf0000 limit=0xffffffff (SEG32_MODE16BIG_CS) + GDT_GRANLIMIT(0xffffffff) | GDT_CODE | GDT_BASE(BUILD_BIOS_ADDR), + // 16 bit data segment base=0 limit=0xffffffff (SEG32_MODE16BIG_DS) + GDT_GRANLIMIT(0xffffffff) | GDT_DATA, +}; + +// GDT descriptor +struct descloc_s rombios32_gdt_48 VAR16VISIBLE = { + .length = sizeof(rombios32_gdt) - 1, + .addr = (u32)MAKE_FLATPTR(SEG_BIOS, rombios32_gdt), +}; + + +/**************************************************************** + * Misc fixed vars + ****************************************************************/ + +char BiosCopyright[] VAR16FIXED(0xff00) = + "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."; + +// BIOS build date +char BiosDate[] VAR16FIXED(0xfff5) = "06/23/99"; + +u8 BiosModelId VAR16FIXED(0xfffe) = CONFIG_MODEL_ID; + +u8 BiosChecksum VAR16FIXED(0xffff); + +// XXX - Initial Interrupt Vector Offsets Loaded by POST +u8 InitVectors[13] VAR16FIXED(0xfef3); + +// XXX - INT 1D - SYSTEM DATA - VIDEO PARAMETER TABLES +u8 VideoParams[88] VAR16FIXED(0xf0a4); diff --git a/bios/seabios/src/mouse.c b/bios/seabios/src/mouse.c new file mode 100644 index 0000000..e26cf69 --- /dev/null +++ b/bios/seabios/src/mouse.c @@ -0,0 +1,326 @@ +// 16bit code to handle mouse events. +// +// Copyright (C) 2008 Kevin O'Connor +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "biosvar.h" // GET_EBDA +#include "util.h" // debug_isr +#include "pic.h" // eoi_pic2 +#include "bregs.h" // struct bregs +#include "ps2port.h" // ps2_mouse_command +#include "usb-hid.h" // usb_mouse_command + +void +mouse_setup(void) +{ + if (! CONFIG_MOUSE) + return; + dprintf(3, "init mouse\n"); + // pointing device installed + SETBITS_BDA(equipment_list_flags, 0x04); +} + +static inline int +mouse_command(int command, u8 *param) +{ + if (usb_mouse_active()) + return usb_mouse_command(command, param); + return ps2_mouse_command(command, param); +} + +#define RET_SUCCESS 0x00 +#define RET_EINVFUNCTION 0x01 +#define RET_EINVINPUT 0x02 +#define RET_EINTERFACE 0x03 +#define RET_ENEEDRESEND 0x04 +#define RET_ENOHANDLER 0x05 + +// Disable Mouse +static void +mouse_15c20000(struct bregs *regs) +{ + int ret = mouse_command(PSMOUSE_CMD_DISABLE, NULL); + if (ret) + set_code_invalid(regs, RET_ENEEDRESEND); + else + set_code_success(regs); +} + +// Enable Mouse +static void +mouse_15c20001(struct bregs *regs) +{ + u8 mouse_flags_2 = GET_EBDA(mouse_flag2); + if ((mouse_flags_2 & 0x80) == 0) { + set_code_invalid(regs, RET_ENOHANDLER); + return; + } + + int ret = mouse_command(PSMOUSE_CMD_ENABLE, NULL); + if (ret) + set_code_invalid(regs, RET_ENEEDRESEND); + else + set_code_success(regs); +} + +static void +mouse_15c200XX(struct bregs *regs) +{ + set_code_unimplemented(regs, RET_EINVFUNCTION); +} + +// Disable/Enable Mouse +static void +mouse_15c200(struct bregs *regs) +{ + switch (regs->bh) { + case 0x00: mouse_15c20000(regs); break; + case 0x01: mouse_15c20001(regs); break; + default: mouse_15c200XX(regs); break; + } +} + +// Reset Mouse +static void +mouse_15c201(struct bregs *regs) +{ + u8 param[2]; + int ret = mouse_command(PSMOUSE_CMD_RESET_BAT, param); + if (ret) { + set_code_invalid(regs, RET_ENEEDRESEND); + return; + } + regs->bl = param[0]; + regs->bh = param[1]; + set_code_success(regs); +} + +// Set Sample Rate +static void +mouse_15c202(struct bregs *regs) +{ + static u8 VAR16 sample_rates[7] = {10, 20, 40, 60, 80, 100, 200}; + if (regs->bh >= ARRAY_SIZE(sample_rates)) { + set_code_invalid(regs, RET_EINVINPUT); + return; + } + u8 mouse_data1 = GET_GLOBAL(sample_rates[regs->bh]); + int ret = mouse_command(PSMOUSE_CMD_SETRATE, &mouse_data1); + if (ret) + set_code_invalid(regs, RET_ENEEDRESEND); + else + set_code_success(regs); +} + +// Set Resolution +static void +mouse_15c203(struct bregs *regs) +{ + // BH: + // 0 = 25 dpi, 1 count per millimeter + // 1 = 50 dpi, 2 counts per millimeter + // 2 = 100 dpi, 4 counts per millimeter + // 3 = 200 dpi, 8 counts per millimeter + if (regs->bh >= 4) { + set_code_invalid(regs, RET_EINVINPUT); + return; + } + u8 param = regs->bh; + int ret = mouse_command(PSMOUSE_CMD_SETRES, ¶m); + if (ret) + set_code_invalid(regs, RET_ENEEDRESEND); + else + set_code_success(regs); +} + +// Get Device ID +static void +mouse_15c204(struct bregs *regs) +{ + u8 param[2]; + int ret = mouse_command(PSMOUSE_CMD_GETID, param); + if (ret) { + set_code_invalid(regs, RET_ENEEDRESEND); + return; + } + regs->bh = param[0]; + set_code_success(regs); +} + +// Initialize Mouse +static void +mouse_15c205(struct bregs *regs) +{ + if (regs->bh != 3) { + set_code_invalid(regs, RET_EINTERFACE); + return; + } + u16 ebda_seg = get_ebda_seg(); + SET_EBDA2(ebda_seg, mouse_flag1, 0x00); + SET_EBDA2(ebda_seg, mouse_flag2, regs->bh); + + // Reset Mouse + mouse_15c201(regs); +} + +// Return Status +static void +mouse_15c20600(struct bregs *regs) +{ + u8 param[3]; + int ret = mouse_command(PSMOUSE_CMD_GETINFO, param); + if (ret) { + set_code_invalid(regs, RET_ENEEDRESEND); + return; + } + regs->bl = param[0]; + regs->cl = param[1]; + regs->dl = param[2]; + set_code_success(regs); +} + +// Set Scaling Factor to 1:1 +static void +mouse_15c20601(struct bregs *regs) +{ + int ret = mouse_command(PSMOUSE_CMD_SETSCALE11, NULL); + if (ret) + set_code_invalid(regs, RET_ENEEDRESEND); + else + set_code_success(regs); +} + +// Set Scaling Factor to 2:1 +static void +mouse_15c20602(struct bregs *regs) +{ + int ret = mouse_command(PSMOUSE_CMD_SETSCALE21, NULL); + if (ret) + set_code_invalid(regs, RET_ENEEDRESEND); + else + set_code_success(regs); +} + +static void +mouse_15c206XX(struct bregs *regs) +{ + set_code_unimplemented(regs, RET_EINVFUNCTION); +} + +// Return Status & Set Scaling Factor... +static void +mouse_15c206(struct bregs *regs) +{ + switch (regs->bh) { + case 0x00: mouse_15c20600(regs); break; + case 0x01: mouse_15c20601(regs); break; + case 0x02: mouse_15c20602(regs); break; + default: mouse_15c206XX(regs); break; + } +} + +// Set Mouse Handler Address +static void +mouse_15c207(struct bregs *regs) +{ + struct segoff_s farptr = SEGOFF(regs->es, regs->bx); + u16 ebda_seg = get_ebda_seg(); + u8 mouse_flags_2 = GET_EBDA2(ebda_seg, mouse_flag2); + if (! farptr.segoff) { + /* remove handler */ + if ((mouse_flags_2 & 0x80) != 0) { + mouse_flags_2 &= ~0x80; + mouse_command(PSMOUSE_CMD_DISABLE, NULL); + } + } else { + /* install handler */ + mouse_flags_2 |= 0x80; + } + SET_EBDA2(ebda_seg, mouse_flag2, mouse_flags_2); + SET_EBDA2(ebda_seg, far_call_pointer, farptr); + set_code_success(regs); +} + +static void +mouse_15c2XX(struct bregs *regs) +{ + set_code_unimplemented(regs, RET_EINVFUNCTION); +} + +void +handle_15c2(struct bregs *regs) +{ + //debug_stub(regs); + + if (! CONFIG_MOUSE) { + set_code_invalid(regs, RET_EUNSUPPORTED); + return; + } + + switch (regs->al) { + case 0x00: mouse_15c200(regs); break; + case 0x01: mouse_15c201(regs); break; + case 0x02: mouse_15c202(regs); break; + case 0x03: mouse_15c203(regs); break; + case 0x04: mouse_15c204(regs); break; + case 0x05: mouse_15c205(regs); break; + case 0x06: mouse_15c206(regs); break; + case 0x07: mouse_15c207(regs); break; + default: mouse_15c2XX(regs); break; + } +} + +void noinline +process_mouse(u8 data) +{ + if (!CONFIG_MOUSE) + return; + + u16 ebda_seg = get_ebda_seg(); + u8 mouse_flags_1 = GET_EBDA2(ebda_seg, mouse_flag1); + u8 mouse_flags_2 = GET_EBDA2(ebda_seg, mouse_flag2); + + if (! (mouse_flags_2 & 0x80)) + // far call handler not installed + return; + + u8 package_count = mouse_flags_2 & 0x07; + u8 index = mouse_flags_1 & 0x07; + SET_EBDA2(ebda_seg, mouse_data[index], data); + + if ((index+1) < package_count) { + mouse_flags_1++; + SET_EBDA2(ebda_seg, mouse_flag1, mouse_flags_1); + return; + } + + u16 status = GET_EBDA2(ebda_seg, mouse_data[0]); + u16 X = GET_EBDA2(ebda_seg, mouse_data[1]); + u16 Y = GET_EBDA2(ebda_seg, mouse_data[2]); + SET_EBDA2(ebda_seg, mouse_flag1, 0); + + struct segoff_s func = GET_EBDA2(ebda_seg, far_call_pointer); + dprintf(16, "mouse farcall s=%04x x=%04x y=%04x func=%04x:%04x\n" + , status, X, Y, func.seg, func.offset); + + asm volatile( + "pushl %%ebp\n" + "sti\n" + + "pushl %0\n" + "pushw %w1\n" // status + "pushw %w2\n" // X + "pushw %w3\n" // Y + "pushw $0\n" // Z + "lcallw *8(%%esp)\n" + "addl $12, %%esp\n" + + "cli\n" + "cld\n" + "popl %%ebp" + : "+a"(func.segoff), "+c"(status), "+d"(X), "+b"(Y) + : + : "edi", "esi", "cc", "memory"); +} diff --git a/bios/seabios/src/mptable.c b/bios/seabios/src/mptable.c new file mode 100644 index 0000000..3100c9a --- /dev/null +++ b/bios/seabios/src/mptable.c @@ -0,0 +1,208 @@ +// MPTable generation (on emulators) +// +// Copyright (C) 2008-2010 Kevin O'Connor +// Copyright (C) 2006 Fabrice Bellard +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // dprintf +#include "config.h" // CONFIG_* +#include "mptable.h" // MPTABLE_SIGNATURE +#include "paravirt.h" // qemu_cfg_irq0_override +#include "pci.h" +#include "pci_regs.h" + +void +mptable_init(void) +{ + if (! CONFIG_MPTABLE) + return; + + dprintf(3, "init MPTable\n"); + + // Config structure in temp area. + struct mptable_config_s *config = malloc_tmp(32*1024); + if (!config) { + warn_noalloc(); + return; + } + memset(config, 0, sizeof(*config)); + config->signature = MPCONFIG_SIGNATURE; + config->spec = 4; + memcpy(config->oemid, CONFIG_CPUNAME8, sizeof(config->oemid)); + memcpy(config->productid, "0.1 ", sizeof(config->productid)); + config->lapic = BUILD_APIC_ADDR; + + // Detect cpu info + u32 cpuid_signature, ebx, ecx, cpuid_features; + cpuid(1, &cpuid_signature, &ebx, &ecx, &cpuid_features); + if (! cpuid_signature) { + // Use default values. + cpuid_signature = 0x600; + cpuid_features = 0x201; + } + int pkgcpus = 1; + if (cpuid_features & (1 << 28)) { + /* Only populate the MPS tables with the first logical CPU in + each package */ + pkgcpus = (ebx >> 16) & 0xff; + pkgcpus = 1 << (__fls(pkgcpus - 1) + 1); /* round up to power of 2 */ + } + u8 apic_version = readl((u8*)BUILD_APIC_ADDR + 0x30) & 0xff; + + // CPU definitions. + struct mpt_cpu *cpus = (void*)&config[1], *cpu = cpus; + int i; + for (i = 0; i < MaxCountCPUs; i+=pkgcpus) { + memset(cpu, 0, sizeof(*cpu)); + cpu->type = MPT_TYPE_CPU; + cpu->apicid = i; + cpu->apicver = apic_version; + /* cpu flags: enabled, bootstrap cpu */ + cpu->cpuflag = ((icpusignature = cpuid_signature; + cpu->featureflag = cpuid_features; + cpu++; + } + int entrycount = cpu - cpus; + + // PCI buses + struct mpt_bus *buses = (void*)cpu, *bus = buses; + int lastbus = -1; + struct pci_device *pci; + foreachpci(pci) { + int curbus = pci_bdf_to_bus(pci->bdf); + if (curbus == lastbus) + continue; + lastbus = curbus; + memset(bus, 0, sizeof(*bus)); + bus->type = MPT_TYPE_BUS; + bus->busid = curbus; + memcpy(bus->bustype, "PCI ", sizeof(bus->bustype)); + bus++; + } + + /* isa bus */ + int isabusid; + memset(bus, 0, sizeof(*bus)); + bus->type = MPT_TYPE_BUS; + isabusid = bus->busid = lastbus + 1; + memcpy(bus->bustype, "ISA ", sizeof(bus->bustype)); + bus++; + entrycount += bus - buses; + + /* ioapic */ + u8 ioapic_id = CountCPUs; + struct mpt_ioapic *ioapic = (void*)bus; + memset(ioapic, 0, sizeof(*ioapic)); + ioapic->type = MPT_TYPE_IOAPIC; + ioapic->apicid = ioapic_id; + ioapic->apicver = 0x11; + ioapic->flags = 1; // enable + ioapic->apicaddr = BUILD_IOAPIC_ADDR; + entrycount++; + + /* irqs */ + struct mpt_intsrc *intsrcs = (void*)&ioapic[1], *intsrc = intsrcs; + int dev = -1; + unsigned short mask = 0, pinmask = 0; + + foreachpci(pci) { + u16 bdf = pci->bdf; + int pin = pci_config_readb(bdf, PCI_INTERRUPT_PIN); + int irq = pci_config_readb(bdf, PCI_INTERRUPT_LINE); + if (pin == 0) + continue; + if (dev != pci_bdf_to_busdev(bdf)) { + dev = pci_bdf_to_busdev(bdf); + pinmask = 0; + } + if (pinmask & (1 << pin)) /* pin was seen already */ + continue; + pinmask |= (1 << pin); + mask |= (1 << irq); + memset(intsrc, 0, sizeof(*intsrc)); + intsrc->type = MPT_TYPE_INTSRC; + intsrc->irqtype = 0; /* INT */ + intsrc->irqflag = 1; /* active high */ + intsrc->srcbus = pci_bdf_to_bus(bdf); /* PCI bus */ + intsrc->srcbusirq = (pci_bdf_to_dev(bdf) << 2) | (pin - 1); + intsrc->dstapic = ioapic_id; + intsrc->dstirq = irq; + intsrc++; + } + + for (i = 0; i < 16; i++) { + memset(intsrc, 0, sizeof(*intsrc)); + if (mask & (1 << i)) + continue; + intsrc->type = MPT_TYPE_INTSRC; + intsrc->irqtype = 0; /* INT */ + intsrc->irqflag = 0; /* conform to bus spec */ + intsrc->srcbus = isabusid; /* ISA bus */ + intsrc->srcbusirq = i; + intsrc->dstapic = ioapic_id; + intsrc->dstirq = i; + if (qemu_cfg_irq0_override()) { + /* Destination 2 is covered by irq0->inti2 override (i == + 0). Source IRQ 2 is unused */ + if (i == 0) + intsrc->dstirq = 2; + else if (i == 2) + intsrc--; + } + intsrc++; + } + + /* Local interrupt assignment */ + intsrc->type = MPT_TYPE_LOCAL_INT; + intsrc->irqtype = 3; /* ExtINT */ + intsrc->irqflag = 0; /* PO, EL default */ + intsrc->srcbus = isabusid; /* ISA */ + intsrc->srcbusirq = 0; + intsrc->dstapic = 0; /* BSP == APIC #0 */ + intsrc->dstirq = 0; /* LINTIN0 */ + intsrc++; + + intsrc->type = MPT_TYPE_LOCAL_INT; + intsrc->irqtype = 1; /* NMI */ + intsrc->irqflag = 0; /* PO, EL default */ + intsrc->srcbus = isabusid; /* ISA */ + intsrc->srcbusirq = 0; + intsrc->dstapic = 0; /* BSP == APIC #0 */ + intsrc->dstirq = 1; /* LINTIN1 */ + intsrc++; + entrycount += intsrc - intsrcs; + + // Finalize config structure. + int length = (void*)intsrc - (void*)config; + config->entrycount = entrycount; + config->length = length; + config->checksum -= checksum(config, length); + + // Allocate final memory locations. (In theory the config + // structure can go in high memory, but Linux kernels before + // v2.6.30 crash with that.) + struct mptable_config_s *finalconfig = malloc_fseg(length); + struct mptable_floating_s *floating = malloc_fseg(sizeof(*floating)); + if (!finalconfig || !floating) { + warn_noalloc(); + free(config); + free(finalconfig); + free(floating); + return; + } + memcpy(finalconfig, config, length); + free(config); + + /* floating pointer structure */ + memset(floating, 0, sizeof(*floating)); + floating->signature = MPTABLE_SIGNATURE; + floating->physaddr = (u32)finalconfig; + floating->length = 1; + floating->spec_rev = 4; + floating->checksum -= checksum(floating, sizeof(*floating)); + + dprintf(1, "MP table addr=%p MPC table addr=%p size=%d\n", + floating, finalconfig, length); +} diff --git a/bios/seabios/src/mptable.h b/bios/seabios/src/mptable.h new file mode 100644 index 0000000..c4e3c51 --- /dev/null +++ b/bios/seabios/src/mptable.h @@ -0,0 +1,80 @@ +#ifndef __MPTABLE_H +#define __MPTABLE_H + +#include "types.h" // u32 + +#define MPTABLE_SIGNATURE 0x5f504d5f // "_MP_" + +struct mptable_floating_s { + u32 signature; + u32 physaddr; + u8 length; + u8 spec_rev; + u8 checksum; + u8 feature1; + u8 feature2; + u8 reserved[3]; +}; + +#define MPCONFIG_SIGNATURE 0x504d4350 // "PCMP" + +struct mptable_config_s { + u32 signature; + u16 length; + u8 spec; + u8 checksum; + char oemid[8]; + char productid[12]; + u32 oemptr; + u16 oemsize; + u16 entrycount; + u32 lapic; + u16 exttable_length; + u8 exttable_checksum; + u8 reserved; +} PACKED; + +#define MPT_TYPE_CPU 0 +#define MPT_TYPE_BUS 1 +#define MPT_TYPE_IOAPIC 2 +#define MPT_TYPE_INTSRC 3 +#define MPT_TYPE_LOCAL_INT 4 + +struct mpt_cpu { + u8 type; + u8 apicid; + u8 apicver; + u8 cpuflag; + u32 cpusignature; + u32 featureflag; + u32 reserved[2]; +} PACKED; + +struct mpt_bus { + u8 type; + u8 busid; + char bustype[6]; +} PACKED; + +struct mpt_ioapic { + u8 type; + u8 apicid; + u8 apicver; + u8 flags; + u32 apicaddr; +} PACKED; + +struct mpt_intsrc { + u8 type; + u8 irqtype; + u16 irqflag; + u8 srcbus; + u8 srcbusirq; + u8 dstapic; + u8 dstirq; +} PACKED; + +// mptable.c +void mptable_init(void); + +#endif // mptable.h diff --git a/bios/seabios/src/mtrr.c b/bios/seabios/src/mtrr.c new file mode 100644 index 0000000..0548043 --- /dev/null +++ b/bios/seabios/src/mtrr.c @@ -0,0 +1,103 @@ +// Initialize MTRRs - mostly useful on KVM. +// +// Copyright (C) 2006 Fabrice Bellard +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // dprintf +#include "biosvar.h" // GET_EBDA +#include "xen.h" // usingXen + +#define MSR_MTRRcap 0x000000fe +#define MSR_MTRRfix64K_00000 0x00000250 +#define MSR_MTRRfix16K_80000 0x00000258 +#define MSR_MTRRfix16K_A0000 0x00000259 +#define MSR_MTRRfix4K_C0000 0x00000268 +#define MSR_MTRRfix4K_C8000 0x00000269 +#define MSR_MTRRfix4K_D0000 0x0000026a +#define MSR_MTRRfix4K_D8000 0x0000026b +#define MSR_MTRRfix4K_E0000 0x0000026c +#define MSR_MTRRfix4K_E8000 0x0000026d +#define MSR_MTRRfix4K_F0000 0x0000026e +#define MSR_MTRRfix4K_F8000 0x0000026f +#define MSR_MTRRdefType 0x000002ff + +#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg)) +#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1) + +#define MTRR_MEMTYPE_UC 0 +#define MTRR_MEMTYPE_WC 1 +#define MTRR_MEMTYPE_WT 4 +#define MTRR_MEMTYPE_WP 5 +#define MTRR_MEMTYPE_WB 6 + +void mtrr_setup(void) +{ + if (!CONFIG_MTRR_INIT || CONFIG_COREBOOT || usingXen()) + return; + + u32 eax, ebx, ecx, edx, cpuid_features; + cpuid(1, &eax, &ebx, &ecx, &cpuid_features); + if (!(cpuid_features & CPUID_MTRR)) + return; + if (!(cpuid_features & CPUID_MSR)) + return; + + dprintf(3, "init mtrr\n"); + + u32 mtrr_cap = rdmsr(MSR_MTRRcap); + int vcnt = mtrr_cap & 0xff; + int fix = mtrr_cap & 0x100; + if (!vcnt || !fix) + return; + + // Disable MTRRs + wrmsr_smp(MSR_MTRRdefType, 0); + + // Set fixed MTRRs + union u64b { + u8 valb[8]; + u64 val; + } u; + u.val = 0; + int i; + for (i = 0; i < 8; i++) + if (RamSize >= 65536 * (i + 1)) + u.valb[i] = MTRR_MEMTYPE_WB; + wrmsr_smp(MSR_MTRRfix64K_00000, u.val); + u.val = 0; + for (i = 0; i < 8; i++) + if (RamSize >= 0x80000 + 16384 * (i + 1)) + u.valb[i] = MTRR_MEMTYPE_WB; + wrmsr_smp(MSR_MTRRfix16K_80000, u.val); + wrmsr_smp(MSR_MTRRfix16K_A0000, 0); // 0xA0000-0xC0000 is uncached + int j; + for (j = 0; j < 8; j++) { + u.val = 0; + for (i = 0; i < 8; i++) + if (RamSize >= 0xC0000 + j * 0x8000 + 4096 * (i + 1)) + u.valb[i] = MTRR_MEMTYPE_WP; + wrmsr_smp(MSR_MTRRfix4K_C0000 + j, u.val); + } + + // Set variable MTRRs + int phys_bits = 36; + cpuid(0x80000000u, &eax, &ebx, &ecx, &edx); + if (eax >= 0x80000008) { + /* Get physical bits from leaf 0x80000008 (if available) */ + cpuid(0x80000008u, &eax, &ebx, &ecx, &edx); + phys_bits = eax & 0xff; + } + u64 phys_mask = ((1ull << phys_bits) - 1); + for (i=0; i +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "bregs.h" // struct bregs +#include "farptr.h" // FLATPTR_TO_SEG +#include "config.h" // CONFIG_* +#include "util.h" // dprintf +#include "pci.h" // foreachpci +#include "pci_regs.h" // PCI_ROM_ADDRESS +#include "pci_ids.h" // PCI_CLASS_DISPLAY_VGA +#include "boot.h" // IPL +#include "paravirt.h" // qemu_cfg_* + + +/**************************************************************** + * Definitions + ****************************************************************/ + +struct rom_header { + u16 signature; + u8 size; + u8 initVector[4]; + u8 reserved[17]; + u16 pcioffset; + u16 pnpoffset; +} PACKED; + +struct pci_data { + u32 signature; + u16 vendor; + u16 device; + u16 vitaldata; + u16 dlen; + u8 drevision; + u8 class_lo; + u16 class_hi; + u16 ilen; + u16 irevision; + u8 type; + u8 indicator; + u16 reserved; +} PACKED; + +struct pnp_data { + u32 signature; + u8 revision; + u8 len; + u16 nextoffset; + u8 reserved_08; + u8 checksum; + u32 devid; + u16 manufacturer; + u16 productname; + u8 type_lo; + u16 type_hi; + u8 dev_flags; + u16 bcv; + u16 dv; + u16 bev; + u16 reserved_1c; + u16 staticresource; +} PACKED; + +#define OPTION_ROM_SIGNATURE 0xaa55 +#define OPTION_ROM_ALIGN 2048 +#define OPTION_ROM_INITVECTOR offsetof(struct rom_header, initVector[0]) +#define PCI_ROM_SIGNATURE 0x52494350 // PCIR +#define PCIROM_CODETYPE_X86 0 + +// The end of the last deployed rom. +u32 RomEnd = BUILD_ROM_START; + + +/**************************************************************** + * Helper functions + ****************************************************************/ + +// Execute a given option rom. +static void +__callrom(struct rom_header *rom, u16 offset, u16 bdf) +{ + u16 seg = FLATPTR_TO_SEG(rom); + dprintf(1, "Running option rom at %04x:%04x\n", seg, offset); + + struct bregs br; + memset(&br, 0, sizeof(br)); + br.flags = F_IF; + br.ax = bdf; + br.bx = 0xffff; + br.dx = 0xffff; + br.es = SEG_BIOS; + br.di = get_pnp_offset(); + br.code = SEGOFF(seg, offset); + start_preempt(); + call16big(&br); + finish_preempt(); + + debug_serial_setup(); +} + +// Execute a given option rom at the standard entry vector. +static void +callrom(struct rom_header *rom, u16 bdf) +{ + __callrom(rom, OPTION_ROM_INITVECTOR, bdf); +} + +// Execute a BCV option rom registered via add_bcv(). +void +call_bcv(u16 seg, u16 ip) +{ + __callrom(MAKE_FLATPTR(seg, 0), ip, 0); +} + +static int EnforceChecksum; + +// Verify that an option rom looks valid +static int +is_valid_rom(struct rom_header *rom) +{ + dprintf(6, "Checking rom %p (sig %x size %d)\n" + , rom, rom->signature, rom->size); + if (rom->signature != OPTION_ROM_SIGNATURE) + return 0; + if (! rom->size) + return 0; + u32 len = rom->size * 512; + u8 sum = checksum(rom, len); + if (sum != 0) { + dprintf(1, "Found option rom with bad checksum: loc=%p len=%d sum=%x\n" + , rom, len, sum); + if (EnforceChecksum) + return 0; + } + return 1; +} + +// Check if a valid option rom has a pnp struct; return it if so. +static struct pnp_data * +get_pnp_rom(struct rom_header *rom) +{ + struct pnp_data *pnp = (void*)((u8*)rom + rom->pnpoffset); + if (pnp->signature != PNP_SIGNATURE) + return NULL; + return pnp; +} + +// Check for multiple pnp option rom headers. +static struct pnp_data * +get_pnp_next(struct rom_header *rom, struct pnp_data *pnp) +{ + if (! pnp->nextoffset) + return NULL; + pnp = (void*)((u8*)rom + pnp->nextoffset); + if (pnp->signature != PNP_SIGNATURE) + return NULL; + return pnp; +} + +// Check if a valid option rom has a pci struct; return it if so. +static struct pci_data * +get_pci_rom(struct rom_header *rom) +{ + struct pci_data *pd = (void*)((u32)rom + rom->pcioffset); + if (pd->signature != PCI_ROM_SIGNATURE) + return NULL; + return pd; +} + +// Return start of code in 0xc0000-0xf0000 space. +static inline u32 _max_rom(void) { + extern u8 code32flat_start[], code32init_end[]; + return CONFIG_RELOCATE_INIT ? (u32)code32init_end : (u32)code32flat_start; +} +// Return the memory position up to which roms may be located. +static inline u32 max_rom(void) { + u32 end = _max_rom(); + return end > BUILD_BIOS_ADDR ? BUILD_BIOS_ADDR : end; +} + +// Copy a rom to its permanent location below 1MiB +static struct rom_header * +copy_rom(struct rom_header *rom) +{ + u32 romsize = rom->size * 512; + if (RomEnd + romsize > max_rom()) { + // Option rom doesn't fit. + warn_noalloc(); + return NULL; + } + dprintf(4, "Copying option rom (size %d) from %p to %x\n" + , romsize, rom, RomEnd); + iomemcpy((void*)RomEnd, rom, romsize); + return (void*)RomEnd; +} + +// Run rom init code and note rom size. +static int +init_optionrom(struct rom_header *rom, u16 bdf, int isvga) +{ + if (! is_valid_rom(rom)) + return -1; + + if (isvga || get_pnp_rom(rom)) + // Only init vga and PnP roms here. + callrom(rom, bdf); + + RomEnd = (u32)rom + ALIGN(rom->size * 512, OPTION_ROM_ALIGN); + + return 0; +} + +#define RS_PCIROM (1LL<<33) + +static void +setRomSource(u64 *sources, struct rom_header *rom, u64 source) +{ + if (sources) + sources[((u32)rom - BUILD_ROM_START) / OPTION_ROM_ALIGN] = source; +} + +static int +getRomPriority(u64 *sources, struct rom_header *rom, int instance) +{ + u64 source = sources[((u32)rom - BUILD_ROM_START) / OPTION_ROM_ALIGN]; + if (!source) + return -1; + if (source & RS_PCIROM) + return bootprio_find_pci_rom((void*)(u32)source, instance); + return bootprio_find_named_rom(romfile_name(source), instance); +} + + +/**************************************************************** + * Roms in CBFS + ****************************************************************/ + +// Check if an option rom is at a hardcoded location or in CBFS. +static struct rom_header * +lookup_hardcode(struct pci_device *pci) +{ + char fname[17]; + snprintf(fname, sizeof(fname), "pci%04x,%04x.rom" + , pci->vendor, pci->device); + int ret = romfile_copy(romfile_find(fname), (void*)RomEnd + , max_rom() - RomEnd); + if (ret <= 0) + return NULL; + return (void*)RomEnd; +} + +// Run all roms in a given CBFS directory. +static void +run_file_roms(const char *prefix, int isvga, u64 *sources) +{ + u32 file = 0; + for (;;) { + file = romfile_findprefix(prefix, file); + if (!file) + break; + struct rom_header *rom = (void*)RomEnd; + int ret = romfile_copy(file, rom, max_rom() - RomEnd); + if (ret > 0) { + setRomSource(sources, rom, file); + init_optionrom(rom, 0, isvga); + } + } +} + + +/**************************************************************** + * PCI roms + ****************************************************************/ + +// Verify device is a vga device with legacy address decoding enabled. +static int +is_pci_vga(struct pci_device *pci) +{ + if (pci->class != PCI_CLASS_DISPLAY_VGA) + return 0; + u16 cmd = pci_config_readw(pci->bdf, PCI_COMMAND); + if (!(cmd & PCI_COMMAND_IO && cmd & PCI_COMMAND_MEMORY)) + return 0; + while (pci->parent) { + pci = pci->parent; + u32 ctrl = pci_config_readb(pci->bdf, PCI_BRIDGE_CONTROL); + if (!(ctrl & PCI_BRIDGE_CTL_VGA)) + return 0; + } + return 1; +} + +// Map the option rom of a given PCI device. +static struct rom_header * +map_pcirom(struct pci_device *pci) +{ + u16 bdf = pci->bdf; + dprintf(6, "Attempting to map option rom on dev %02x:%02x.%x\n" + , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf)); + + if ((pci->header_type & 0x7f) != PCI_HEADER_TYPE_NORMAL) { + dprintf(6, "Skipping non-normal pci device (type=%x)\n" + , pci->header_type); + return NULL; + } + + u32 orig = pci_config_readl(bdf, PCI_ROM_ADDRESS); + pci_config_writel(bdf, PCI_ROM_ADDRESS, ~PCI_ROM_ADDRESS_ENABLE); + u32 sz = pci_config_readl(bdf, PCI_ROM_ADDRESS); + + dprintf(6, "Option rom sizing returned %x %x\n", orig, sz); + orig &= ~PCI_ROM_ADDRESS_ENABLE; + if (!sz || sz == 0xffffffff) + goto fail; + + if (orig == sz || (u32)(orig + 4*1024*1024) < 20*1024*1024) { + // Don't try to map to a pci addresses at its max, in the last + // 4MiB of ram, or the first 16MiB of ram. + dprintf(6, "Preset rom address doesn't look valid\n"); + goto fail; + } + + // Looks like a rom - enable it. + pci_config_writel(bdf, PCI_ROM_ADDRESS, orig | PCI_ROM_ADDRESS_ENABLE); + + struct rom_header *rom = (void*)orig; + for (;;) { + dprintf(5, "Inspecting possible rom at %p (vd=%04x:%04x" + " bdf=%02x:%02x.%x)\n" + , rom, pci->vendor, pci->device + , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf)); + if (rom->signature != OPTION_ROM_SIGNATURE) { + dprintf(6, "No option rom signature (got %x)\n", rom->signature); + goto fail; + } + struct pci_data *pd = get_pci_rom(rom); + if (! pd) { + dprintf(6, "No valid pci signature found\n"); + goto fail; + } + + if (pd->vendor == pci->vendor && pd->device == pci->device + && pd->type == PCIROM_CODETYPE_X86) + // A match + break; + dprintf(6, "Didn't match dev/ven (got %04x:%04x) or type (got %d)\n" + , pd->vendor, pd->device, pd->type); + if (pd->indicator & 0x80) { + dprintf(6, "No more images left\n"); + goto fail; + } + rom = (void*)((u32)rom + pd->ilen * 512); + } + + rom = copy_rom(rom); + pci_config_writel(bdf, PCI_ROM_ADDRESS, orig); + return rom; +fail: + // Not valid - restore original and exit. + pci_config_writel(bdf, PCI_ROM_ADDRESS, orig); + return NULL; +} + +// Attempt to map and initialize the option rom on a given PCI device. +static int +init_pcirom(struct pci_device *pci, int isvga, u64 *sources) +{ + u16 bdf = pci->bdf; + dprintf(4, "Attempting to init PCI bdf %02x:%02x.%x (vd %04x:%04x)\n" + , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf) + , pci->vendor, pci->device); + struct rom_header *rom = lookup_hardcode(pci); + if (! rom) + rom = map_pcirom(pci); + if (! rom) + // No ROM present. + return -1; + setRomSource(sources, rom, RS_PCIROM | (u32)pci); + return init_optionrom(rom, bdf, isvga); +} + + +/**************************************************************** + * Non-VGA option rom init + ****************************************************************/ + +void +optionrom_setup(void) +{ + if (! CONFIG_OPTIONROMS) + return; + + dprintf(1, "Scan for option roms\n"); + u64 sources[(BUILD_BIOS_ADDR - BUILD_ROM_START) / OPTION_ROM_ALIGN]; + memset(sources, 0, sizeof(sources)); + u32 post_vga = RomEnd; + + if (CONFIG_OPTIONROMS_DEPLOYED) { + // Option roms are already deployed on the system. + u32 pos = RomEnd; + while (pos < max_rom()) { + int ret = init_optionrom((void*)pos, 0, 0); + if (ret) + pos += OPTION_ROM_ALIGN; + else + pos = RomEnd; + } + } else { + // Find and deploy PCI roms. + struct pci_device *pci; + foreachpci(pci) { + if (pci->class == PCI_CLASS_DISPLAY_VGA || pci->have_driver) + continue; + init_pcirom(pci, 0, sources); + } + + // Find and deploy CBFS roms not associated with a device. + run_file_roms("genroms/", 0, sources); + } + + // All option roms found and deployed - now build BEV/BCV vectors. + + u32 pos = post_vga; + while (pos < RomEnd) { + struct rom_header *rom = (void*)pos; + if (! is_valid_rom(rom)) { + pos += OPTION_ROM_ALIGN; + continue; + } + pos += ALIGN(rom->size * 512, OPTION_ROM_ALIGN); + struct pnp_data *pnp = get_pnp_rom(rom); + if (! pnp) { + // Legacy rom. + boot_add_bcv(FLATPTR_TO_SEG(rom), OPTION_ROM_INITVECTOR, 0 + , getRomPriority(sources, rom, 0)); + continue; + } + // PnP rom. + if (pnp->bev) { + // Can boot system - add to IPL list. + boot_add_bev(FLATPTR_TO_SEG(rom), pnp->bev, pnp->productname + , getRomPriority(sources, rom, 0)); + } else { + // Check for BCV (there may be multiple). + int instance = 0; + while (pnp && pnp->bcv) { + boot_add_bcv(FLATPTR_TO_SEG(rom), pnp->bcv, pnp->productname + , getRomPriority(sources, rom, instance++)); + pnp = get_pnp_next(rom, pnp); + } + } + } +} + + +/**************************************************************** + * VGA init + ****************************************************************/ + +static int S3ResumeVgaInit; +int ScreenAndDebug; + +// Call into vga code to turn on console. +void +vga_setup(void) +{ + if (! CONFIG_OPTIONROMS) + return; + + dprintf(1, "Scan for VGA option rom\n"); + + // Load some config settings that impact VGA. + EnforceChecksum = romfile_loadint("etc/optionroms-checksum", 1); + S3ResumeVgaInit = romfile_loadint("etc/s3-resume-vga-init", 0); + ScreenAndDebug = romfile_loadint("etc/screen-and-debug", 1); + + if (CONFIG_OPTIONROMS_DEPLOYED) { + // Option roms are already deployed on the system. + init_optionrom((void*)BUILD_ROM_START, 0, 1); + } else { + // Clear option rom memory + memset((void*)RomEnd, 0, max_rom() - RomEnd); + + // Find and deploy PCI VGA rom. + struct pci_device *pci; + foreachpci(pci) { + if (!is_pci_vga(pci)) + continue; + vgahook_setup(pci); + init_pcirom(pci, 1, NULL); + break; + } + + // Find and deploy CBFS vga-style roms not associated with a device. + run_file_roms("vgaroms/", 1, NULL); + } + + if (RomEnd == BUILD_ROM_START) { + // No VGA rom found + RomEnd += OPTION_ROM_ALIGN; + return; + } + + enable_vga_console(); +} + +void +s3_resume_vga_init(void) +{ + if (!S3ResumeVgaInit) + return; + struct rom_header *rom = (void*)BUILD_ROM_START; + if (! is_valid_rom(rom)) + return; + callrom(rom, 0); +} diff --git a/bios/seabios/src/output.c b/bios/seabios/src/output.c new file mode 100644 index 0000000..462ffb7 --- /dev/null +++ b/bios/seabios/src/output.c @@ -0,0 +1,581 @@ +// Raw screen writing and debug output code. +// +// Copyright (C) 2008,2009 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include // va_list + +#include "farptr.h" // GET_VAR +#include "util.h" // printf +#include "bregs.h" // struct bregs +#include "config.h" // CONFIG_* +#include "biosvar.h" // GET_GLOBAL + +struct putcinfo { + void (*func)(struct putcinfo *info, char c); +}; + + +/**************************************************************** + * Debug output + ****************************************************************/ + +#define DEBUG_TIMEOUT 100000 + +void +debug_serial_setup(void) +{ + if (!CONFIG_DEBUG_SERIAL) + return; + // setup for serial logging: 8N1 + u8 oldparam, newparam = 0x03; + oldparam = inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LCR); + outb(newparam, CONFIG_DEBUG_SERIAL_PORT+SEROFF_LCR); + // Disable irqs + u8 oldier, newier = 0; + oldier = inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_IER); + outb(newier, CONFIG_DEBUG_SERIAL_PORT+SEROFF_IER); + + if (oldparam != newparam || oldier != newier) + dprintf(1, "Changing serial settings was %x/%x now %x/%x\n" + , oldparam, oldier, newparam, newier); +} + +// Write a character to the serial port. +static void +debug_serial(char c) +{ + if (!CONFIG_DEBUG_SERIAL) + return; + int timeout = DEBUG_TIMEOUT; + while ((inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LSR) & 0x20) != 0x20) + if (!timeout--) + // Ran out of time. + return; + outb(c, CONFIG_DEBUG_SERIAL_PORT+SEROFF_DATA); +} + +// Make sure all serial port writes have been completely sent. +static void +debug_serial_flush(void) +{ + if (!CONFIG_DEBUG_SERIAL) + return; + int timeout = DEBUG_TIMEOUT; + while ((inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LSR) & 0x60) != 0x60) + if (!timeout--) + // Ran out of time. + return; +} + +// Write a character to debug port(s). +static void +putc_debug(struct putcinfo *action, char c) +{ + if (! CONFIG_DEBUG_LEVEL) + return; + if (! CONFIG_COREBOOT) + // Send character to debug port. + outb(c, PORT_BIOS_DEBUG); + if (c == '\n') + debug_serial('\r'); + debug_serial(c); +} + +// In segmented mode just need a dummy variable (putc_debug is always +// used anyway), and in 32bit flat mode need a pointer to the 32bit +// instance of putc_debug(). +#if MODE16 +static struct putcinfo debuginfo VAR16; +#elif MODESEGMENT +static struct putcinfo debuginfo VAR32SEG; +#else +static struct putcinfo debuginfo = { putc_debug }; +#endif + + +/**************************************************************** + * Screen writing + ****************************************************************/ + +// Show a character on the screen. +static void +screenc(char c) +{ + struct bregs br; + memset(&br, 0, sizeof(br)); + br.flags = F_IF; + br.ah = 0x0e; + br.al = c; + call16_int(0x10, &br); +} + +// Handle a character from a printf request. +static void +putc_screen(struct putcinfo *action, char c) +{ + if (ScreenAndDebug) + putc_debug(&debuginfo, c); + if (c == '\n') + screenc('\r'); + screenc(c); +} + +static struct putcinfo screeninfo = { putc_screen }; + + +/**************************************************************** + * Xprintf code + ****************************************************************/ + +// Output a character. +static void +putc(struct putcinfo *action, char c) +{ + if (MODESEGMENT) { + // Only debugging output supported in segmented mode. + putc_debug(action, c); + return; + } + + void (*func)(struct putcinfo *info, char c) = GET_GLOBAL(action->func); + func(action, c); +} + +// Ouptut a string. +static void +puts(struct putcinfo *action, const char *s) +{ + if (!MODESEGMENT && !s) + s = "(NULL)"; + for (; *s; s++) + putc(action, *s); +} + +// Output a string that is in the CS segment. +static void +puts_cs(struct putcinfo *action, const char *s) +{ + char *vs = (char*)s; + for (;; vs++) { + char c = GET_GLOBAL(*vs); + if (!c) + break; + putc(action, c); + } +} + +// Output an unsigned integer. +static void +putuint(struct putcinfo *action, u32 val) +{ + char buf[12]; + char *d = &buf[sizeof(buf) - 1]; + *d-- = '\0'; + for (;;) { + *d = (val % 10) + '0'; + val /= 10; + if (!val) + break; + d--; + } + puts(action, d); +} + +// Output a single digit hex character. +static inline void +putsinglehex(struct putcinfo *action, u32 val) +{ + if (val <= 9) + val = '0' + val; + else + val = 'a' + val - 10; + putc(action, val); +} + +// Output an integer in hexadecimal. +static void +puthex(struct putcinfo *action, u32 val, int width, int spacepad) +{ + if (!width) { + u32 tmp = val; + width = 1; + while (tmp >>= 4) + width++; + } else if (spacepad) { + u32 tmp = val; + u32 count = 1; + while (tmp >>= 4) + count++; + if (width > count) { + count = width - count; + width -= count; + while (count--) + putc(action, ' '); + } + } + + switch (width) { + default: putsinglehex(action, (val >> 28) & 0xf); + case 7: putsinglehex(action, (val >> 24) & 0xf); + case 6: putsinglehex(action, (val >> 20) & 0xf); + case 5: putsinglehex(action, (val >> 16) & 0xf); + case 4: putsinglehex(action, (val >> 12) & 0xf); + case 3: putsinglehex(action, (val >> 8) & 0xf); + case 2: putsinglehex(action, (val >> 4) & 0xf); + case 1: putsinglehex(action, (val >> 0) & 0xf); + } +} + +static inline int +isdigit(u8 c) +{ + return ((u8)(c - '0')) < 10; +} + +static void +bvprintf(struct putcinfo *action, const char *fmt, va_list args) +{ + const char *s = fmt; + for (;; s++) { + char c = GET_GLOBAL(*(u8*)s); + if (!c) + break; + if (c != '%') { + putc(action, c); + continue; + } + const char *n = s+1; + int field_width = 0; + int spacepad = 1; + for (;;) { + c = GET_GLOBAL(*(u8*)n); + if (!isdigit(c)) + break; + if (!field_width && (c == '0')) + spacepad = 0; + else + field_width = field_width * 10 + c - '0'; + n++; + } + if (c == 'l') { + // Ignore long format indicator + n++; + c = GET_GLOBAL(*(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 'p': + /* %p always has 0x prepended */ + putc(action, '0'); + putc(action, 'x'); + field_width = 8; + spacepad = 0; + case 'x': + val = va_arg(args, s32); + puthex(action, val, field_width, spacepad); + break; + case 'c': + val = va_arg(args, int); + putc(action, val); + break; + case '.': + // Hack to support "%.s" - meaning string on stack. + if (GET_GLOBAL(*(u8*)(n+1)) != 's') + break; + n++; + sarg = va_arg(args, const char *); + puts(action, sarg); + break; + case 's': + sarg = va_arg(args, const char *); + puts_cs(action, sarg); + break; + default: + putc(action, '%'); + n = s; + } + s = n; + } +} + +void +panic(const char *fmt, ...) +{ + if (CONFIG_DEBUG_LEVEL) { + va_list args; + va_start(args, fmt); + bvprintf(&debuginfo, fmt, args); + va_end(args); + debug_serial_flush(); + } + + // XXX - use PANIC PORT. + irq_disable(); + for (;;) + hlt(); +} + +void +__dprintf(const char *fmt, ...) +{ + if (!MODESEGMENT && CONFIG_THREADS && CONFIG_DEBUG_LEVEL >= DEBUG_thread + && *fmt != '\\' && *fmt != '/') { + struct thread_info *cur = getCurThread(); + if (cur != &MainThread) { + // Show "thread id" for this debug message. + putc_debug(&debuginfo, '|'); + puthex(&debuginfo, (u32)cur, 8, 0); + putc_debug(&debuginfo, '|'); + putc_debug(&debuginfo, ' '); + } + } + + va_list args; + va_start(args, fmt); + bvprintf(&debuginfo, fmt, args); + va_end(args); + debug_serial_flush(); +} + +void +printf(const char *fmt, ...) +{ + ASSERT32FLAT(); + va_list args; + va_start(args, fmt); + bvprintf(&screeninfo, fmt, args); + va_end(args); + if (ScreenAndDebug) + debug_serial_flush(); +} + + +/**************************************************************** + * snprintf + ****************************************************************/ + +struct snprintfinfo { + struct putcinfo info; + char *str, *end; +}; + +static void +putc_str(struct putcinfo *info, char c) +{ + struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info); + if (sinfo->str >= sinfo->end) + return; + *sinfo->str = c; + sinfo->str++; +} + +// Build a formatted string. Note, this function returns the actual +// number of bytes used (not including null) even in the overflow +// case. +int +snprintf(char *str, size_t size, const char *fmt, ...) +{ + ASSERT32FLAT(); + if (!size) + return 0; + struct snprintfinfo sinfo = { { putc_str }, str, str + size }; + va_list args; + va_start(args, fmt); + bvprintf(&sinfo.info, fmt, args); + va_end(args); + char *end = sinfo.str; + if (end >= sinfo.end) + end = sinfo.end - 1; + *end = '\0'; + return end - str; +} + +// Build a formatted string - malloc'ing the memory. +char * +znprintf(size_t size, const char *fmt, ...) +{ + ASSERT32FLAT(); + if (!size) + return NULL; + char *str = malloc_tmp(size); + if (!str) { + warn_noalloc(); + return NULL; + } + struct snprintfinfo sinfo = { { putc_str }, str, str + size }; + va_list args; + va_start(args, fmt); + bvprintf(&sinfo.info, fmt, args); + va_end(args); + char *end = sinfo.str; + if (end >= sinfo.end) + end = sinfo.end - 1; + *end = '\0'; + return str; +} + + +/**************************************************************** + * Misc helpers + ****************************************************************/ + +void +hexdump(const void *d, int len) +{ + int count=0; + while (len > 0) { + if (count % 8 == 0) { + putc(&debuginfo, '\n'); + puthex(&debuginfo, count*4, 8, 0); + putc(&debuginfo, ':'); + } else { + putc(&debuginfo, ' '); + } + puthex(&debuginfo, *(u32*)d, 8, 0); + count++; + len-=4; + d+=4; + } + putc(&debuginfo, '\n'); + debug_serial_flush(); +} + +static void +dump_regs(struct bregs *regs) +{ + if (!regs) { + dprintf(1, " NULL\n"); + return; + } + dprintf(1, " a=%08x b=%08x c=%08x d=%08x ds=%04x es=%04x ss=%04x\n" + , regs->eax, regs->ebx, regs->ecx, regs->edx + , regs->ds, regs->es, GET_SEG(SS)); + dprintf(1, " si=%08x di=%08x bp=%08x sp=%08x cs=%04x ip=%04x f=%04x\n" + , regs->esi, regs->edi, regs->ebp, (u32)®s[1] + , regs->code.seg, regs->code.offset, regs->flags); +} + +// Report entry to an Interrupt Service Routine (ISR). +void +__debug_isr(const char *fname) +{ + puts_cs(&debuginfo, fname); + putc(&debuginfo, '\n'); + debug_serial_flush(); +} + +// Function called on handler startup. +void +__debug_enter(struct bregs *regs, const char *fname) +{ + dprintf(1, "enter %s:\n", fname); + dump_regs(regs); +} + +// Send debugging output info. +void +__debug_stub(struct bregs *regs, int lineno, const char *fname) +{ + dprintf(1, "stub %s:%d:\n", fname, lineno); + dump_regs(regs); +} + +// Report on an invalid parameter. +void +__warn_invalid(struct bregs *regs, int lineno, const char *fname) +{ + if (CONFIG_DEBUG_LEVEL >= DEBUG_invalid) { + dprintf(1, "invalid %s:%d:\n", fname, lineno); + dump_regs(regs); + } +} + +// Report on an unimplemented feature. +void +__warn_unimplemented(struct bregs *regs, int lineno, const char *fname) +{ + if (CONFIG_DEBUG_LEVEL >= DEBUG_unimplemented) { + dprintf(1, "unimplemented %s:%d:\n", fname, lineno); + dump_regs(regs); + } +} + +// Report a detected internal inconsistency. +void +__warn_internalerror(int lineno, const char *fname) +{ + dprintf(1, "WARNING - internal error detected at %s:%d!\n" + , fname, lineno); +} + +// Report on an allocation failure. +void +__warn_noalloc(int lineno, const char *fname) +{ + dprintf(1, "WARNING - Unable to allocate resource at %s:%d!\n" + , fname, lineno); +} + +// Report on a timeout exceeded. +void +__warn_timeout(int lineno, const char *fname) +{ + dprintf(1, "WARNING - Timeout at %s:%d!\n", fname, lineno); +} + +// Report a handler reporting an invalid parameter to the caller. +void +__set_invalid(struct bregs *regs, int lineno, const char *fname) +{ + __warn_invalid(regs, lineno, fname); + set_invalid_silent(regs); +} + +// Report a call of an unimplemented function. +void +__set_unimplemented(struct bregs *regs, int lineno, const char *fname) +{ + __warn_unimplemented(regs, lineno, fname); + set_invalid_silent(regs); +} + +// Report a handler reporting an invalid parameter code to the +// caller. Note, the lineno and return code are encoded in the same +// parameter as gcc does a better job of scheduling function calls +// when there are 3 or less parameters. +void +__set_code_invalid(struct bregs *regs, u32 linecode, const char *fname) +{ + u8 code = linecode; + u32 lineno = linecode >> 8; + __warn_invalid(regs, lineno, fname); + set_code_invalid_silent(regs, code); +} + +// Report a call of an unimplemented function. +void +__set_code_unimplemented(struct bregs *regs, u32 linecode, const char *fname) +{ + u8 code = linecode; + u32 lineno = linecode >> 8; + __warn_unimplemented(regs, lineno, fname); + set_code_invalid_silent(regs, code); +} diff --git a/bios/seabios/src/paravirt.c b/bios/seabios/src/paravirt.c new file mode 100644 index 0000000..9cf77de --- /dev/null +++ b/bios/seabios/src/paravirt.c @@ -0,0 +1,430 @@ +// Paravirtualization support. +// +// Copyright (C) 2009 Red Hat Inc. +// +// Authors: +// Gleb Natapov +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "config.h" // CONFIG_COREBOOT +#include "util.h" // ntoh[ls] +#include "ioport.h" // outw +#include "paravirt.h" // qemu_cfg_port_probe +#include "smbios.h" // struct smbios_structure_header + +int qemu_cfg_present; + +static void +qemu_cfg_select(u16 f) +{ + outw(f, PORT_QEMU_CFG_CTL); +} + +static void +qemu_cfg_read(u8 *buf, int len) +{ + insb(PORT_QEMU_CFG_DATA, buf, len); +} + +static void +qemu_cfg_skip(int len) +{ + while (len--) + inb(PORT_QEMU_CFG_DATA); +} + +static void +qemu_cfg_read_entry(void *buf, int e, int len) +{ + qemu_cfg_select(e); + qemu_cfg_read(buf, len); +} + +void qemu_cfg_port_probe(void) +{ + char *sig = "QEMU"; + int i; + + if (CONFIG_COREBOOT) + return; + + qemu_cfg_present = 1; + + qemu_cfg_select(QEMU_CFG_SIGNATURE); + + for (i = 0; i < 4; i++) + if (inb(PORT_QEMU_CFG_DATA) != sig[i]) { + qemu_cfg_present = 0; + break; + } + dprintf(4, "qemu_cfg_present=%d\n", qemu_cfg_present); +} + +void qemu_cfg_get_uuid(u8 *uuid) +{ + if (!qemu_cfg_present) + return; + + qemu_cfg_read_entry(uuid, QEMU_CFG_UUID, 16); +} + +int qemu_cfg_show_boot_menu(void) +{ + u16 v; + if (!qemu_cfg_present) + return 1; + + qemu_cfg_read_entry(&v, QEMU_CFG_BOOT_MENU, sizeof(v)); + + return v; +} + +int qemu_cfg_irq0_override(void) +{ + u8 v; + + if (!qemu_cfg_present) + return 0; + + qemu_cfg_read_entry(&v, QEMU_CFG_IRQ0_OVERRIDE, sizeof(v)); + + return v; +} + +u16 qemu_cfg_acpi_additional_tables(void) +{ + u16 cnt; + + if (!qemu_cfg_present) + return 0; + + qemu_cfg_read_entry(&cnt, QEMU_CFG_ACPI_TABLES, sizeof(cnt)); + + return cnt; +} + +u16 qemu_cfg_next_acpi_table_len(void) +{ + u16 len; + + qemu_cfg_read((u8*)&len, sizeof(len)); + + return len; +} + +void* qemu_cfg_next_acpi_table_load(void *addr, u16 len) +{ + qemu_cfg_read(addr, len); + return addr; +} + +u16 qemu_cfg_smbios_entries(void) +{ + u16 cnt; + + if (!qemu_cfg_present) + return 0; + + qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt)); + + return cnt; +} + +u32 qemu_cfg_e820_entries(void) +{ + u32 cnt; + + if (!qemu_cfg_present) + return 0; + + qemu_cfg_read_entry(&cnt, QEMU_CFG_E820_TABLE, sizeof(cnt)); + return cnt; +} + +void* qemu_cfg_e820_load_next(void *addr) +{ + qemu_cfg_read(addr, sizeof(struct e820_reservation)); + return addr; +} + +struct smbios_header { + u16 length; + u8 type; +} PACKED; + +struct smbios_field { + struct smbios_header header; + u8 type; + u16 offset; + u8 data[]; +} PACKED; + +struct smbios_table { + struct smbios_header header; + u8 data[]; +} PACKED; + +#define SMBIOS_FIELD_ENTRY 0 +#define SMBIOS_TABLE_ENTRY 1 + +size_t qemu_cfg_smbios_load_field(int type, size_t offset, void *addr) +{ + int i; + + for (i = qemu_cfg_smbios_entries(); i > 0; i--) { + struct smbios_field field; + + qemu_cfg_read((u8 *)&field, sizeof(struct smbios_header)); + field.header.length -= sizeof(struct smbios_header); + + if (field.header.type != SMBIOS_FIELD_ENTRY) { + qemu_cfg_skip(field.header.length); + continue; + } + + qemu_cfg_read((u8 *)&field.type, + sizeof(field) - sizeof(struct smbios_header)); + field.header.length -= sizeof(field) - sizeof(struct smbios_header); + + if (field.type != type || field.offset != offset) { + qemu_cfg_skip(field.header.length); + continue; + } + + qemu_cfg_read(addr, field.header.length); + return (size_t)field.header.length; + } + return 0; +} + +int qemu_cfg_smbios_load_external(int type, char **p, unsigned *nr_structs, + unsigned *max_struct_size, char *end) +{ + static u64 used_bitmap[4] = { 0 }; + char *start = *p; + int i; + + /* Check if we've already reported these tables */ + if (used_bitmap[(type >> 6) & 0x3] & (1ULL << (type & 0x3f))) + return 1; + + /* Don't introduce spurious end markers */ + if (type == 127) + return 0; + + for (i = qemu_cfg_smbios_entries(); i > 0; i--) { + struct smbios_table table; + struct smbios_structure_header *header = (void *)*p; + int string; + + qemu_cfg_read((u8 *)&table, sizeof(struct smbios_header)); + table.header.length -= sizeof(struct smbios_header); + + if (table.header.type != SMBIOS_TABLE_ENTRY) { + qemu_cfg_skip(table.header.length); + continue; + } + + if (end - *p < sizeof(struct smbios_structure_header)) { + warn_noalloc(); + break; + } + + qemu_cfg_read((u8 *)*p, sizeof(struct smbios_structure_header)); + table.header.length -= sizeof(struct smbios_structure_header); + + if (header->type != type) { + qemu_cfg_skip(table.header.length); + continue; + } + + *p += sizeof(struct smbios_structure_header); + + /* Entries end with a double NULL char, if there's a string at + * the end (length is greater than formatted length), the string + * terminator provides the first NULL. */ + string = header->length < table.header.length + + sizeof(struct smbios_structure_header); + + /* Read the rest and terminate the entry */ + if (end - *p < table.header.length) { + warn_noalloc(); + *p -= sizeof(struct smbios_structure_header); + continue; + } + qemu_cfg_read((u8 *)*p, table.header.length); + *p += table.header.length; + *((u8*)*p) = 0; + (*p)++; + if (!string) { + *((u8*)*p) = 0; + (*p)++; + } + + (*nr_structs)++; + if (*p - (char *)header > *max_struct_size) + *max_struct_size = *p - (char *)header; + } + + if (start != *p) { + /* Mark that we've reported on this type */ + used_bitmap[(type >> 6) & 0x3] |= (1ULL << (type & 0x3f)); + return 1; + } + + return 0; +} + +int qemu_cfg_get_numa_nodes(void) +{ + u64 cnt; + + qemu_cfg_read_entry(&cnt, QEMU_CFG_NUMA, sizeof(cnt)); + + return (int)cnt; +} + +void qemu_cfg_get_numa_data(u64 *data, int n) +{ + int i; + + for (i = 0; i < n; i++) + qemu_cfg_read((u8*)(data + i), sizeof(u64)); +} + +u16 qemu_cfg_get_max_cpus(void) +{ + u16 cnt; + + if (!qemu_cfg_present) + return 0; + + qemu_cfg_read_entry(&cnt, QEMU_CFG_MAX_CPUS, sizeof(cnt)); + + return cnt; +} + +static QemuCfgFile LastFile; + +static u32 +__cfg_next_prefix_file(const char *prefix, int prefixlen, u32 prevselect) +{ + if (!qemu_cfg_present) + return 0; + + u32 count; + qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count)); + count = ntohl(count); + u32 e; + for (e = 0; e < count; e++) { + qemu_cfg_read((void*)&LastFile, sizeof(LastFile)); + u32 select = ntohs(LastFile.select); + if (select <= prevselect) + continue; + if (memcmp(prefix, LastFile.name, prefixlen) == 0) + return select; + } + return 0; +} + +u32 qemu_cfg_next_prefix_file(const char *prefix, u32 prevselect) +{ + return __cfg_next_prefix_file(prefix, strlen(prefix), prevselect); +} + +u32 qemu_cfg_find_file(const char *name) +{ + return __cfg_next_prefix_file(name, strlen(name) + 1, 0); +} + +static int +__qemu_cfg_set_file(u32 select) +{ + if (!qemu_cfg_present || !select) + return -1; + if (select == ntohs(LastFile.select)) + return 0; + + u32 count; + qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count)); + count = ntohl(count); + u32 e; + for (e = 0; e < count; e++) { + qemu_cfg_read((void*)&LastFile, sizeof(LastFile)); + if (select == ntohs(LastFile.select)) + return 0; + } + return -1; +} + +int qemu_cfg_size_file(u32 select) +{ + if (__qemu_cfg_set_file(select)) + return -1; + return ntohl(LastFile.size); +} + +const char* qemu_cfg_name_file(u32 select) +{ + if (__qemu_cfg_set_file(select)) + return NULL; + return LastFile.name; +} + +int qemu_cfg_read_file(u32 select, void *dst, u32 maxlen) +{ + if (__qemu_cfg_set_file(select)) + return -1; + int len = qemu_cfg_size_file(select); + if (len < 0 || len > maxlen) + return -1; + qemu_cfg_read_entry(dst, select, len); + return len; +} + +// Helper function to find, malloc_tmphigh, and copy a romfile. This +// function adds a trailing zero to the malloc'd copy. +void * +romfile_loadfile(const char *name, int *psize) +{ + u32 file = romfile_find(name); + if (!file) + return NULL; + + int filesize = romfile_size(file); + if (!filesize) + return NULL; + + char *data = malloc_tmphigh(filesize+1); + if (!data) { + warn_noalloc(); + return NULL; + } + + dprintf(5, "Copying romfile '%s' (len %d)\n", name, filesize); + romfile_copy(file, data, filesize); + if (psize) + *psize = filesize; + data[filesize] = '\0'; + return data; +} + +// Attempt to load an integer from the given file - return 'defval' +// if unsuccesful. +u64 +romfile_loadint(const char *name, u64 defval) +{ + u32 file = romfile_find(name); + if (!file) + return defval; + + int filesize = romfile_size(file); + if (!filesize || filesize > sizeof(u64) || (filesize & (filesize-1))) + // Doesn't look like a valid integer. + return defval; + + u64 val = 0; + romfile_copy(file, &val, sizeof(val)); + return val; +} diff --git a/bios/seabios/src/paravirt.h b/bios/seabios/src/paravirt.h new file mode 100644 index 0000000..4a370a0 --- /dev/null +++ b/bios/seabios/src/paravirt.h @@ -0,0 +1,110 @@ +#ifndef __PV_H +#define __PV_H + +#include "config.h" // CONFIG_COREBOOT +#include "util.h" + +/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx. It + * should be used to determine that a VM is running under KVM. + */ +#define KVM_CPUID_SIGNATURE 0x40000000 + +static inline int kvm_para_available(void) +{ + unsigned int eax, ebx, ecx, edx; + char signature[13]; + + cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx); + memcpy(signature + 0, &ebx, 4); + memcpy(signature + 4, &ecx, 4); + memcpy(signature + 8, &edx, 4); + signature[12] = 0; + + if (strcmp(signature, "KVMKVMKVM") == 0) + return 1; + + return 0; +} + +#define QEMU_CFG_SIGNATURE 0x00 +#define QEMU_CFG_ID 0x01 +#define QEMU_CFG_UUID 0x02 +#define QEMU_CFG_NUMA 0x0d +#define QEMU_CFG_BOOT_MENU 0x0e +#define QEMU_CFG_MAX_CPUS 0x0f +#define QEMU_CFG_FILE_DIR 0x19 +#define QEMU_CFG_ARCH_LOCAL 0x8000 +#define QEMU_CFG_ACPI_TABLES (QEMU_CFG_ARCH_LOCAL + 0) +#define QEMU_CFG_SMBIOS_ENTRIES (QEMU_CFG_ARCH_LOCAL + 1) +#define QEMU_CFG_IRQ0_OVERRIDE (QEMU_CFG_ARCH_LOCAL + 2) +#define QEMU_CFG_E820_TABLE (QEMU_CFG_ARCH_LOCAL + 3) + +extern int qemu_cfg_present; + +void qemu_cfg_port_probe(void); +int qemu_cfg_show_boot_menu(void); +void qemu_cfg_get_uuid(u8 *uuid); +int qemu_cfg_irq0_override(void); +u16 qemu_cfg_acpi_additional_tables(void); +u16 qemu_cfg_next_acpi_table_len(void); +void *qemu_cfg_next_acpi_table_load(void *addr, u16 len); +u16 qemu_cfg_smbios_entries(void); +size_t qemu_cfg_smbios_load_field(int type, size_t offset, void *addr); +int qemu_cfg_smbios_load_external(int type, char **p, unsigned *nr_structs, + unsigned *max_struct_size, char *end); +int qemu_cfg_get_numa_nodes(void); +void qemu_cfg_get_numa_data(u64 *data, int n); +u16 qemu_cfg_get_max_cpus(void); + +typedef struct QemuCfgFile { + u32 size; /* file size */ + u16 select; /* write this to 0x510 to read it */ + u16 reserved; + char name[56]; +} QemuCfgFile; + +struct e820_reservation { + u64 address; + u64 length; + u32 type; +}; + +u32 qemu_cfg_next_prefix_file(const char *prefix, u32 prevselect); +u32 qemu_cfg_find_file(const char *name); +int qemu_cfg_size_file(u32 select); +const char* qemu_cfg_name_file(u32 select); +int qemu_cfg_read_file(u32 select, void *dst, u32 maxlen); + +// Wrappers that select cbfs or qemu_cfg file interface. +static inline u32 romfile_findprefix(const char *prefix, u32 previd) { + if (CONFIG_COREBOOT) + return (u32)cbfs_findprefix(prefix, (void*)previd); + return qemu_cfg_next_prefix_file(prefix, previd); +} +static inline u32 romfile_find(const char *name) { + if (CONFIG_COREBOOT) + return (u32)cbfs_finddatafile(name); + return qemu_cfg_find_file(name); +} +static inline u32 romfile_size(u32 fileid) { + if (CONFIG_COREBOOT) + return cbfs_datasize((void*)fileid); + return qemu_cfg_size_file(fileid); +} +static inline int romfile_copy(u32 fileid, void *dst, u32 maxlen) { + if (CONFIG_COREBOOT) + return cbfs_copyfile((void*)fileid, dst, maxlen); + return qemu_cfg_read_file(fileid, dst, maxlen); +} +static inline const char* romfile_name(u32 fileid) { + if (CONFIG_COREBOOT) + return cbfs_filename((void*)fileid); + return qemu_cfg_name_file(fileid); +} +void *romfile_loadfile(const char *name, int *psize); +u64 romfile_loadint(const char *name, u64 defval); + +u32 qemu_cfg_e820_entries(void); +void* qemu_cfg_e820_load_next(void *addr); + +#endif diff --git a/bios/seabios/src/pci.c b/bios/seabios/src/pci.c new file mode 100644 index 0000000..6031c9f --- /dev/null +++ b/bios/seabios/src/pci.c @@ -0,0 +1,277 @@ +// PCI config space access functions. +// +// Copyright (C) 2008 Kevin O'Connor +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "pci.h" // pci_config_writel +#include "ioport.h" // outl +#include "util.h" // dprintf +#include "paravirt.h" // romfile_loadint +#include "farptr.h" // MAKE_FLATPTR +#include "pci_regs.h" // PCI_VENDOR_ID +#include "pci_ids.h" // PCI_CLASS_DISPLAY_VGA + +void pci_config_writel(u16 bdf, u32 addr, u32 val) +{ + outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD); + outl(val, PORT_PCI_DATA); +} + +void pci_config_writew(u16 bdf, u32 addr, u16 val) +{ + outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD); + outw(val, PORT_PCI_DATA + (addr & 2)); +} + +void pci_config_writeb(u16 bdf, u32 addr, u8 val) +{ + outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD); + outb(val, PORT_PCI_DATA + (addr & 3)); +} + +u32 pci_config_readl(u16 bdf, u32 addr) +{ + outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD); + return inl(PORT_PCI_DATA); +} + +u16 pci_config_readw(u16 bdf, u32 addr) +{ + outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD); + return inw(PORT_PCI_DATA + (addr & 2)); +} + +u8 pci_config_readb(u16 bdf, u32 addr) +{ + outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD); + return inb(PORT_PCI_DATA + (addr & 3)); +} + +void +pci_config_maskw(u16 bdf, u32 addr, u16 off, u16 on) +{ + u16 val = pci_config_readw(bdf, addr); + val = (val & ~off) | on; + pci_config_writew(bdf, addr, val); +} + +// Helper function for foreachbdf() macro - return next device +int +pci_next(int bdf, int bus) +{ + if (pci_bdf_to_fn(bdf) == 0 + && (pci_config_readb(bdf, PCI_HEADER_TYPE) & 0x80) == 0) + // Last found device wasn't a multi-function device - skip to + // the next device. + bdf += 8; + else + bdf += 1; + + for (;;) { + if (pci_bdf_to_bus(bdf) != bus) + return -1; + + u16 v = pci_config_readw(bdf, PCI_VENDOR_ID); + if (v != 0x0000 && v != 0xffff) + // Device is present. + return bdf; + + if (pci_bdf_to_fn(bdf) == 0) + bdf += 8; + else + bdf += 1; + } +} + +struct pci_device *PCIDevices; +int MaxPCIBus VAR16VISIBLE; + +// Check if PCI is available at all +int +pci_probe_host(void) +{ + outl(0x80000000, PORT_PCI_CMD); + if (inl(PORT_PCI_CMD) != 0x80000000) { + dprintf(1, "Detected non-PCI system\n"); + return -1; + } + return 0; +} + +// Find all PCI devices and populate PCIDevices linked list. +void +pci_probe_devices(void) +{ + dprintf(3, "PCI probe\n"); + struct pci_device *busdevs[256]; + memset(busdevs, 0, sizeof(busdevs)); + struct pci_device **pprev = &PCIDevices; + int extraroots = romfile_loadint("etc/extra-pci-roots", 0); + int bus = -1, lastbus = 0, rootbuses = 0, count=0; + while (bus < 0xff && (bus < MaxPCIBus || rootbuses < extraroots)) { + bus++; + int bdf; + foreachbdf(bdf, bus) { + // Create new pci_device struct and add to list. + struct pci_device *dev = malloc_tmp(sizeof(*dev)); + if (!dev) { + warn_noalloc(); + return; + } + memset(dev, 0, sizeof(*dev)); + *pprev = dev; + pprev = &dev->next; + count++; + + // Find parent device. + int rootbus; + struct pci_device *parent = busdevs[bus]; + if (!parent) { + if (bus != lastbus) + rootbuses++; + lastbus = bus; + rootbus = rootbuses; + if (bus > MaxPCIBus) + MaxPCIBus = bus; + } else { + rootbus = parent->rootbus; + } + + // Populate pci_device info. + dev->bdf = bdf; + dev->parent = parent; + dev->rootbus = rootbus; + u32 vendev = pci_config_readl(bdf, PCI_VENDOR_ID); + dev->vendor = vendev & 0xffff; + dev->device = vendev >> 16; + u32 classrev = pci_config_readl(bdf, PCI_CLASS_REVISION); + dev->class = classrev >> 16; + dev->prog_if = classrev >> 8; + dev->revision = classrev & 0xff; + dev->header_type = pci_config_readb(bdf, PCI_HEADER_TYPE); + u8 v = dev->header_type & 0x7f; + if (v == PCI_HEADER_TYPE_BRIDGE || v == PCI_HEADER_TYPE_CARDBUS) { + u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS); + dev->secondary_bus = secbus; + if (secbus > bus && !busdevs[secbus]) + busdevs[secbus] = dev; + if (secbus > MaxPCIBus) + MaxPCIBus = secbus; + } + dprintf(4, "PCI device %02x:%02x.%x (vd=%04x:%04x c=%04x)\n" + , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf) + , pci_bdf_to_fn(bdf) + , dev->vendor, dev->device, dev->class); + } + } + dprintf(1, "Found %d PCI devices (max PCI bus is %02x)\n", count, MaxPCIBus); +} + +// Search for a device with the specified vendor and device ids. +struct pci_device * +pci_find_device(u16 vendid, u16 devid) +{ + struct pci_device *pci; + foreachpci(pci) { + if (pci->vendor == vendid && pci->device == devid) + return pci; + } + return NULL; +} + +// Search for a device with the specified class id. +struct pci_device * +pci_find_class(u16 classid) +{ + struct pci_device *pci; + foreachpci(pci) { + if (pci->class == classid) + return pci; + } + return NULL; +} + +int pci_init_device(const struct pci_device_id *ids + , struct pci_device *pci, void *arg) +{ + while (ids->vendid || ids->class_mask) { + if ((ids->vendid == PCI_ANY_ID || ids->vendid == pci->vendor) && + (ids->devid == PCI_ANY_ID || ids->devid == pci->device) && + !((ids->class ^ pci->class) & ids->class_mask)) { + if (ids->func) + ids->func(pci, arg); + return 0; + } + ids++; + } + return -1; +} + +struct pci_device * +pci_find_init_device(const struct pci_device_id *ids, void *arg) +{ + struct pci_device *pci; + foreachpci(pci) { + if (pci_init_device(ids, pci, arg) == 0) + return pci; + } + return NULL; +} + +void +pci_reboot(void) +{ + u8 v = inb(PORT_PCI_REBOOT) & ~6; + outb(v|2, PORT_PCI_REBOOT); /* Request hard reset */ + udelay(50); + outb(v|6, PORT_PCI_REBOOT); /* Actually do the reset */ + udelay(50); +} + +// helper functions to access pci mmio bars from real mode + +u32 VISIBLE32FLAT +pci_readl_32(u32 addr) +{ + dprintf(3, "32: pci read : %x\n", addr); + return readl((void*)addr); +} + +u32 pci_readl(u32 addr) +{ + if (MODESEGMENT) { + dprintf(3, "16: pci read : %x\n", addr); + extern void _cfunc32flat_pci_readl_32(u32 addr); + return call32(_cfunc32flat_pci_readl_32, addr, -1); + } else { + return pci_readl_32(addr); + } +} + +struct reg32 { + u32 addr; + u32 data; +}; + +void VISIBLE32FLAT +pci_writel_32(struct reg32 *reg32) +{ + dprintf(3, "32: pci write: %x, %x (%p)\n", reg32->addr, reg32->data, reg32); + writel((void*)(reg32->addr), reg32->data); +} + +void pci_writel(u32 addr, u32 val) +{ + struct reg32 reg32 = { .addr = addr, .data = val }; + if (MODESEGMENT) { + dprintf(3, "16: pci write: %x, %x (%x:%p)\n", + reg32.addr, reg32.data, GET_SEG(SS), ®32); + void *flatptr = MAKE_FLATPTR(GET_SEG(SS), ®32); + extern void _cfunc32flat_pci_writel_32(struct reg32 *reg32); + call32(_cfunc32flat_pci_writel_32, (u32)flatptr, -1); + } else { + pci_writel_32(®32); + } +} diff --git a/bios/seabios/src/pci.h b/bios/seabios/src/pci.h new file mode 100644 index 0000000..a2a5a4c --- /dev/null +++ b/bios/seabios/src/pci.h @@ -0,0 +1,162 @@ +#ifndef __PCI_H +#define __PCI_H + +#include "types.h" // u32 + +#define PCI_ROM_SLOT 6 +#define PCI_NUM_REGIONS 7 + +static inline u8 pci_bdf_to_bus(u16 bdf) { + return bdf >> 8; +} +static inline u8 pci_bdf_to_devfn(u16 bdf) { + return bdf & 0xff; +} +static inline u16 pci_bdf_to_busdev(u16 bdf) { + return bdf & ~0x07; +} +static inline u8 pci_bdf_to_dev(u16 bdf) { + return (bdf >> 3) & 0x1f; +} +static inline u8 pci_bdf_to_fn(u16 bdf) { + return bdf & 0x07; +} +static inline u16 pci_to_bdf(int bus, int dev, int fn) { + return (bus<<8) | (dev<<3) | fn; +} +static inline u16 pci_bus_devfn_to_bdf(int bus, u16 devfn) { + return (bus << 8) | devfn; +} + +void pci_config_writel(u16 bdf, u32 addr, u32 val); +void pci_config_writew(u16 bdf, u32 addr, u16 val); +void pci_config_writeb(u16 bdf, u32 addr, u8 val); +u32 pci_config_readl(u16 bdf, u32 addr); +u16 pci_config_readw(u16 bdf, u32 addr); +u8 pci_config_readb(u16 bdf, u32 addr); +void pci_config_maskw(u16 bdf, u32 addr, u16 off, u16 on); + +struct pci_device *pci_find_device(u16 vendid, u16 devid); +struct pci_device *pci_find_class(u16 classid); + +struct pci_device { + u16 bdf; + u8 rootbus; + struct pci_device *next; + struct pci_device *parent; + + // Configuration space device information + u16 vendor, device; + u16 class; + u8 prog_if, revision; + u8 header_type; + u8 secondary_bus; + struct { + u32 addr; + u32 size; + int is64; + } bars[PCI_NUM_REGIONS]; + + // Local information on device. + int have_driver; +}; +extern struct pci_device *PCIDevices; +extern int MaxPCIBus; +int pci_probe_host(void); +void pci_probe_devices(void); +static inline u32 pci_classprog(struct pci_device *pci) { + return (pci->class << 8) | pci->prog_if; +} + +#define foreachpci(PCI) \ + for (PCI=PCIDevices; PCI; PCI=PCI->next) + +int pci_next(int bdf, int bus); +#define foreachbdf(BDF, BUS) \ + for (BDF=pci_next(pci_bus_devfn_to_bdf((BUS), 0)-1, (BUS)) \ + ; BDF >= 0 \ + ; BDF=pci_next(BDF, (BUS))) + +#define PCI_ANY_ID (~0) +struct pci_device_id { + u32 vendid; + u32 devid; + u32 class; + u32 class_mask; + void (*func)(struct pci_device *pci, void *arg); +}; + +#define PCI_DEVICE(vendor_id, device_id, init_func) \ + { \ + .vendid = (vendor_id), \ + .devid = (device_id), \ + .class = PCI_ANY_ID, \ + .class_mask = 0, \ + .func = (init_func) \ + } + +#define PCI_DEVICE_CLASS(vendor_id, device_id, class_code, init_func) \ + { \ + .vendid = (vendor_id), \ + .devid = (device_id), \ + .class = (class_code), \ + .class_mask = ~0, \ + .func = (init_func) \ + } + +#define PCI_DEVICE_END \ + { \ + .vendid = 0, \ + } + +int pci_init_device(const struct pci_device_id *ids + , struct pci_device *pci, void *arg); +struct pci_device *pci_find_init_device(const struct pci_device_id *ids + , void *arg); +void pci_reboot(void); + +// helper functions to access pci mmio bars from real mode +u32 pci_readl(u32 addr); +void pci_writel(u32 addr, u32 val); + +// pirtable.c +void create_pirtable(void); + + +/**************************************************************** + * PIR table + ****************************************************************/ + +extern u16 PirOffset; + +struct link_info { + u8 link; + u16 bitmap; +} PACKED; + +struct pir_slot { + u8 bus; + u8 dev; + struct link_info links[4]; + u8 slot_nr; + u8 reserved; +} PACKED; + +struct pir_header { + u32 signature; + u16 version; + u16 size; + u8 router_bus; + u8 router_devfunc; + u16 exclusive_irqs; + u32 compatible_devid; + u32 miniport_data; + u8 reserved[11]; + u8 checksum; + struct pir_slot slots[0]; +} PACKED; + +#define PIR_SIGNATURE 0x52495024 // $PIR + + +#endif diff --git a/bios/seabios/src/pci_ids.h b/bios/seabios/src/pci_ids.h new file mode 100644 index 0000000..e1cded2 --- /dev/null +++ b/bios/seabios/src/pci_ids.h @@ -0,0 +1,2610 @@ +/* + * PCI Class, Vendor and Device IDs + * + * Please keep sorted. + */ + +/* Device classes and subclasses */ + +#define PCI_CLASS_NOT_DEFINED 0x0000 +#define PCI_CLASS_NOT_DEFINED_VGA 0x0001 + +#define PCI_BASE_CLASS_STORAGE 0x01 +#define PCI_CLASS_STORAGE_SCSI 0x0100 +#define PCI_CLASS_STORAGE_IDE 0x0101 +#define PCI_CLASS_STORAGE_FLOPPY 0x0102 +#define PCI_CLASS_STORAGE_IPI 0x0103 +#define PCI_CLASS_STORAGE_RAID 0x0104 +#define PCI_CLASS_STORAGE_SATA 0x0106 +#define PCI_CLASS_STORAGE_SATA_AHCI 0x010601 +#define PCI_CLASS_STORAGE_SAS 0x0107 +#define PCI_CLASS_STORAGE_OTHER 0x0180 + +#define PCI_BASE_CLASS_NETWORK 0x02 +#define PCI_CLASS_NETWORK_ETHERNET 0x0200 +#define PCI_CLASS_NETWORK_TOKEN_RING 0x0201 +#define PCI_CLASS_NETWORK_FDDI 0x0202 +#define PCI_CLASS_NETWORK_ATM 0x0203 +#define PCI_CLASS_NETWORK_OTHER 0x0280 + +#define PCI_BASE_CLASS_DISPLAY 0x03 +#define PCI_CLASS_DISPLAY_VGA 0x0300 +#define PCI_CLASS_DISPLAY_XGA 0x0301 +#define PCI_CLASS_DISPLAY_3D 0x0302 +#define PCI_CLASS_DISPLAY_OTHER 0x0380 + +#define PCI_BASE_CLASS_MULTIMEDIA 0x04 +#define PCI_CLASS_MULTIMEDIA_VIDEO 0x0400 +#define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401 +#define PCI_CLASS_MULTIMEDIA_PHONE 0x0402 +#define PCI_CLASS_MULTIMEDIA_OTHER 0x0480 + +#define PCI_BASE_CLASS_MEMORY 0x05 +#define PCI_CLASS_MEMORY_RAM 0x0500 +#define PCI_CLASS_MEMORY_FLASH 0x0501 +#define PCI_CLASS_MEMORY_OTHER 0x0580 + +#define PCI_BASE_CLASS_BRIDGE 0x06 +#define PCI_CLASS_BRIDGE_HOST 0x0600 +#define PCI_CLASS_BRIDGE_ISA 0x0601 +#define PCI_CLASS_BRIDGE_EISA 0x0602 +#define PCI_CLASS_BRIDGE_MC 0x0603 +#define PCI_CLASS_BRIDGE_PCI 0x0604 +#define PCI_CLASS_BRIDGE_PCMCIA 0x0605 +#define PCI_CLASS_BRIDGE_NUBUS 0x0606 +#define PCI_CLASS_BRIDGE_CARDBUS 0x0607 +#define PCI_CLASS_BRIDGE_RACEWAY 0x0608 +#define PCI_CLASS_BRIDGE_OTHER 0x0680 + +#define PCI_BASE_CLASS_COMMUNICATION 0x07 +#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700 +#define PCI_CLASS_COMMUNICATION_PARALLEL 0x0701 +#define PCI_CLASS_COMMUNICATION_MULTISERIAL 0x0702 +#define PCI_CLASS_COMMUNICATION_MODEM 0x0703 +#define PCI_CLASS_COMMUNICATION_OTHER 0x0780 + +#define PCI_BASE_CLASS_SYSTEM 0x08 +#define PCI_CLASS_SYSTEM_PIC 0x0800 +#define PCI_CLASS_SYSTEM_PIC_IOAPIC 0x080010 +#define PCI_CLASS_SYSTEM_PIC_IOXAPIC 0x080020 +#define PCI_CLASS_SYSTEM_DMA 0x0801 +#define PCI_CLASS_SYSTEM_TIMER 0x0802 +#define PCI_CLASS_SYSTEM_RTC 0x0803 +#define PCI_CLASS_SYSTEM_PCI_HOTPLUG 0x0804 +#define PCI_CLASS_SYSTEM_SDHCI 0x0805 +#define PCI_CLASS_SYSTEM_OTHER 0x0880 + +#define PCI_BASE_CLASS_INPUT 0x09 +#define PCI_CLASS_INPUT_KEYBOARD 0x0900 +#define PCI_CLASS_INPUT_PEN 0x0901 +#define PCI_CLASS_INPUT_MOUSE 0x0902 +#define PCI_CLASS_INPUT_SCANNER 0x0903 +#define PCI_CLASS_INPUT_GAMEPORT 0x0904 +#define PCI_CLASS_INPUT_OTHER 0x0980 + +#define PCI_BASE_CLASS_DOCKING 0x0a +#define PCI_CLASS_DOCKING_GENERIC 0x0a00 +#define PCI_CLASS_DOCKING_OTHER 0x0a80 + +#define PCI_BASE_CLASS_PROCESSOR 0x0b +#define PCI_CLASS_PROCESSOR_386 0x0b00 +#define PCI_CLASS_PROCESSOR_486 0x0b01 +#define PCI_CLASS_PROCESSOR_PENTIUM 0x0b02 +#define PCI_CLASS_PROCESSOR_ALPHA 0x0b10 +#define PCI_CLASS_PROCESSOR_POWERPC 0x0b20 +#define PCI_CLASS_PROCESSOR_MIPS 0x0b30 +#define PCI_CLASS_PROCESSOR_CO 0x0b40 + +#define PCI_BASE_CLASS_SERIAL 0x0c +#define PCI_CLASS_SERIAL_FIREWIRE 0x0c00 +#define PCI_CLASS_SERIAL_FIREWIRE_OHCI 0x0c0010 +#define PCI_CLASS_SERIAL_ACCESS 0x0c01 +#define PCI_CLASS_SERIAL_SSA 0x0c02 +#define PCI_CLASS_SERIAL_USB 0x0c03 +#define PCI_CLASS_SERIAL_USB_UHCI 0x0c0300 +#define PCI_CLASS_SERIAL_USB_OHCI 0x0c0310 +#define PCI_CLASS_SERIAL_USB_EHCI 0x0c0320 +#define PCI_CLASS_SERIAL_FIBER 0x0c04 +#define PCI_CLASS_SERIAL_SMBUS 0x0c05 + +#define PCI_BASE_CLASS_WIRELESS 0x0d +#define PCI_CLASS_WIRELESS_RF_CONTROLLER 0x0d10 +#define PCI_CLASS_WIRELESS_WHCI 0x0d1010 + +#define PCI_BASE_CLASS_INTELLIGENT 0x0e +#define PCI_CLASS_INTELLIGENT_I2O 0x0e00 + +#define PCI_BASE_CLASS_SATELLITE 0x0f +#define PCI_CLASS_SATELLITE_TV 0x0f00 +#define PCI_CLASS_SATELLITE_AUDIO 0x0f01 +#define PCI_CLASS_SATELLITE_VOICE 0x0f03 +#define PCI_CLASS_SATELLITE_DATA 0x0f04 + +#define PCI_BASE_CLASS_CRYPT 0x10 +#define PCI_CLASS_CRYPT_NETWORK 0x1000 +#define PCI_CLASS_CRYPT_ENTERTAINMENT 0x1001 +#define PCI_CLASS_CRYPT_OTHER 0x1080 + +#define PCI_BASE_CLASS_SIGNAL_PROCESSING 0x11 +#define PCI_CLASS_SP_DPIO 0x1100 +#define PCI_CLASS_SP_OTHER 0x1180 + +#define PCI_CLASS_OTHERS 0xff + +/* Vendors and devices. Sort key: vendor first, device next. */ + +#define PCI_VENDOR_ID_TTTECH 0x0357 +#define PCI_DEVICE_ID_TTTECH_MC322 0x000a + +#define PCI_VENDOR_ID_DYNALINK 0x0675 +#define PCI_DEVICE_ID_DYNALINK_IS64PH 0x1702 + +#define PCI_VENDOR_ID_BERKOM 0x0871 +#define PCI_DEVICE_ID_BERKOM_A1T 0xffa1 +#define PCI_DEVICE_ID_BERKOM_T_CONCEPT 0xffa2 +#define PCI_DEVICE_ID_BERKOM_A4T 0xffa4 +#define PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO 0xffa8 + +#define PCI_VENDOR_ID_COMPAQ 0x0e11 +#define PCI_DEVICE_ID_COMPAQ_TOKENRING 0x0508 +#define PCI_DEVICE_ID_COMPAQ_TACHYON 0xa0fc +#define PCI_DEVICE_ID_COMPAQ_SMART2P 0xae10 +#define PCI_DEVICE_ID_COMPAQ_NETEL100 0xae32 +#define PCI_DEVICE_ID_COMPAQ_NETEL10 0xae34 +#define PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE 0xae33 +#define PCI_DEVICE_ID_COMPAQ_NETFLEX3I 0xae35 +#define PCI_DEVICE_ID_COMPAQ_NETEL100D 0xae40 +#define PCI_DEVICE_ID_COMPAQ_NETEL100PI 0xae43 +#define PCI_DEVICE_ID_COMPAQ_NETEL100I 0xb011 +#define PCI_DEVICE_ID_COMPAQ_CISS 0xb060 +#define PCI_DEVICE_ID_COMPAQ_CISSB 0xb178 +#define PCI_DEVICE_ID_COMPAQ_CISSC 0x46 +#define PCI_DEVICE_ID_COMPAQ_THUNDER 0xf130 +#define PCI_DEVICE_ID_COMPAQ_NETFLEX3B 0xf150 + +#define PCI_VENDOR_ID_NCR 0x1000 +#define PCI_VENDOR_ID_LSI_LOGIC 0x1000 +#define PCI_DEVICE_ID_NCR_53C810 0x0001 +#define PCI_DEVICE_ID_NCR_53C820 0x0002 +#define PCI_DEVICE_ID_NCR_53C825 0x0003 +#define PCI_DEVICE_ID_NCR_53C815 0x0004 +#define PCI_DEVICE_ID_LSI_53C810AP 0x0005 +#define PCI_DEVICE_ID_NCR_53C860 0x0006 +#define PCI_DEVICE_ID_LSI_53C1510 0x000a +#define PCI_DEVICE_ID_NCR_53C896 0x000b +#define PCI_DEVICE_ID_NCR_53C895 0x000c +#define PCI_DEVICE_ID_NCR_53C885 0x000d +#define PCI_DEVICE_ID_NCR_53C875 0x000f +#define PCI_DEVICE_ID_NCR_53C1510 0x0010 +#define PCI_DEVICE_ID_LSI_53C895A 0x0012 +#define PCI_DEVICE_ID_LSI_53C875A 0x0013 +#define PCI_DEVICE_ID_LSI_53C1010_33 0x0020 +#define PCI_DEVICE_ID_LSI_53C1010_66 0x0021 +#define PCI_DEVICE_ID_LSI_53C1030 0x0030 +#define PCI_DEVICE_ID_LSI_1030_53C1035 0x0032 +#define PCI_DEVICE_ID_LSI_53C1035 0x0040 +#define PCI_DEVICE_ID_NCR_53C875J 0x008f +#define PCI_DEVICE_ID_LSI_FC909 0x0621 +#define PCI_DEVICE_ID_LSI_FC929 0x0622 +#define PCI_DEVICE_ID_LSI_FC929_LAN 0x0623 +#define PCI_DEVICE_ID_LSI_FC919 0x0624 +#define PCI_DEVICE_ID_LSI_FC919_LAN 0x0625 +#define PCI_DEVICE_ID_LSI_FC929X 0x0626 +#define PCI_DEVICE_ID_LSI_FC939X 0x0642 +#define PCI_DEVICE_ID_LSI_FC949X 0x0640 +#define PCI_DEVICE_ID_LSI_FC949ES 0x0646 +#define PCI_DEVICE_ID_LSI_FC919X 0x0628 +#define PCI_DEVICE_ID_NCR_YELLOWFIN 0x0701 +#define PCI_DEVICE_ID_LSI_61C102 0x0901 +#define PCI_DEVICE_ID_LSI_63C815 0x1000 +#define PCI_DEVICE_ID_LSI_SAS1064 0x0050 +#define PCI_DEVICE_ID_LSI_SAS1064R 0x0411 +#define PCI_DEVICE_ID_LSI_SAS1066 0x005E +#define PCI_DEVICE_ID_LSI_SAS1068 0x0054 +#define PCI_DEVICE_ID_LSI_SAS1064A 0x005C +#define PCI_DEVICE_ID_LSI_SAS1064E 0x0056 +#define PCI_DEVICE_ID_LSI_SAS1066E 0x005A +#define PCI_DEVICE_ID_LSI_SAS1068E 0x0058 +#define PCI_DEVICE_ID_LSI_SAS1078 0x0060 + +#define PCI_VENDOR_ID_ATI 0x1002 +/* Mach64 */ +#define PCI_DEVICE_ID_ATI_68800 0x4158 +#define PCI_DEVICE_ID_ATI_215CT222 0x4354 +#define PCI_DEVICE_ID_ATI_210888CX 0x4358 +#define PCI_DEVICE_ID_ATI_215ET222 0x4554 +/* Mach64 / Rage */ +#define PCI_DEVICE_ID_ATI_215GB 0x4742 +#define PCI_DEVICE_ID_ATI_215GD 0x4744 +#define PCI_DEVICE_ID_ATI_215GI 0x4749 +#define PCI_DEVICE_ID_ATI_215GP 0x4750 +#define PCI_DEVICE_ID_ATI_215GQ 0x4751 +#define PCI_DEVICE_ID_ATI_215XL 0x4752 +#define PCI_DEVICE_ID_ATI_215GT 0x4754 +#define PCI_DEVICE_ID_ATI_215GTB 0x4755 +#define PCI_DEVICE_ID_ATI_215_IV 0x4756 +#define PCI_DEVICE_ID_ATI_215_IW 0x4757 +#define PCI_DEVICE_ID_ATI_215_IZ 0x475A +#define PCI_DEVICE_ID_ATI_210888GX 0x4758 +#define PCI_DEVICE_ID_ATI_215_LB 0x4c42 +#define PCI_DEVICE_ID_ATI_215_LD 0x4c44 +#define PCI_DEVICE_ID_ATI_215_LG 0x4c47 +#define PCI_DEVICE_ID_ATI_215_LI 0x4c49 +#define PCI_DEVICE_ID_ATI_215_LM 0x4c4D +#define PCI_DEVICE_ID_ATI_215_LN 0x4c4E +#define PCI_DEVICE_ID_ATI_215_LR 0x4c52 +#define PCI_DEVICE_ID_ATI_215_LS 0x4c53 +#define PCI_DEVICE_ID_ATI_264_LT 0x4c54 +/* Mach64 VT */ +#define PCI_DEVICE_ID_ATI_264VT 0x5654 +#define PCI_DEVICE_ID_ATI_264VU 0x5655 +#define PCI_DEVICE_ID_ATI_264VV 0x5656 +/* Rage128 GL */ +#define PCI_DEVICE_ID_ATI_RAGE128_RE 0x5245 +#define PCI_DEVICE_ID_ATI_RAGE128_RF 0x5246 +#define PCI_DEVICE_ID_ATI_RAGE128_RG 0x5247 +/* Rage128 VR */ +#define PCI_DEVICE_ID_ATI_RAGE128_RK 0x524b +#define PCI_DEVICE_ID_ATI_RAGE128_RL 0x524c +#define PCI_DEVICE_ID_ATI_RAGE128_SE 0x5345 +#define PCI_DEVICE_ID_ATI_RAGE128_SF 0x5346 +#define PCI_DEVICE_ID_ATI_RAGE128_SG 0x5347 +#define PCI_DEVICE_ID_ATI_RAGE128_SH 0x5348 +#define PCI_DEVICE_ID_ATI_RAGE128_SK 0x534b +#define PCI_DEVICE_ID_ATI_RAGE128_SL 0x534c +#define PCI_DEVICE_ID_ATI_RAGE128_SM 0x534d +#define PCI_DEVICE_ID_ATI_RAGE128_SN 0x534e +/* Rage128 Ultra */ +#define PCI_DEVICE_ID_ATI_RAGE128_TF 0x5446 +#define PCI_DEVICE_ID_ATI_RAGE128_TL 0x544c +#define PCI_DEVICE_ID_ATI_RAGE128_TR 0x5452 +#define PCI_DEVICE_ID_ATI_RAGE128_TS 0x5453 +#define PCI_DEVICE_ID_ATI_RAGE128_TT 0x5454 +#define PCI_DEVICE_ID_ATI_RAGE128_TU 0x5455 +/* Rage128 M3 */ +#define PCI_DEVICE_ID_ATI_RAGE128_LE 0x4c45 +#define PCI_DEVICE_ID_ATI_RAGE128_LF 0x4c46 +/* Rage128 M4 */ +#define PCI_DEVICE_ID_ATI_RAGE128_MF 0x4d46 +#define PCI_DEVICE_ID_ATI_RAGE128_ML 0x4d4c +/* Rage128 Pro GL */ +#define PCI_DEVICE_ID_ATI_RAGE128_PA 0x5041 +#define PCI_DEVICE_ID_ATI_RAGE128_PB 0x5042 +#define PCI_DEVICE_ID_ATI_RAGE128_PC 0x5043 +#define PCI_DEVICE_ID_ATI_RAGE128_PD 0x5044 +#define PCI_DEVICE_ID_ATI_RAGE128_PE 0x5045 +#define PCI_DEVICE_ID_ATI_RAGE128_PF 0x5046 +/* Rage128 Pro VR */ +#define PCI_DEVICE_ID_ATI_RAGE128_PG 0x5047 +#define PCI_DEVICE_ID_ATI_RAGE128_PH 0x5048 +#define PCI_DEVICE_ID_ATI_RAGE128_PI 0x5049 +#define PCI_DEVICE_ID_ATI_RAGE128_PJ 0x504A +#define PCI_DEVICE_ID_ATI_RAGE128_PK 0x504B +#define PCI_DEVICE_ID_ATI_RAGE128_PL 0x504C +#define PCI_DEVICE_ID_ATI_RAGE128_PM 0x504D +#define PCI_DEVICE_ID_ATI_RAGE128_PN 0x504E +#define PCI_DEVICE_ID_ATI_RAGE128_PO 0x504F +#define PCI_DEVICE_ID_ATI_RAGE128_PP 0x5050 +#define PCI_DEVICE_ID_ATI_RAGE128_PQ 0x5051 +#define PCI_DEVICE_ID_ATI_RAGE128_PR 0x5052 +#define PCI_DEVICE_ID_ATI_RAGE128_PS 0x5053 +#define PCI_DEVICE_ID_ATI_RAGE128_PT 0x5054 +#define PCI_DEVICE_ID_ATI_RAGE128_PU 0x5055 +#define PCI_DEVICE_ID_ATI_RAGE128_PV 0x5056 +#define PCI_DEVICE_ID_ATI_RAGE128_PW 0x5057 +#define PCI_DEVICE_ID_ATI_RAGE128_PX 0x5058 +/* Rage128 M4 */ +/* Radeon R100 */ +#define PCI_DEVICE_ID_ATI_RADEON_QD 0x5144 +#define PCI_DEVICE_ID_ATI_RADEON_QE 0x5145 +#define PCI_DEVICE_ID_ATI_RADEON_QF 0x5146 +#define PCI_DEVICE_ID_ATI_RADEON_QG 0x5147 +/* Radeon RV100 (VE) */ +#define PCI_DEVICE_ID_ATI_RADEON_QY 0x5159 +#define PCI_DEVICE_ID_ATI_RADEON_QZ 0x515a +/* Radeon R200 (8500) */ +#define PCI_DEVICE_ID_ATI_RADEON_QL 0x514c +#define PCI_DEVICE_ID_ATI_RADEON_QN 0x514e +#define PCI_DEVICE_ID_ATI_RADEON_QO 0x514f +#define PCI_DEVICE_ID_ATI_RADEON_Ql 0x516c +#define PCI_DEVICE_ID_ATI_RADEON_BB 0x4242 +/* Radeon R200 (9100) */ +#define PCI_DEVICE_ID_ATI_RADEON_QM 0x514d +/* Radeon RV200 (7500) */ +#define PCI_DEVICE_ID_ATI_RADEON_QW 0x5157 +#define PCI_DEVICE_ID_ATI_RADEON_QX 0x5158 +/* Radeon NV-100 */ +/* Radeon RV250 (9000) */ +#define PCI_DEVICE_ID_ATI_RADEON_Id 0x4964 +#define PCI_DEVICE_ID_ATI_RADEON_Ie 0x4965 +#define PCI_DEVICE_ID_ATI_RADEON_If 0x4966 +#define PCI_DEVICE_ID_ATI_RADEON_Ig 0x4967 +/* Radeon RV280 (9200) */ +#define PCI_DEVICE_ID_ATI_RADEON_Ya 0x5961 +#define PCI_DEVICE_ID_ATI_RADEON_Yd 0x5964 +/* Radeon R300 (9500) */ +/* Radeon R300 (9700) */ +#define PCI_DEVICE_ID_ATI_RADEON_ND 0x4e44 +#define PCI_DEVICE_ID_ATI_RADEON_NE 0x4e45 +#define PCI_DEVICE_ID_ATI_RADEON_NF 0x4e46 +#define PCI_DEVICE_ID_ATI_RADEON_NG 0x4e47 +/* Radeon R350 (9800) */ +/* Radeon RV350 (9600) */ +/* Radeon M6 */ +#define PCI_DEVICE_ID_ATI_RADEON_LY 0x4c59 +#define PCI_DEVICE_ID_ATI_RADEON_LZ 0x4c5a +/* Radeon M7 */ +#define PCI_DEVICE_ID_ATI_RADEON_LW 0x4c57 +#define PCI_DEVICE_ID_ATI_RADEON_LX 0x4c58 +/* Radeon M9 */ +#define PCI_DEVICE_ID_ATI_RADEON_Ld 0x4c64 +#define PCI_DEVICE_ID_ATI_RADEON_Le 0x4c65 +#define PCI_DEVICE_ID_ATI_RADEON_Lf 0x4c66 +#define PCI_DEVICE_ID_ATI_RADEON_Lg 0x4c67 +/* Radeon */ +/* RadeonIGP */ +#define PCI_DEVICE_ID_ATI_RS100 0xcab0 +#define PCI_DEVICE_ID_ATI_RS200 0xcab2 +#define PCI_DEVICE_ID_ATI_RS200_B 0xcbb2 +#define PCI_DEVICE_ID_ATI_RS250 0xcab3 +#define PCI_DEVICE_ID_ATI_RS300_100 0x5830 +#define PCI_DEVICE_ID_ATI_RS300_133 0x5831 +#define PCI_DEVICE_ID_ATI_RS300_166 0x5832 +#define PCI_DEVICE_ID_ATI_RS300_200 0x5833 +#define PCI_DEVICE_ID_ATI_RS350_100 0x7830 +#define PCI_DEVICE_ID_ATI_RS350_133 0x7831 +#define PCI_DEVICE_ID_ATI_RS350_166 0x7832 +#define PCI_DEVICE_ID_ATI_RS350_200 0x7833 +#define PCI_DEVICE_ID_ATI_RS400_100 0x5a30 +#define PCI_DEVICE_ID_ATI_RS400_133 0x5a31 +#define PCI_DEVICE_ID_ATI_RS400_166 0x5a32 +#define PCI_DEVICE_ID_ATI_RS400_200 0x5a33 +#define PCI_DEVICE_ID_ATI_RS480 0x5950 +/* ATI IXP Chipset */ +#define PCI_DEVICE_ID_ATI_IXP200_IDE 0x4349 +#define PCI_DEVICE_ID_ATI_IXP200_SMBUS 0x4353 +#define PCI_DEVICE_ID_ATI_IXP300_SMBUS 0x4363 +#define PCI_DEVICE_ID_ATI_IXP300_IDE 0x4369 +#define PCI_DEVICE_ID_ATI_IXP300_SATA 0x436e +#define PCI_DEVICE_ID_ATI_IXP400_SMBUS 0x4372 +#define PCI_DEVICE_ID_ATI_IXP400_IDE 0x4376 +#define PCI_DEVICE_ID_ATI_IXP400_SATA 0x4379 +#define PCI_DEVICE_ID_ATI_IXP400_SATA2 0x437a +#define PCI_DEVICE_ID_ATI_IXP600_SATA 0x4380 +#define PCI_DEVICE_ID_ATI_SBX00_SMBUS 0x4385 +#define PCI_DEVICE_ID_ATI_IXP600_IDE 0x438c +#define PCI_DEVICE_ID_ATI_IXP700_SATA 0x4390 +#define PCI_DEVICE_ID_ATI_IXP700_IDE 0x439c + +#define PCI_VENDOR_ID_VLSI 0x1004 +#define PCI_DEVICE_ID_VLSI_82C592 0x0005 +#define PCI_DEVICE_ID_VLSI_82C593 0x0006 +#define PCI_DEVICE_ID_VLSI_82C594 0x0007 +#define PCI_DEVICE_ID_VLSI_82C597 0x0009 +#define PCI_DEVICE_ID_VLSI_82C541 0x000c +#define PCI_DEVICE_ID_VLSI_82C543 0x000d +#define PCI_DEVICE_ID_VLSI_82C532 0x0101 +#define PCI_DEVICE_ID_VLSI_82C534 0x0102 +#define PCI_DEVICE_ID_VLSI_82C535 0x0104 +#define PCI_DEVICE_ID_VLSI_82C147 0x0105 +#define PCI_DEVICE_ID_VLSI_VAS96011 0x0702 + +#define PCI_VENDOR_ID_ADL 0x1005 +#define PCI_DEVICE_ID_ADL_2301 0x2301 + +#define PCI_VENDOR_ID_NS 0x100b +#define PCI_DEVICE_ID_NS_87415 0x0002 +#define PCI_DEVICE_ID_NS_87560_LIO 0x000e +#define PCI_DEVICE_ID_NS_87560_USB 0x0012 +#define PCI_DEVICE_ID_NS_83815 0x0020 +#define PCI_DEVICE_ID_NS_83820 0x0022 +#define PCI_DEVICE_ID_NS_CS5535_ISA 0x002b +#define PCI_DEVICE_ID_NS_CS5535_IDE 0x002d +#define PCI_DEVICE_ID_NS_CS5535_AUDIO 0x002e +#define PCI_DEVICE_ID_NS_CS5535_USB 0x002f +#define PCI_DEVICE_ID_NS_GX_VIDEO 0x0030 +#define PCI_DEVICE_ID_NS_SATURN 0x0035 +#define PCI_DEVICE_ID_NS_SCx200_BRIDGE 0x0500 +#define PCI_DEVICE_ID_NS_SCx200_SMI 0x0501 +#define PCI_DEVICE_ID_NS_SCx200_IDE 0x0502 +#define PCI_DEVICE_ID_NS_SCx200_AUDIO 0x0503 +#define PCI_DEVICE_ID_NS_SCx200_VIDEO 0x0504 +#define PCI_DEVICE_ID_NS_SCx200_XBUS 0x0505 +#define PCI_DEVICE_ID_NS_SC1100_BRIDGE 0x0510 +#define PCI_DEVICE_ID_NS_SC1100_SMI 0x0511 +#define PCI_DEVICE_ID_NS_SC1100_XBUS 0x0515 +#define PCI_DEVICE_ID_NS_87410 0xd001 + +#define PCI_DEVICE_ID_NS_GX_HOST_BRIDGE 0x0028 + +#define PCI_VENDOR_ID_TSENG 0x100c +#define PCI_DEVICE_ID_TSENG_W32P_2 0x3202 +#define PCI_DEVICE_ID_TSENG_W32P_b 0x3205 +#define PCI_DEVICE_ID_TSENG_W32P_c 0x3206 +#define PCI_DEVICE_ID_TSENG_W32P_d 0x3207 +#define PCI_DEVICE_ID_TSENG_ET6000 0x3208 + +#define PCI_VENDOR_ID_WEITEK 0x100e +#define PCI_DEVICE_ID_WEITEK_P9000 0x9001 +#define PCI_DEVICE_ID_WEITEK_P9100 0x9100 + +#define PCI_VENDOR_ID_DEC 0x1011 +#define PCI_DEVICE_ID_DEC_BRD 0x0001 +#define PCI_DEVICE_ID_DEC_TULIP 0x0002 +#define PCI_DEVICE_ID_DEC_TGA 0x0004 +#define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009 +#define PCI_DEVICE_ID_DEC_TGA2 0x000D +#define PCI_DEVICE_ID_DEC_FDDI 0x000F +#define PCI_DEVICE_ID_DEC_TULIP_PLUS 0x0014 +#define PCI_DEVICE_ID_DEC_21142 0x0019 +#define PCI_DEVICE_ID_DEC_21052 0x0021 +#define PCI_DEVICE_ID_DEC_21150 0x0022 +#define PCI_DEVICE_ID_DEC_21152 0x0024 +#define PCI_DEVICE_ID_DEC_21153 0x0025 +#define PCI_DEVICE_ID_DEC_21154 0x0026 +#define PCI_DEVICE_ID_DEC_21285 0x1065 +#define PCI_DEVICE_ID_COMPAQ_42XX 0x0046 + +#define PCI_VENDOR_ID_CIRRUS 0x1013 +#define PCI_DEVICE_ID_CIRRUS_7548 0x0038 +#define PCI_DEVICE_ID_CIRRUS_5430 0x00a0 +#define PCI_DEVICE_ID_CIRRUS_5434_4 0x00a4 +#define PCI_DEVICE_ID_CIRRUS_5434_8 0x00a8 +#define PCI_DEVICE_ID_CIRRUS_5436 0x00ac +#define PCI_DEVICE_ID_CIRRUS_5446 0x00b8 +#define PCI_DEVICE_ID_CIRRUS_5480 0x00bc +#define PCI_DEVICE_ID_CIRRUS_5462 0x00d0 +#define PCI_DEVICE_ID_CIRRUS_5464 0x00d4 +#define PCI_DEVICE_ID_CIRRUS_5465 0x00d6 +#define PCI_DEVICE_ID_CIRRUS_6729 0x1100 +#define PCI_DEVICE_ID_CIRRUS_6832 0x1110 +#define PCI_DEVICE_ID_CIRRUS_7543 0x1202 +#define PCI_DEVICE_ID_CIRRUS_4610 0x6001 +#define PCI_DEVICE_ID_CIRRUS_4612 0x6003 +#define PCI_DEVICE_ID_CIRRUS_4615 0x6004 + +#define PCI_VENDOR_ID_IBM 0x1014 +#define PCI_DEVICE_ID_IBM_TR 0x0018 +#define PCI_DEVICE_ID_IBM_TR_WAKE 0x003e +#define PCI_DEVICE_ID_IBM_CPC710_PCI64 0x00fc +#define PCI_DEVICE_ID_IBM_SNIPE 0x0180 +#define PCI_DEVICE_ID_IBM_CITRINE 0x028C +#define PCI_DEVICE_ID_IBM_GEMSTONE 0xB166 +#define PCI_DEVICE_ID_IBM_OBSIDIAN 0x02BD +#define PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1 0x0031 +#define PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2 0x0219 +#define PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX 0x021A +#define PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM 0x0251 +#define PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM_PCIE 0x0361 +#define PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL 0x252 + +#define PCI_VENDOR_ID_UNISYS 0x1018 +#define PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR 0x001C + +#define PCI_VENDOR_ID_COMPEX2 0x101a /* pci.ids says "AT&T GIS (NCR)" */ +#define PCI_DEVICE_ID_COMPEX2_100VG 0x0005 + +#define PCI_VENDOR_ID_WD 0x101c +#define PCI_DEVICE_ID_WD_90C 0xc24a + +#define PCI_VENDOR_ID_AMI 0x101e +#define PCI_DEVICE_ID_AMI_MEGARAID3 0x1960 +#define PCI_DEVICE_ID_AMI_MEGARAID 0x9010 +#define PCI_DEVICE_ID_AMI_MEGARAID2 0x9060 + +#define PCI_VENDOR_ID_AMD 0x1022 +#define PCI_DEVICE_ID_AMD_K8_NB 0x1100 +#define PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP 0x1101 +#define PCI_DEVICE_ID_AMD_K8_NB_MEMCTL 0x1102 +#define PCI_DEVICE_ID_AMD_K8_NB_MISC 0x1103 +#define PCI_DEVICE_ID_AMD_10H_NB_HT 0x1200 +#define PCI_DEVICE_ID_AMD_10H_NB_MAP 0x1201 +#define PCI_DEVICE_ID_AMD_10H_NB_DRAM 0x1202 +#define PCI_DEVICE_ID_AMD_10H_NB_MISC 0x1203 +#define PCI_DEVICE_ID_AMD_10H_NB_LINK 0x1204 +#define PCI_DEVICE_ID_AMD_11H_NB_HT 0x1300 +#define PCI_DEVICE_ID_AMD_11H_NB_MAP 0x1301 +#define PCI_DEVICE_ID_AMD_11H_NB_DRAM 0x1302 +#define PCI_DEVICE_ID_AMD_11H_NB_MISC 0x1303 +#define PCI_DEVICE_ID_AMD_11H_NB_LINK 0x1304 +#define PCI_DEVICE_ID_AMD_LANCE 0x2000 +#define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001 +#define PCI_DEVICE_ID_AMD_SCSI 0x2020 +#define PCI_DEVICE_ID_AMD_SERENADE 0x36c0 +#define PCI_DEVICE_ID_AMD_FE_GATE_7006 0x7006 +#define PCI_DEVICE_ID_AMD_FE_GATE_7007 0x7007 +#define PCI_DEVICE_ID_AMD_FE_GATE_700C 0x700C +#define PCI_DEVICE_ID_AMD_FE_GATE_700E 0x700E +#define PCI_DEVICE_ID_AMD_COBRA_7401 0x7401 +#define PCI_DEVICE_ID_AMD_VIPER_7409 0x7409 +#define PCI_DEVICE_ID_AMD_VIPER_740B 0x740B +#define PCI_DEVICE_ID_AMD_VIPER_7410 0x7410 +#define PCI_DEVICE_ID_AMD_VIPER_7411 0x7411 +#define PCI_DEVICE_ID_AMD_VIPER_7413 0x7413 +#define PCI_DEVICE_ID_AMD_VIPER_7440 0x7440 +#define PCI_DEVICE_ID_AMD_OPUS_7441 0x7441 +#define PCI_DEVICE_ID_AMD_OPUS_7443 0x7443 +#define PCI_DEVICE_ID_AMD_VIPER_7443 0x7443 +#define PCI_DEVICE_ID_AMD_OPUS_7445 0x7445 +#define PCI_DEVICE_ID_AMD_8111_LPC 0x7468 +#define PCI_DEVICE_ID_AMD_8111_IDE 0x7469 +#define PCI_DEVICE_ID_AMD_8111_SMBUS2 0x746a +#define PCI_DEVICE_ID_AMD_8111_SMBUS 0x746b +#define PCI_DEVICE_ID_AMD_8111_AUDIO 0x746d +#define PCI_DEVICE_ID_AMD_8151_0 0x7454 +#define PCI_DEVICE_ID_AMD_8131_BRIDGE 0x7450 +#define PCI_DEVICE_ID_AMD_8131_APIC 0x7451 +#define PCI_DEVICE_ID_AMD_8132_BRIDGE 0x7458 +#define PCI_DEVICE_ID_AMD_CS5536_ISA 0x2090 +#define PCI_DEVICE_ID_AMD_CS5536_FLASH 0x2091 +#define PCI_DEVICE_ID_AMD_CS5536_AUDIO 0x2093 +#define PCI_DEVICE_ID_AMD_CS5536_OHC 0x2094 +#define PCI_DEVICE_ID_AMD_CS5536_EHC 0x2095 +#define PCI_DEVICE_ID_AMD_CS5536_UDC 0x2096 +#define PCI_DEVICE_ID_AMD_CS5536_UOC 0x2097 +#define PCI_DEVICE_ID_AMD_CS5536_IDE 0x209A + +#define PCI_DEVICE_ID_AMD_LX_VIDEO 0x2081 +#define PCI_DEVICE_ID_AMD_LX_AES 0x2082 + +#define PCI_VENDOR_ID_TRIDENT 0x1023 +#define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000 +#define PCI_DEVICE_ID_TRIDENT_4DWAVE_NX 0x2001 +#define PCI_DEVICE_ID_TRIDENT_9320 0x9320 +#define PCI_DEVICE_ID_TRIDENT_9388 0x9388 +#define PCI_DEVICE_ID_TRIDENT_9397 0x9397 +#define PCI_DEVICE_ID_TRIDENT_939A 0x939A +#define PCI_DEVICE_ID_TRIDENT_9520 0x9520 +#define PCI_DEVICE_ID_TRIDENT_9525 0x9525 +#define PCI_DEVICE_ID_TRIDENT_9420 0x9420 +#define PCI_DEVICE_ID_TRIDENT_9440 0x9440 +#define PCI_DEVICE_ID_TRIDENT_9660 0x9660 +#define PCI_DEVICE_ID_TRIDENT_9750 0x9750 +#define PCI_DEVICE_ID_TRIDENT_9850 0x9850 +#define PCI_DEVICE_ID_TRIDENT_9880 0x9880 +#define PCI_DEVICE_ID_TRIDENT_8400 0x8400 +#define PCI_DEVICE_ID_TRIDENT_8420 0x8420 +#define PCI_DEVICE_ID_TRIDENT_8500 0x8500 + +#define PCI_VENDOR_ID_AI 0x1025 +#define PCI_DEVICE_ID_AI_M1435 0x1435 + +#define PCI_VENDOR_ID_DELL 0x1028 +#define PCI_DEVICE_ID_DELL_RACIII 0x0008 +#define PCI_DEVICE_ID_DELL_RAC4 0x0012 +#define PCI_DEVICE_ID_DELL_PERC5 0x0015 + +#define PCI_VENDOR_ID_MATROX 0x102B +#define PCI_DEVICE_ID_MATROX_MGA_2 0x0518 +#define PCI_DEVICE_ID_MATROX_MIL 0x0519 +#define PCI_DEVICE_ID_MATROX_MYS 0x051A +#define PCI_DEVICE_ID_MATROX_MIL_2 0x051b +#define PCI_DEVICE_ID_MATROX_MYS_AGP 0x051e +#define PCI_DEVICE_ID_MATROX_MIL_2_AGP 0x051f +#define PCI_DEVICE_ID_MATROX_MGA_IMP 0x0d10 +#define PCI_DEVICE_ID_MATROX_G100_MM 0x1000 +#define PCI_DEVICE_ID_MATROX_G100_AGP 0x1001 +#define PCI_DEVICE_ID_MATROX_G200_PCI 0x0520 +#define PCI_DEVICE_ID_MATROX_G200_AGP 0x0521 +#define PCI_DEVICE_ID_MATROX_G400 0x0525 +#define PCI_DEVICE_ID_MATROX_G200EV_PCI 0x0530 +#define PCI_DEVICE_ID_MATROX_G550 0x2527 +#define PCI_DEVICE_ID_MATROX_VIA 0x4536 + +#define PCI_VENDOR_ID_CT 0x102c +#define PCI_DEVICE_ID_CT_69000 0x00c0 +#define PCI_DEVICE_ID_CT_65545 0x00d8 +#define PCI_DEVICE_ID_CT_65548 0x00dc +#define PCI_DEVICE_ID_CT_65550 0x00e0 +#define PCI_DEVICE_ID_CT_65554 0x00e4 +#define PCI_DEVICE_ID_CT_65555 0x00e5 + +#define PCI_VENDOR_ID_MIRO 0x1031 +#define PCI_DEVICE_ID_MIRO_36050 0x5601 +#define PCI_DEVICE_ID_MIRO_DC10PLUS 0x7efe +#define PCI_DEVICE_ID_MIRO_DC30PLUS 0xd801 + +#define PCI_VENDOR_ID_NEC 0x1033 +#define PCI_DEVICE_ID_NEC_CBUS_1 0x0001 /* PCI-Cbus Bridge */ +#define PCI_DEVICE_ID_NEC_LOCAL 0x0002 /* Local Bridge */ +#define PCI_DEVICE_ID_NEC_ATM 0x0003 /* ATM LAN Controller */ +#define PCI_DEVICE_ID_NEC_R4000 0x0004 /* R4000 Bridge */ +#define PCI_DEVICE_ID_NEC_486 0x0005 /* 486 Like Peripheral Bus Bridge */ +#define PCI_DEVICE_ID_NEC_ACCEL_1 0x0006 /* Graphic Accelerator */ +#define PCI_DEVICE_ID_NEC_UXBUS 0x0007 /* UX-Bus Bridge */ +#define PCI_DEVICE_ID_NEC_ACCEL_2 0x0008 /* Graphic Accelerator */ +#define PCI_DEVICE_ID_NEC_GRAPH 0x0009 /* PCI-CoreGraph Bridge */ +#define PCI_DEVICE_ID_NEC_VL 0x0016 /* PCI-VL Bridge */ +#define PCI_DEVICE_ID_NEC_STARALPHA2 0x002c /* STAR ALPHA2 */ +#define PCI_DEVICE_ID_NEC_CBUS_2 0x002d /* PCI-Cbus Bridge */ +#define PCI_DEVICE_ID_NEC_USB 0x0035 /* PCI-USB Host */ +#define PCI_DEVICE_ID_NEC_CBUS_3 0x003b +#define PCI_DEVICE_ID_NEC_NAPCCARD 0x003e +#define PCI_DEVICE_ID_NEC_PCX2 0x0046 /* PowerVR */ +#define PCI_DEVICE_ID_NEC_VRC5476 0x009b +#define PCI_DEVICE_ID_NEC_VRC4173 0x00a5 +#define PCI_DEVICE_ID_NEC_VRC5477_AC97 0x00a6 +#define PCI_DEVICE_ID_NEC_PC9821CS01 0x800c /* PC-9821-CS01 */ +#define PCI_DEVICE_ID_NEC_PC9821NRB06 0x800d /* PC-9821NR-B06 */ + +#define PCI_VENDOR_ID_FD 0x1036 +#define PCI_DEVICE_ID_FD_36C70 0x0000 + +#define PCI_VENDOR_ID_SI 0x1039 +#define PCI_DEVICE_ID_SI_5591_AGP 0x0001 +#define PCI_DEVICE_ID_SI_6202 0x0002 +#define PCI_DEVICE_ID_SI_503 0x0008 +#define PCI_DEVICE_ID_SI_ACPI 0x0009 +#define PCI_DEVICE_ID_SI_SMBUS 0x0016 +#define PCI_DEVICE_ID_SI_LPC 0x0018 +#define PCI_DEVICE_ID_SI_5597_VGA 0x0200 +#define PCI_DEVICE_ID_SI_6205 0x0205 +#define PCI_DEVICE_ID_SI_501 0x0406 +#define PCI_DEVICE_ID_SI_496 0x0496 +#define PCI_DEVICE_ID_SI_300 0x0300 +#define PCI_DEVICE_ID_SI_315H 0x0310 +#define PCI_DEVICE_ID_SI_315 0x0315 +#define PCI_DEVICE_ID_SI_315PRO 0x0325 +#define PCI_DEVICE_ID_SI_530 0x0530 +#define PCI_DEVICE_ID_SI_540 0x0540 +#define PCI_DEVICE_ID_SI_550 0x0550 +#define PCI_DEVICE_ID_SI_540_VGA 0x5300 +#define PCI_DEVICE_ID_SI_550_VGA 0x5315 +#define PCI_DEVICE_ID_SI_620 0x0620 +#define PCI_DEVICE_ID_SI_630 0x0630 +#define PCI_DEVICE_ID_SI_633 0x0633 +#define PCI_DEVICE_ID_SI_635 0x0635 +#define PCI_DEVICE_ID_SI_640 0x0640 +#define PCI_DEVICE_ID_SI_645 0x0645 +#define PCI_DEVICE_ID_SI_646 0x0646 +#define PCI_DEVICE_ID_SI_648 0x0648 +#define PCI_DEVICE_ID_SI_650 0x0650 +#define PCI_DEVICE_ID_SI_651 0x0651 +#define PCI_DEVICE_ID_SI_655 0x0655 +#define PCI_DEVICE_ID_SI_661 0x0661 +#define PCI_DEVICE_ID_SI_730 0x0730 +#define PCI_DEVICE_ID_SI_733 0x0733 +#define PCI_DEVICE_ID_SI_630_VGA 0x6300 +#define PCI_DEVICE_ID_SI_735 0x0735 +#define PCI_DEVICE_ID_SI_740 0x0740 +#define PCI_DEVICE_ID_SI_741 0x0741 +#define PCI_DEVICE_ID_SI_745 0x0745 +#define PCI_DEVICE_ID_SI_746 0x0746 +#define PCI_DEVICE_ID_SI_755 0x0755 +#define PCI_DEVICE_ID_SI_760 0x0760 +#define PCI_DEVICE_ID_SI_900 0x0900 +#define PCI_DEVICE_ID_SI_961 0x0961 +#define PCI_DEVICE_ID_SI_962 0x0962 +#define PCI_DEVICE_ID_SI_963 0x0963 +#define PCI_DEVICE_ID_SI_965 0x0965 +#define PCI_DEVICE_ID_SI_966 0x0966 +#define PCI_DEVICE_ID_SI_968 0x0968 +#define PCI_DEVICE_ID_SI_1180 0x1180 +#define PCI_DEVICE_ID_SI_5511 0x5511 +#define PCI_DEVICE_ID_SI_5513 0x5513 +#define PCI_DEVICE_ID_SI_5517 0x5517 +#define PCI_DEVICE_ID_SI_5518 0x5518 +#define PCI_DEVICE_ID_SI_5571 0x5571 +#define PCI_DEVICE_ID_SI_5581 0x5581 +#define PCI_DEVICE_ID_SI_5582 0x5582 +#define PCI_DEVICE_ID_SI_5591 0x5591 +#define PCI_DEVICE_ID_SI_5596 0x5596 +#define PCI_DEVICE_ID_SI_5597 0x5597 +#define PCI_DEVICE_ID_SI_5598 0x5598 +#define PCI_DEVICE_ID_SI_5600 0x5600 +#define PCI_DEVICE_ID_SI_7012 0x7012 +#define PCI_DEVICE_ID_SI_7013 0x7013 +#define PCI_DEVICE_ID_SI_7016 0x7016 +#define PCI_DEVICE_ID_SI_7018 0x7018 + +#define PCI_VENDOR_ID_HP 0x103c +#define PCI_DEVICE_ID_HP_VISUALIZE_EG 0x1005 +#define PCI_DEVICE_ID_HP_VISUALIZE_FX6 0x1006 +#define PCI_DEVICE_ID_HP_VISUALIZE_FX4 0x1008 +#define PCI_DEVICE_ID_HP_VISUALIZE_FX2 0x100a +#define PCI_DEVICE_ID_HP_TACHYON 0x1028 +#define PCI_DEVICE_ID_HP_TACHLITE 0x1029 +#define PCI_DEVICE_ID_HP_J2585A 0x1030 +#define PCI_DEVICE_ID_HP_J2585B 0x1031 +#define PCI_DEVICE_ID_HP_J2973A 0x1040 +#define PCI_DEVICE_ID_HP_J2970A 0x1042 +#define PCI_DEVICE_ID_HP_DIVA 0x1048 +#define PCI_DEVICE_ID_HP_DIVA_TOSCA1 0x1049 +#define PCI_DEVICE_ID_HP_DIVA_TOSCA2 0x104A +#define PCI_DEVICE_ID_HP_DIVA_MAESTRO 0x104B +#define PCI_DEVICE_ID_HP_REO_IOC 0x10f1 +#define PCI_DEVICE_ID_HP_VISUALIZE_FXE 0x108b +#define PCI_DEVICE_ID_HP_DIVA_HALFDOME 0x1223 +#define PCI_DEVICE_ID_HP_DIVA_KEYSTONE 0x1226 +#define PCI_DEVICE_ID_HP_DIVA_POWERBAR 0x1227 +#define PCI_DEVICE_ID_HP_ZX1_IOC 0x122a +#define PCI_DEVICE_ID_HP_PCIX_LBA 0x122e +#define PCI_DEVICE_ID_HP_SX1000_IOC 0x127c +#define PCI_DEVICE_ID_HP_DIVA_EVEREST 0x1282 +#define PCI_DEVICE_ID_HP_DIVA_AUX 0x1290 +#define PCI_DEVICE_ID_HP_DIVA_RMP3 0x1301 +#define PCI_DEVICE_ID_HP_DIVA_HURRICANE 0x132a +#define PCI_DEVICE_ID_HP_CISSA 0x3220 +#define PCI_DEVICE_ID_HP_CISSC 0x3230 +#define PCI_DEVICE_ID_HP_CISSD 0x3238 +#define PCI_DEVICE_ID_HP_CISSE 0x323a +#define PCI_DEVICE_ID_HP_ZX2_IOC 0x4031 + +#define PCI_VENDOR_ID_PCTECH 0x1042 +#define PCI_DEVICE_ID_PCTECH_RZ1000 0x1000 +#define PCI_DEVICE_ID_PCTECH_RZ1001 0x1001 +#define PCI_DEVICE_ID_PCTECH_SAMURAI_IDE 0x3020 + +#define PCI_VENDOR_ID_ASUSTEK 0x1043 +#define PCI_DEVICE_ID_ASUSTEK_0675 0x0675 + +#define PCI_VENDOR_ID_DPT 0x1044 +#define PCI_DEVICE_ID_DPT 0xa400 + +#define PCI_VENDOR_ID_OPTI 0x1045 +#define PCI_DEVICE_ID_OPTI_82C558 0xc558 +#define PCI_DEVICE_ID_OPTI_82C621 0xc621 +#define PCI_DEVICE_ID_OPTI_82C700 0xc700 +#define PCI_DEVICE_ID_OPTI_82C825 0xd568 + +#define PCI_VENDOR_ID_ELSA 0x1048 +#define PCI_DEVICE_ID_ELSA_MICROLINK 0x1000 +#define PCI_DEVICE_ID_ELSA_QS3000 0x3000 + +#define PCI_VENDOR_ID_BUSLOGIC 0x104B +#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140 +#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER 0x1040 +#define PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT 0x8130 + +#define PCI_VENDOR_ID_TI 0x104c +#define PCI_DEVICE_ID_TI_TVP4020 0x3d07 +#define PCI_DEVICE_ID_TI_4450 0x8011 +#define PCI_DEVICE_ID_TI_TSB43AB22 0x8023 +#define PCI_DEVICE_ID_TI_XX21_XX11 0x8031 +#define PCI_DEVICE_ID_TI_XX21_XX11_FM 0x8033 +#define PCI_DEVICE_ID_TI_XX21_XX11_SD 0x8034 +#define PCI_DEVICE_ID_TI_X515 0x8036 +#define PCI_DEVICE_ID_TI_XX12 0x8039 +#define PCI_DEVICE_ID_TI_XX12_FM 0x803b +#define PCI_DEVICE_ID_TI_1130 0xac12 +#define PCI_DEVICE_ID_TI_1031 0xac13 +#define PCI_DEVICE_ID_TI_1131 0xac15 +#define PCI_DEVICE_ID_TI_1250 0xac16 +#define PCI_DEVICE_ID_TI_1220 0xac17 +#define PCI_DEVICE_ID_TI_1221 0xac19 +#define PCI_DEVICE_ID_TI_1210 0xac1a +#define PCI_DEVICE_ID_TI_1450 0xac1b +#define PCI_DEVICE_ID_TI_1225 0xac1c +#define PCI_DEVICE_ID_TI_1251A 0xac1d +#define PCI_DEVICE_ID_TI_1211 0xac1e +#define PCI_DEVICE_ID_TI_1251B 0xac1f +#define PCI_DEVICE_ID_TI_4410 0xac41 +#define PCI_DEVICE_ID_TI_4451 0xac42 +#define PCI_DEVICE_ID_TI_4510 0xac44 +#define PCI_DEVICE_ID_TI_4520 0xac46 +#define PCI_DEVICE_ID_TI_7510 0xac47 +#define PCI_DEVICE_ID_TI_7610 0xac48 +#define PCI_DEVICE_ID_TI_7410 0xac49 +#define PCI_DEVICE_ID_TI_1410 0xac50 +#define PCI_DEVICE_ID_TI_1420 0xac51 +#define PCI_DEVICE_ID_TI_1451A 0xac52 +#define PCI_DEVICE_ID_TI_1620 0xac54 +#define PCI_DEVICE_ID_TI_1520 0xac55 +#define PCI_DEVICE_ID_TI_1510 0xac56 +#define PCI_DEVICE_ID_TI_X620 0xac8d +#define PCI_DEVICE_ID_TI_X420 0xac8e +#define PCI_DEVICE_ID_TI_XX20_FM 0xac8f + +#define PCI_VENDOR_ID_SONY 0x104d + +/* Winbond have two vendor IDs! See 0x10ad as well */ +#define PCI_VENDOR_ID_WINBOND2 0x1050 +#define PCI_DEVICE_ID_WINBOND2_89C940F 0x5a5a +#define PCI_DEVICE_ID_WINBOND2_6692 0x6692 + +#define PCI_VENDOR_ID_ANIGMA 0x1051 +#define PCI_DEVICE_ID_ANIGMA_MC145575 0x0100 + +#define PCI_VENDOR_ID_EFAR 0x1055 +#define PCI_DEVICE_ID_EFAR_SLC90E66_1 0x9130 +#define PCI_DEVICE_ID_EFAR_SLC90E66_3 0x9463 + +#define PCI_VENDOR_ID_MOTOROLA 0x1057 +#define PCI_DEVICE_ID_MOTOROLA_MPC105 0x0001 +#define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002 +#define PCI_DEVICE_ID_MOTOROLA_MPC107 0x0004 +#define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801 +#define PCI_DEVICE_ID_MOTOROLA_FALCON 0x4802 +#define PCI_DEVICE_ID_MOTOROLA_HAWK 0x4803 +#define PCI_DEVICE_ID_MOTOROLA_HARRIER 0x480b +#define PCI_DEVICE_ID_MOTOROLA_MPC5200 0x5803 +#define PCI_DEVICE_ID_MOTOROLA_MPC5200B 0x5809 + +#define PCI_VENDOR_ID_PROMISE 0x105a +#define PCI_DEVICE_ID_PROMISE_20265 0x0d30 +#define PCI_DEVICE_ID_PROMISE_20267 0x4d30 +#define PCI_DEVICE_ID_PROMISE_20246 0x4d33 +#define PCI_DEVICE_ID_PROMISE_20262 0x4d38 +#define PCI_DEVICE_ID_PROMISE_20263 0x0D38 +#define PCI_DEVICE_ID_PROMISE_20268 0x4d68 +#define PCI_DEVICE_ID_PROMISE_20269 0x4d69 +#define PCI_DEVICE_ID_PROMISE_20270 0x6268 +#define PCI_DEVICE_ID_PROMISE_20271 0x6269 +#define PCI_DEVICE_ID_PROMISE_20275 0x1275 +#define PCI_DEVICE_ID_PROMISE_20276 0x5275 +#define PCI_DEVICE_ID_PROMISE_20277 0x7275 + +#define PCI_VENDOR_ID_UMC 0x1060 +#define PCI_DEVICE_ID_UMC_UM8673F 0x0101 +#define PCI_DEVICE_ID_UMC_UM8886BF 0x673a +#define PCI_DEVICE_ID_UMC_UM8886A 0x886a + +#define PCI_VENDOR_ID_PICOPOWER 0x1066 +#define PCI_DEVICE_ID_PICOPOWER_PT86C523 0x0002 +#define PCI_DEVICE_ID_PICOPOWER_PT86C523BBP 0x8002 + +#define PCI_VENDOR_ID_MYLEX 0x1069 +#define PCI_DEVICE_ID_MYLEX_DAC960_P 0x0001 +#define PCI_DEVICE_ID_MYLEX_DAC960_PD 0x0002 +#define PCI_DEVICE_ID_MYLEX_DAC960_PG 0x0010 +#define PCI_DEVICE_ID_MYLEX_DAC960_LA 0x0020 +#define PCI_DEVICE_ID_MYLEX_DAC960_LP 0x0050 +#define PCI_DEVICE_ID_MYLEX_DAC960_BA 0xBA56 +#define PCI_DEVICE_ID_MYLEX_DAC960_GEM 0xB166 + +#define PCI_VENDOR_ID_APPLE 0x106b +#define PCI_DEVICE_ID_APPLE_BANDIT 0x0001 +#define PCI_DEVICE_ID_APPLE_HYDRA 0x000e +#define PCI_DEVICE_ID_APPLE_UNI_N_FW 0x0018 +#define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020 +#define PCI_DEVICE_ID_APPLE_UNI_N_GMAC 0x0021 +#define PCI_DEVICE_ID_APPLE_UNI_N_GMACP 0x0024 +#define PCI_DEVICE_ID_APPLE_UNI_N_AGP_P 0x0027 +#define PCI_DEVICE_ID_APPLE_UNI_N_AGP15 0x002d +#define PCI_DEVICE_ID_APPLE_UNI_N_PCI15 0x002e +#define PCI_DEVICE_ID_APPLE_UNI_N_GMAC2 0x0032 +#define PCI_DEVICE_ID_APPLE_UNI_N_ATA 0x0033 +#define PCI_DEVICE_ID_APPLE_UNI_N_AGP2 0x0034 +#define PCI_DEVICE_ID_APPLE_IPID_ATA100 0x003b +#define PCI_DEVICE_ID_APPLE_K2_ATA100 0x0043 +#define PCI_DEVICE_ID_APPLE_U3_AGP 0x004b +#define PCI_DEVICE_ID_APPLE_K2_GMAC 0x004c +#define PCI_DEVICE_ID_APPLE_SH_ATA 0x0050 +#define PCI_DEVICE_ID_APPLE_SH_SUNGEM 0x0051 +#define PCI_DEVICE_ID_APPLE_U3L_AGP 0x0058 +#define PCI_DEVICE_ID_APPLE_U3H_AGP 0x0059 +#define PCI_DEVICE_ID_APPLE_IPID2_AGP 0x0066 +#define PCI_DEVICE_ID_APPLE_IPID2_ATA 0x0069 +#define PCI_DEVICE_ID_APPLE_IPID2_FW 0x006a +#define PCI_DEVICE_ID_APPLE_IPID2_GMAC 0x006b +#define PCI_DEVICE_ID_APPLE_TIGON3 0x1645 + +#define PCI_VENDOR_ID_YAMAHA 0x1073 +#define PCI_DEVICE_ID_YAMAHA_724 0x0004 +#define PCI_DEVICE_ID_YAMAHA_724F 0x000d +#define PCI_DEVICE_ID_YAMAHA_740 0x000a +#define PCI_DEVICE_ID_YAMAHA_740C 0x000c +#define PCI_DEVICE_ID_YAMAHA_744 0x0010 +#define PCI_DEVICE_ID_YAMAHA_754 0x0012 + +#define PCI_VENDOR_ID_QLOGIC 0x1077 +#define PCI_DEVICE_ID_QLOGIC_ISP10160 0x1016 +#define PCI_DEVICE_ID_QLOGIC_ISP1020 0x1020 +#define PCI_DEVICE_ID_QLOGIC_ISP1080 0x1080 +#define PCI_DEVICE_ID_QLOGIC_ISP12160 0x1216 +#define PCI_DEVICE_ID_QLOGIC_ISP1240 0x1240 +#define PCI_DEVICE_ID_QLOGIC_ISP1280 0x1280 +#define PCI_DEVICE_ID_QLOGIC_ISP2100 0x2100 +#define PCI_DEVICE_ID_QLOGIC_ISP2200 0x2200 +#define PCI_DEVICE_ID_QLOGIC_ISP2300 0x2300 +#define PCI_DEVICE_ID_QLOGIC_ISP2312 0x2312 +#define PCI_DEVICE_ID_QLOGIC_ISP2322 0x2322 +#define PCI_DEVICE_ID_QLOGIC_ISP6312 0x6312 +#define PCI_DEVICE_ID_QLOGIC_ISP6322 0x6322 +#define PCI_DEVICE_ID_QLOGIC_ISP2422 0x2422 +#define PCI_DEVICE_ID_QLOGIC_ISP2432 0x2432 +#define PCI_DEVICE_ID_QLOGIC_ISP2512 0x2512 +#define PCI_DEVICE_ID_QLOGIC_ISP2522 0x2522 +#define PCI_DEVICE_ID_QLOGIC_ISP5422 0x5422 +#define PCI_DEVICE_ID_QLOGIC_ISP5432 0x5432 + +#define PCI_VENDOR_ID_CYRIX 0x1078 +#define PCI_DEVICE_ID_CYRIX_5510 0x0000 +#define PCI_DEVICE_ID_CYRIX_PCI_MASTER 0x0001 +#define PCI_DEVICE_ID_CYRIX_5520 0x0002 +#define PCI_DEVICE_ID_CYRIX_5530_LEGACY 0x0100 +#define PCI_DEVICE_ID_CYRIX_5530_IDE 0x0102 +#define PCI_DEVICE_ID_CYRIX_5530_AUDIO 0x0103 +#define PCI_DEVICE_ID_CYRIX_5530_VIDEO 0x0104 + +#define PCI_VENDOR_ID_CONTAQ 0x1080 +#define PCI_DEVICE_ID_CONTAQ_82C693 0xc693 + +#define PCI_VENDOR_ID_OLICOM 0x108d +#define PCI_DEVICE_ID_OLICOM_OC2325 0x0012 +#define PCI_DEVICE_ID_OLICOM_OC2183 0x0013 +#define PCI_DEVICE_ID_OLICOM_OC2326 0x0014 + +#define PCI_VENDOR_ID_SUN 0x108e +#define PCI_DEVICE_ID_SUN_EBUS 0x1000 +#define PCI_DEVICE_ID_SUN_HAPPYMEAL 0x1001 +#define PCI_DEVICE_ID_SUN_RIO_EBUS 0x1100 +#define PCI_DEVICE_ID_SUN_RIO_GEM 0x1101 +#define PCI_DEVICE_ID_SUN_RIO_1394 0x1102 +#define PCI_DEVICE_ID_SUN_RIO_USB 0x1103 +#define PCI_DEVICE_ID_SUN_GEM 0x2bad +#define PCI_DEVICE_ID_SUN_SIMBA 0x5000 +#define PCI_DEVICE_ID_SUN_PBM 0x8000 +#define PCI_DEVICE_ID_SUN_SCHIZO 0x8001 +#define PCI_DEVICE_ID_SUN_SABRE 0xa000 +#define PCI_DEVICE_ID_SUN_HUMMINGBIRD 0xa001 +#define PCI_DEVICE_ID_SUN_TOMATILLO 0xa801 +#define PCI_DEVICE_ID_SUN_CASSINI 0xabba + +#define PCI_VENDOR_ID_CMD 0x1095 +#define PCI_DEVICE_ID_CMD_643 0x0643 +#define PCI_DEVICE_ID_CMD_646 0x0646 +#define PCI_DEVICE_ID_CMD_648 0x0648 +#define PCI_DEVICE_ID_CMD_649 0x0649 + +#define PCI_DEVICE_ID_SII_680 0x0680 +#define PCI_DEVICE_ID_SII_3112 0x3112 +#define PCI_DEVICE_ID_SII_1210SA 0x0240 + +#define PCI_VENDOR_ID_BROOKTREE 0x109e +#define PCI_DEVICE_ID_BROOKTREE_878 0x0878 +#define PCI_DEVICE_ID_BROOKTREE_879 0x0879 + +#define PCI_VENDOR_ID_SGI 0x10a9 +#define PCI_DEVICE_ID_SGI_IOC3 0x0003 +#define PCI_DEVICE_ID_SGI_LITHIUM 0x1002 +#define PCI_DEVICE_ID_SGI_IOC4 0x100a + +#define PCI_VENDOR_ID_WINBOND 0x10ad +#define PCI_DEVICE_ID_WINBOND_82C105 0x0105 +#define PCI_DEVICE_ID_WINBOND_83C553 0x0565 + +#define PCI_VENDOR_ID_PLX 0x10b5 +#define PCI_DEVICE_ID_PLX_R685 0x1030 +#define PCI_DEVICE_ID_PLX_ROMULUS 0x106a +#define PCI_DEVICE_ID_PLX_SPCOM800 0x1076 +#define PCI_DEVICE_ID_PLX_1077 0x1077 +#define PCI_DEVICE_ID_PLX_SPCOM200 0x1103 +#define PCI_DEVICE_ID_PLX_DJINN_ITOO 0x1151 +#define PCI_DEVICE_ID_PLX_R753 0x1152 +#define PCI_DEVICE_ID_PLX_OLITEC 0x1187 +#define PCI_DEVICE_ID_PLX_PCI200SYN 0x3196 +#define PCI_DEVICE_ID_PLX_9030 0x9030 +#define PCI_DEVICE_ID_PLX_9050 0x9050 +#define PCI_DEVICE_ID_PLX_9080 0x9080 +#define PCI_DEVICE_ID_PLX_GTEK_SERIAL2 0xa001 + +#define PCI_VENDOR_ID_MADGE 0x10b6 +#define PCI_DEVICE_ID_MADGE_MK2 0x0002 + +#define PCI_VENDOR_ID_3COM 0x10b7 +#define PCI_DEVICE_ID_3COM_3C985 0x0001 +#define PCI_DEVICE_ID_3COM_3C940 0x1700 +#define PCI_DEVICE_ID_3COM_3C339 0x3390 +#define PCI_DEVICE_ID_3COM_3C359 0x3590 +#define PCI_DEVICE_ID_3COM_3C940B 0x80eb +#define PCI_DEVICE_ID_3COM_3CR990 0x9900 +#define PCI_DEVICE_ID_3COM_3CR990_TX_95 0x9902 +#define PCI_DEVICE_ID_3COM_3CR990_TX_97 0x9903 +#define PCI_DEVICE_ID_3COM_3CR990B 0x9904 +#define PCI_DEVICE_ID_3COM_3CR990_FX 0x9905 +#define PCI_DEVICE_ID_3COM_3CR990SVR95 0x9908 +#define PCI_DEVICE_ID_3COM_3CR990SVR97 0x9909 +#define PCI_DEVICE_ID_3COM_3CR990SVR 0x990a + +#define PCI_VENDOR_ID_AL 0x10b9 +#define PCI_DEVICE_ID_AL_M1533 0x1533 +#define PCI_DEVICE_ID_AL_M1535 0x1535 +#define PCI_DEVICE_ID_AL_M1541 0x1541 +#define PCI_DEVICE_ID_AL_M1563 0x1563 +#define PCI_DEVICE_ID_AL_M1621 0x1621 +#define PCI_DEVICE_ID_AL_M1631 0x1631 +#define PCI_DEVICE_ID_AL_M1632 0x1632 +#define PCI_DEVICE_ID_AL_M1641 0x1641 +#define PCI_DEVICE_ID_AL_M1644 0x1644 +#define PCI_DEVICE_ID_AL_M1647 0x1647 +#define PCI_DEVICE_ID_AL_M1651 0x1651 +#define PCI_DEVICE_ID_AL_M1671 0x1671 +#define PCI_DEVICE_ID_AL_M1681 0x1681 +#define PCI_DEVICE_ID_AL_M1683 0x1683 +#define PCI_DEVICE_ID_AL_M1689 0x1689 +#define PCI_DEVICE_ID_AL_M5219 0x5219 +#define PCI_DEVICE_ID_AL_M5228 0x5228 +#define PCI_DEVICE_ID_AL_M5229 0x5229 +#define PCI_DEVICE_ID_AL_M5451 0x5451 +#define PCI_DEVICE_ID_AL_M7101 0x7101 + +#define PCI_VENDOR_ID_NEOMAGIC 0x10c8 +#define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005 +#define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006 +#define PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO 0x8016 + +#define PCI_VENDOR_ID_TCONRAD 0x10da +#define PCI_DEVICE_ID_TCONRAD_TOKENRING 0x0508 + +#define PCI_VENDOR_ID_NVIDIA 0x10de +#define PCI_DEVICE_ID_NVIDIA_TNT 0x0020 +#define PCI_DEVICE_ID_NVIDIA_TNT2 0x0028 +#define PCI_DEVICE_ID_NVIDIA_UTNT2 0x0029 +#define PCI_DEVICE_ID_NVIDIA_TNT_UNKNOWN 0x002a +#define PCI_DEVICE_ID_NVIDIA_VTNT2 0x002C +#define PCI_DEVICE_ID_NVIDIA_UVTNT2 0x002D +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS 0x0034 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE 0x0035 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA 0x0036 +#define PCI_DEVICE_ID_NVIDIA_NVENET_10 0x0037 +#define PCI_DEVICE_ID_NVIDIA_NVENET_11 0x0038 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2 0x003e +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_ULTRA 0x0040 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800 0x0041 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_LE 0x0042 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_GT 0x0045 +#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_4000 0x004E +#define PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS 0x0052 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE 0x0053 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA 0x0054 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2 0x0055 +#define PCI_DEVICE_ID_NVIDIA_NVENET_8 0x0056 +#define PCI_DEVICE_ID_NVIDIA_NVENET_9 0x0057 +#define PCI_DEVICE_ID_NVIDIA_CK804_AUDIO 0x0059 +#define PCI_DEVICE_ID_NVIDIA_CK804_PCIE 0x005d +#define PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS 0x0064 +#define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE 0x0065 +#define PCI_DEVICE_ID_NVIDIA_NVENET_2 0x0066 +#define PCI_DEVICE_ID_NVIDIA_MCP2_MODEM 0x0069 +#define PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO 0x006a +#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS 0x0084 +#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE 0x0085 +#define PCI_DEVICE_ID_NVIDIA_NVENET_4 0x0086 +#define PCI_DEVICE_ID_NVIDIA_MCP2S_MODEM 0x0089 +#define PCI_DEVICE_ID_NVIDIA_CK8_AUDIO 0x008a +#define PCI_DEVICE_ID_NVIDIA_NVENET_5 0x008c +#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA 0x008e +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GT 0x0090 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GTX 0x0091 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800 0x0098 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800_GTX 0x0099 +#define PCI_DEVICE_ID_NVIDIA_ITNT2 0x00A0 +#define PCI_DEVICE_ID_GEFORCE_6800A 0x00c1 +#define PCI_DEVICE_ID_GEFORCE_6800A_LE 0x00c2 +#define PCI_DEVICE_ID_GEFORCE_GO_6800 0x00c8 +#define PCI_DEVICE_ID_GEFORCE_GO_6800_ULTRA 0x00c9 +#define PCI_DEVICE_ID_QUADRO_FX_GO1400 0x00cc +#define PCI_DEVICE_ID_QUADRO_FX_1400 0x00ce +#define PCI_DEVICE_ID_NVIDIA_NFORCE3 0x00d1 +#define PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS 0x00d4 +#define PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE 0x00d5 +#define PCI_DEVICE_ID_NVIDIA_NVENET_3 0x00d6 +#define PCI_DEVICE_ID_NVIDIA_MCP3_MODEM 0x00d9 +#define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO 0x00da +#define PCI_DEVICE_ID_NVIDIA_NVENET_7 0x00df +#define PCI_DEVICE_ID_NVIDIA_NFORCE3S 0x00e1 +#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA 0x00e3 +#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS 0x00e4 +#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE 0x00e5 +#define PCI_DEVICE_ID_NVIDIA_NVENET_6 0x00e6 +#define PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO 0x00ea +#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2 0x00ee +#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_ALT1 0x00f0 +#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT1 0x00f1 +#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT2 0x00f2 +#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6200_ALT1 0x00f3 +#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_GT 0x00f9 +#define PCIE_DEVICE_ID_NVIDIA_QUADRO_NVS280 0x00fd +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR 0x0100 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR 0x0101 +#define PCI_DEVICE_ID_NVIDIA_QUADRO 0x0103 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX 0x0110 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2 0x0111 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO 0x0112 +#define PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR 0x0113 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6600_GT 0x0140 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6600 0x0141 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6610_XL 0x0145 +#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_540 0x014E +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6200 0x014F +#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS 0x0150 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2 0x0151 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA 0x0152 +#define PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO 0x0153 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6200_TURBOCACHE 0x0161 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200 0x0164 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250 0x0166 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200_1 0x0167 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250_1 0x0168 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460 0x0170 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440 0x0171 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420 0x0172 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_SE 0x0173 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO 0x0174 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO 0x0175 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32 0x0176 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_460_GO 0x0177 +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL 0x0178 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64 0x0179 +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_200 0x017A +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL 0x017B +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL 0x017C +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_410_GO_M16 0x017D +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_8X 0x0181 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440SE_8X 0x0182 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420_8X 0x0183 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_4000 0x0185 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_448_GO 0x0186 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_488_GO 0x0187 +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_580_XGL 0x0188 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_MAC 0x0189 +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_280_NVS 0x018A +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_380_XGL 0x018B +#define PCI_DEVICE_ID_NVIDIA_IGEFORCE2 0x01a0 +#define PCI_DEVICE_ID_NVIDIA_NFORCE 0x01a4 +#define PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO 0x01b1 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS 0x01b4 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_IDE 0x01bc +#define PCI_DEVICE_ID_NVIDIA_MCP1_MODEM 0x01c1 +#define PCI_DEVICE_ID_NVIDIA_NVENET_1 0x01c3 +#define PCI_DEVICE_ID_NVIDIA_NFORCE2 0x01e0 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE3 0x0200 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1 0x0201 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_2 0x0202 +#define PCI_DEVICE_ID_NVIDIA_QUADRO_DDC 0x0203 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B 0x0211 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_LE 0x0212 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_GT 0x0215 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600 0x0250 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400 0x0251 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200 0x0253 +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL 0x0258 +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL 0x0259 +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL 0x025B +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS 0x0264 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE 0x0265 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA 0x0266 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2 0x0267 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS 0x0368 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE 0x036E +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA 0x037E +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2 0x037F +#define PCI_DEVICE_ID_NVIDIA_NVENET_12 0x0268 +#define PCI_DEVICE_ID_NVIDIA_NVENET_13 0x0269 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800 0x0280 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_8X 0x0281 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800SE 0x0282 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_4200_GO 0x0286 +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_980_XGL 0x0288 +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_780_XGL 0x0289 +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_700_GOGL 0x028C +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800_ULTRA 0x0301 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800 0x0302 +#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_2000 0x0308 +#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1000 0x0309 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600_ULTRA 0x0311 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600 0x0312 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600SE 0x0314 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5600 0x031A +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5650 0x031B +#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO700 0x031C +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200 0x0320 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_ULTRA 0x0321 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_1 0x0322 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200SE 0x0323 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5200 0x0324 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250 0x0325 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5500 0x0326 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5100 0x0327 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250_32 0x0328 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO_5200 0x0329 +#define PCI_DEVICE_ID_NVIDIA_QUADRO_NVS_280_PCI 0x032A +#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_500 0x032B +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5300 0x032C +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5100 0x032D +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900_ULTRA 0x0330 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900 0x0331 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900XT 0x0332 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5950_ULTRA 0x0333 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900ZT 0x0334 +#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_3000 0x0338 +#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_700 0x033F +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700_ULTRA 0x0341 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700 0x0342 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700LE 0x0343 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700VE 0x0344 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_1 0x0347 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_2 0x0348 +#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO1000 0x034C +#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100 0x034E +#define PCI_DEVICE_ID_NVIDIA_NVENET_14 0x0372 +#define PCI_DEVICE_ID_NVIDIA_NVENET_15 0x0373 +#define PCI_DEVICE_ID_NVIDIA_NVENET_16 0x03E5 +#define PCI_DEVICE_ID_NVIDIA_NVENET_17 0x03E6 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA 0x03E7 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS 0x03EB +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE 0x03EC +#define PCI_DEVICE_ID_NVIDIA_NVENET_18 0x03EE +#define PCI_DEVICE_ID_NVIDIA_NVENET_19 0x03EF +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2 0x03F6 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3 0x03F7 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS 0x0446 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE 0x0448 +#define PCI_DEVICE_ID_NVIDIA_NVENET_20 0x0450 +#define PCI_DEVICE_ID_NVIDIA_NVENET_21 0x0451 +#define PCI_DEVICE_ID_NVIDIA_NVENET_22 0x0452 +#define PCI_DEVICE_ID_NVIDIA_NVENET_23 0x0453 +#define PCI_DEVICE_ID_NVIDIA_NVENET_24 0x054C +#define PCI_DEVICE_ID_NVIDIA_NVENET_25 0x054D +#define PCI_DEVICE_ID_NVIDIA_NVENET_26 0x054E +#define PCI_DEVICE_ID_NVIDIA_NVENET_27 0x054F +#define PCI_DEVICE_ID_NVIDIA_NVENET_28 0x07DC +#define PCI_DEVICE_ID_NVIDIA_NVENET_29 0x07DD +#define PCI_DEVICE_ID_NVIDIA_NVENET_30 0x07DE +#define PCI_DEVICE_ID_NVIDIA_NVENET_31 0x07DF +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE 0x0560 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE 0x056C +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE 0x0759 +#define PCI_DEVICE_ID_NVIDIA_NVENET_32 0x0760 +#define PCI_DEVICE_ID_NVIDIA_NVENET_33 0x0761 +#define PCI_DEVICE_ID_NVIDIA_NVENET_34 0x0762 +#define PCI_DEVICE_ID_NVIDIA_NVENET_35 0x0763 +#define PCI_DEVICE_ID_NVIDIA_NVENET_36 0x0AB0 +#define PCI_DEVICE_ID_NVIDIA_NVENET_37 0x0AB1 +#define PCI_DEVICE_ID_NVIDIA_NVENET_38 0x0AB2 +#define PCI_DEVICE_ID_NVIDIA_NVENET_39 0x0AB3 + +#define PCI_VENDOR_ID_IMS 0x10e0 +#define PCI_DEVICE_ID_IMS_TT128 0x9128 +#define PCI_DEVICE_ID_IMS_TT3D 0x9135 + +#define PCI_VENDOR_ID_INTERG 0x10ea +#define PCI_DEVICE_ID_INTERG_1682 0x1682 +#define PCI_DEVICE_ID_INTERG_2000 0x2000 +#define PCI_DEVICE_ID_INTERG_2010 0x2010 +#define PCI_DEVICE_ID_INTERG_5000 0x5000 +#define PCI_DEVICE_ID_INTERG_5050 0x5050 + +#define PCI_VENDOR_ID_REALTEK 0x10ec +#define PCI_DEVICE_ID_REALTEK_8139 0x8139 + +#define PCI_VENDOR_ID_XILINX 0x10ee +#define PCI_DEVICE_ID_RME_DIGI96 0x3fc0 +#define PCI_DEVICE_ID_RME_DIGI96_8 0x3fc1 +#define PCI_DEVICE_ID_RME_DIGI96_8_PRO 0x3fc2 +#define PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST 0x3fc3 +#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP 0x3fc5 +#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI 0x3fc6 + +#define PCI_VENDOR_ID_INIT 0x1101 + +#define PCI_VENDOR_ID_CREATIVE 0x1102 /* duplicate: ECTIVA */ +#define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002 + +#define PCI_VENDOR_ID_ECTIVA 0x1102 /* duplicate: CREATIVE */ +#define PCI_DEVICE_ID_ECTIVA_EV1938 0x8938 + +#define PCI_VENDOR_ID_TTI 0x1103 +#define PCI_DEVICE_ID_TTI_HPT343 0x0003 +#define PCI_DEVICE_ID_TTI_HPT366 0x0004 +#define PCI_DEVICE_ID_TTI_HPT372 0x0005 +#define PCI_DEVICE_ID_TTI_HPT302 0x0006 +#define PCI_DEVICE_ID_TTI_HPT371 0x0007 +#define PCI_DEVICE_ID_TTI_HPT374 0x0008 +#define PCI_DEVICE_ID_TTI_HPT372N 0x0009 /* apparently a 372N variant? */ + +#define PCI_VENDOR_ID_VIA 0x1106 +#define PCI_DEVICE_ID_VIA_8763_0 0x0198 +#define PCI_DEVICE_ID_VIA_8380_0 0x0204 +#define PCI_DEVICE_ID_VIA_3238_0 0x0238 +#define PCI_DEVICE_ID_VIA_PT880 0x0258 +#define PCI_DEVICE_ID_VIA_PT880ULTRA 0x0308 +#define PCI_DEVICE_ID_VIA_PX8X0_0 0x0259 +#define PCI_DEVICE_ID_VIA_3269_0 0x0269 +#define PCI_DEVICE_ID_VIA_K8T800PRO_0 0x0282 +#define PCI_DEVICE_ID_VIA_3296_0 0x0296 +#define PCI_DEVICE_ID_VIA_8363_0 0x0305 +#define PCI_DEVICE_ID_VIA_P4M800CE 0x0314 +#define PCI_DEVICE_ID_VIA_P4M890 0x0327 +#define PCI_DEVICE_ID_VIA_VT3324 0x0324 +#define PCI_DEVICE_ID_VIA_VT3336 0x0336 +#define PCI_DEVICE_ID_VIA_VT3351 0x0351 +#define PCI_DEVICE_ID_VIA_VT3364 0x0364 +#define PCI_DEVICE_ID_VIA_8371_0 0x0391 +#define PCI_DEVICE_ID_VIA_8501_0 0x0501 +#define PCI_DEVICE_ID_VIA_82C561 0x0561 +#define PCI_DEVICE_ID_VIA_82C586_1 0x0571 +#define PCI_DEVICE_ID_VIA_82C576 0x0576 +#define PCI_DEVICE_ID_VIA_82C586_0 0x0586 +#define PCI_DEVICE_ID_VIA_82C596 0x0596 +#define PCI_DEVICE_ID_VIA_82C597_0 0x0597 +#define PCI_DEVICE_ID_VIA_82C598_0 0x0598 +#define PCI_DEVICE_ID_VIA_8601_0 0x0601 +#define PCI_DEVICE_ID_VIA_8605_0 0x0605 +#define PCI_DEVICE_ID_VIA_82C686 0x0686 +#define PCI_DEVICE_ID_VIA_82C691_0 0x0691 +#define PCI_DEVICE_ID_VIA_82C576_1 0x1571 +#define PCI_DEVICE_ID_VIA_82C586_2 0x3038 +#define PCI_DEVICE_ID_VIA_82C586_3 0x3040 +#define PCI_DEVICE_ID_VIA_82C596_3 0x3050 +#define PCI_DEVICE_ID_VIA_82C596B_3 0x3051 +#define PCI_DEVICE_ID_VIA_82C686_4 0x3057 +#define PCI_DEVICE_ID_VIA_82C686_5 0x3058 +#define PCI_DEVICE_ID_VIA_8233_5 0x3059 +#define PCI_DEVICE_ID_VIA_8233_0 0x3074 +#define PCI_DEVICE_ID_VIA_8633_0 0x3091 +#define PCI_DEVICE_ID_VIA_8367_0 0x3099 +#define PCI_DEVICE_ID_VIA_8653_0 0x3101 +#define PCI_DEVICE_ID_VIA_8622 0x3102 +#define PCI_DEVICE_ID_VIA_8235_USB_2 0x3104 +#define PCI_DEVICE_ID_VIA_8233C_0 0x3109 +#define PCI_DEVICE_ID_VIA_8361 0x3112 +#define PCI_DEVICE_ID_VIA_XM266 0x3116 +#define PCI_DEVICE_ID_VIA_612X 0x3119 +#define PCI_DEVICE_ID_VIA_862X_0 0x3123 +#define PCI_DEVICE_ID_VIA_8753_0 0x3128 +#define PCI_DEVICE_ID_VIA_8233A 0x3147 +#define PCI_DEVICE_ID_VIA_8703_51_0 0x3148 +#define PCI_DEVICE_ID_VIA_8237_SATA 0x3149 +#define PCI_DEVICE_ID_VIA_XN266 0x3156 +#define PCI_DEVICE_ID_VIA_6410 0x3164 +#define PCI_DEVICE_ID_VIA_8754C_0 0x3168 +#define PCI_DEVICE_ID_VIA_8235 0x3177 +#define PCI_DEVICE_ID_VIA_8385_0 0x3188 +#define PCI_DEVICE_ID_VIA_8377_0 0x3189 +#define PCI_DEVICE_ID_VIA_8378_0 0x3205 +#define PCI_DEVICE_ID_VIA_8783_0 0x3208 +#define PCI_DEVICE_ID_VIA_8237 0x3227 +#define PCI_DEVICE_ID_VIA_8251 0x3287 +#define PCI_DEVICE_ID_VIA_8237A 0x3337 +#define PCI_DEVICE_ID_VIA_8237S 0x3372 +#define PCI_DEVICE_ID_VIA_SATA_EIDE 0x5324 +#define PCI_DEVICE_ID_VIA_8231 0x8231 +#define PCI_DEVICE_ID_VIA_8231_4 0x8235 +#define PCI_DEVICE_ID_VIA_8365_1 0x8305 +#define PCI_DEVICE_ID_VIA_CX700 0x8324 +#define PCI_DEVICE_ID_VIA_CX700_IDE 0x0581 +#define PCI_DEVICE_ID_VIA_VX800 0x8353 +#define PCI_DEVICE_ID_VIA_8371_1 0x8391 +#define PCI_DEVICE_ID_VIA_82C598_1 0x8598 +#define PCI_DEVICE_ID_VIA_838X_1 0xB188 +#define PCI_DEVICE_ID_VIA_83_87XX_1 0xB198 + +#define PCI_VENDOR_ID_SIEMENS 0x110A +#define PCI_DEVICE_ID_SIEMENS_DSCC4 0x2102 + +#define PCI_VENDOR_ID_VORTEX 0x1119 +#define PCI_DEVICE_ID_VORTEX_GDT60x0 0x0000 +#define PCI_DEVICE_ID_VORTEX_GDT6000B 0x0001 +#define PCI_DEVICE_ID_VORTEX_GDT6x10 0x0002 +#define PCI_DEVICE_ID_VORTEX_GDT6x20 0x0003 +#define PCI_DEVICE_ID_VORTEX_GDT6530 0x0004 +#define PCI_DEVICE_ID_VORTEX_GDT6550 0x0005 +#define PCI_DEVICE_ID_VORTEX_GDT6x17 0x0006 +#define PCI_DEVICE_ID_VORTEX_GDT6x27 0x0007 +#define PCI_DEVICE_ID_VORTEX_GDT6537 0x0008 +#define PCI_DEVICE_ID_VORTEX_GDT6557 0x0009 +#define PCI_DEVICE_ID_VORTEX_GDT6x15 0x000a +#define PCI_DEVICE_ID_VORTEX_GDT6x25 0x000b +#define PCI_DEVICE_ID_VORTEX_GDT6535 0x000c +#define PCI_DEVICE_ID_VORTEX_GDT6555 0x000d +#define PCI_DEVICE_ID_VORTEX_GDT6x17RP 0x0100 +#define PCI_DEVICE_ID_VORTEX_GDT6x27RP 0x0101 +#define PCI_DEVICE_ID_VORTEX_GDT6537RP 0x0102 +#define PCI_DEVICE_ID_VORTEX_GDT6557RP 0x0103 +#define PCI_DEVICE_ID_VORTEX_GDT6x11RP 0x0104 +#define PCI_DEVICE_ID_VORTEX_GDT6x21RP 0x0105 + +#define PCI_VENDOR_ID_EF 0x111a +#define PCI_DEVICE_ID_EF_ATM_FPGA 0x0000 +#define PCI_DEVICE_ID_EF_ATM_ASIC 0x0002 +#define PCI_DEVICE_ID_EF_ATM_LANAI2 0x0003 +#define PCI_DEVICE_ID_EF_ATM_LANAIHB 0x0005 + +#define PCI_VENDOR_ID_IDT 0x111d +#define PCI_DEVICE_ID_IDT_IDT77201 0x0001 + +#define PCI_VENDOR_ID_FORE 0x1127 +#define PCI_DEVICE_ID_FORE_PCA200E 0x0300 + +#define PCI_VENDOR_ID_PHILIPS 0x1131 +#define PCI_DEVICE_ID_PHILIPS_SAA7146 0x7146 +#define PCI_DEVICE_ID_PHILIPS_SAA9730 0x9730 + +#define PCI_VENDOR_ID_EICON 0x1133 +#define PCI_DEVICE_ID_EICON_DIVA20 0xe002 +#define PCI_DEVICE_ID_EICON_DIVA20_U 0xe004 +#define PCI_DEVICE_ID_EICON_DIVA201 0xe005 +#define PCI_DEVICE_ID_EICON_DIVA202 0xe00b +#define PCI_DEVICE_ID_EICON_MAESTRA 0xe010 +#define PCI_DEVICE_ID_EICON_MAESTRAQ 0xe012 +#define PCI_DEVICE_ID_EICON_MAESTRAQ_U 0xe013 +#define PCI_DEVICE_ID_EICON_MAESTRAP 0xe014 + +#define PCI_VENDOR_ID_CISCO 0x1137 + +#define PCI_VENDOR_ID_ZIATECH 0x1138 +#define PCI_DEVICE_ID_ZIATECH_5550_HC 0x5550 + + +#define PCI_VENDOR_ID_SYSKONNECT 0x1148 +#define PCI_DEVICE_ID_SYSKONNECT_TR 0x4200 +#define PCI_DEVICE_ID_SYSKONNECT_GE 0x4300 +#define PCI_DEVICE_ID_SYSKONNECT_YU 0x4320 +#define PCI_DEVICE_ID_SYSKONNECT_9DXX 0x4400 +#define PCI_DEVICE_ID_SYSKONNECT_9MXX 0x4500 + +#define PCI_VENDOR_ID_DIGI 0x114f +#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_E 0x0070 +#define PCI_DEVICE_ID_DIGI_DF_M_E 0x0071 +#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_A 0x0072 +#define PCI_DEVICE_ID_DIGI_DF_M_A 0x0073 +#define PCI_DEVICE_ID_NEO_2DB9 0x00C8 +#define PCI_DEVICE_ID_NEO_2DB9PRI 0x00C9 +#define PCI_DEVICE_ID_NEO_2RJ45 0x00CA +#define PCI_DEVICE_ID_NEO_2RJ45PRI 0x00CB +#define PCIE_DEVICE_ID_NEO_4_IBM 0x00F4 + +#define PCI_VENDOR_ID_XIRCOM 0x115d +#define PCI_DEVICE_ID_XIRCOM_RBM56G 0x0101 +#define PCI_DEVICE_ID_XIRCOM_X3201_MDM 0x0103 + +#define PCI_VENDOR_ID_SERVERWORKS 0x1166 +#define PCI_DEVICE_ID_SERVERWORKS_HE 0x0008 +#define PCI_DEVICE_ID_SERVERWORKS_LE 0x0009 +#define PCI_DEVICE_ID_SERVERWORKS_GCNB_LE 0x0017 +#define PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB 0x0036 +#define PCI_DEVICE_ID_SERVERWORKS_EPB 0x0103 +#define PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE 0x0132 +#define PCI_DEVICE_ID_SERVERWORKS_OSB4 0x0200 +#define PCI_DEVICE_ID_SERVERWORKS_CSB5 0x0201 +#define PCI_DEVICE_ID_SERVERWORKS_CSB6 0x0203 +#define PCI_DEVICE_ID_SERVERWORKS_HT1000SB 0x0205 +#define PCI_DEVICE_ID_SERVERWORKS_OSB4IDE 0x0211 +#define PCI_DEVICE_ID_SERVERWORKS_CSB5IDE 0x0212 +#define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE 0x0213 +#define PCI_DEVICE_ID_SERVERWORKS_HT1000IDE 0x0214 +#define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2 0x0217 +#define PCI_DEVICE_ID_SERVERWORKS_CSB6LPC 0x0227 + +#define PCI_VENDOR_ID_SBE 0x1176 +#define PCI_DEVICE_ID_SBE_WANXL100 0x0301 +#define PCI_DEVICE_ID_SBE_WANXL200 0x0302 +#define PCI_DEVICE_ID_SBE_WANXL400 0x0104 + +#define PCI_VENDOR_ID_TOSHIBA 0x1179 +#define PCI_DEVICE_ID_TOSHIBA_PICCOLO 0x0102 +#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_1 0x0103 +#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_2 0x0105 +#define PCI_DEVICE_ID_TOSHIBA_TOPIC95 0x060a +#define PCI_DEVICE_ID_TOSHIBA_TOPIC97 0x060f +#define PCI_DEVICE_ID_TOSHIBA_TOPIC100 0x0617 + +#define PCI_VENDOR_ID_TOSHIBA_2 0x102f +#define PCI_DEVICE_ID_TOSHIBA_TC35815CF 0x0030 +#define PCI_DEVICE_ID_TOSHIBA_TC35815_NWU 0x0031 +#define PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939 0x0032 +#define PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE 0x0105 +#define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC 0x0108 +#define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3 + +#define PCI_VENDOR_ID_ATTO 0x117c + +#define PCI_VENDOR_ID_RICOH 0x1180 +#define PCI_DEVICE_ID_RICOH_RL5C465 0x0465 +#define PCI_DEVICE_ID_RICOH_RL5C466 0x0466 +#define PCI_DEVICE_ID_RICOH_RL5C475 0x0475 +#define PCI_DEVICE_ID_RICOH_RL5C476 0x0476 +#define PCI_DEVICE_ID_RICOH_RL5C478 0x0478 +#define PCI_DEVICE_ID_RICOH_R5C822 0x0822 +#define PCI_DEVICE_ID_RICOH_R5C832 0x0832 +#define PCI_DEVICE_ID_RICOH_R5C843 0x0843 + +#define PCI_VENDOR_ID_DLINK 0x1186 +#define PCI_DEVICE_ID_DLINK_DGE510T 0x4c00 + +#define PCI_VENDOR_ID_ARTOP 0x1191 +#define PCI_DEVICE_ID_ARTOP_ATP850UF 0x0005 +#define PCI_DEVICE_ID_ARTOP_ATP860 0x0006 +#define PCI_DEVICE_ID_ARTOP_ATP860R 0x0007 +#define PCI_DEVICE_ID_ARTOP_ATP865 0x0008 +#define PCI_DEVICE_ID_ARTOP_ATP865R 0x0009 +#define PCI_DEVICE_ID_ARTOP_AEC7610 0x8002 +#define PCI_DEVICE_ID_ARTOP_AEC7612UW 0x8010 +#define PCI_DEVICE_ID_ARTOP_AEC7612U 0x8020 +#define PCI_DEVICE_ID_ARTOP_AEC7612S 0x8030 +#define PCI_DEVICE_ID_ARTOP_AEC7612D 0x8040 +#define PCI_DEVICE_ID_ARTOP_AEC7612SUW 0x8050 +#define PCI_DEVICE_ID_ARTOP_8060 0x8060 + +#define PCI_VENDOR_ID_ZEITNET 0x1193 +#define PCI_DEVICE_ID_ZEITNET_1221 0x0001 +#define PCI_DEVICE_ID_ZEITNET_1225 0x0002 + +#define PCI_VENDOR_ID_FUJITSU_ME 0x119e +#define PCI_DEVICE_ID_FUJITSU_FS155 0x0001 +#define PCI_DEVICE_ID_FUJITSU_FS50 0x0003 + +#define PCI_SUBVENDOR_ID_KEYSPAN 0x11a9 +#define PCI_SUBDEVICE_ID_KEYSPAN_SX2 0x5334 + +#define PCI_VENDOR_ID_MARVELL 0x11ab +#define PCI_DEVICE_ID_MARVELL_GT64111 0x4146 +#define PCI_DEVICE_ID_MARVELL_GT64260 0x6430 +#define PCI_DEVICE_ID_MARVELL_MV64360 0x6460 +#define PCI_DEVICE_ID_MARVELL_MV64460 0x6480 +#define PCI_DEVICE_ID_MARVELL_88ALP01_NAND 0x4100 +#define PCI_DEVICE_ID_MARVELL_88ALP01_SD 0x4101 +#define PCI_DEVICE_ID_MARVELL_88ALP01_CCIC 0x4102 + +#define PCI_VENDOR_ID_V3 0x11b0 +#define PCI_DEVICE_ID_V3_V960 0x0001 +#define PCI_DEVICE_ID_V3_V351 0x0002 + +#define PCI_VENDOR_ID_ATT 0x11c1 +#define PCI_DEVICE_ID_ATT_VENUS_MODEM 0x480 + +#define PCI_VENDOR_ID_SPECIALIX 0x11cb +#define PCI_DEVICE_ID_SPECIALIX_IO8 0x2000 +#define PCI_DEVICE_ID_SPECIALIX_RIO 0x8000 +#define PCI_SUBDEVICE_ID_SPECIALIX_SPEED4 0xa004 + +#define PCI_VENDOR_ID_ANALOG_DEVICES 0x11d4 +#define PCI_DEVICE_ID_AD1889JS 0x1889 + +#define PCI_DEVICE_ID_SEGA_BBA 0x1234 + +#define PCI_VENDOR_ID_ZORAN 0x11de +#define PCI_DEVICE_ID_ZORAN_36057 0x6057 +#define PCI_DEVICE_ID_ZORAN_36120 0x6120 + +#define PCI_VENDOR_ID_COMPEX 0x11f6 +#define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112 + +#define PCI_VENDOR_ID_RP 0x11fe +#define PCI_DEVICE_ID_RP32INTF 0x0001 +#define PCI_DEVICE_ID_RP8INTF 0x0002 +#define PCI_DEVICE_ID_RP16INTF 0x0003 +#define PCI_DEVICE_ID_RP4QUAD 0x0004 +#define PCI_DEVICE_ID_RP8OCTA 0x0005 +#define PCI_DEVICE_ID_RP8J 0x0006 +#define PCI_DEVICE_ID_RP4J 0x0007 +#define PCI_DEVICE_ID_RP8SNI 0x0008 +#define PCI_DEVICE_ID_RP16SNI 0x0009 +#define PCI_DEVICE_ID_RPP4 0x000A +#define PCI_DEVICE_ID_RPP8 0x000B +#define PCI_DEVICE_ID_RP4M 0x000D +#define PCI_DEVICE_ID_RP2_232 0x000E +#define PCI_DEVICE_ID_RP2_422 0x000F +#define PCI_DEVICE_ID_URP32INTF 0x0801 +#define PCI_DEVICE_ID_URP8INTF 0x0802 +#define PCI_DEVICE_ID_URP16INTF 0x0803 +#define PCI_DEVICE_ID_URP8OCTA 0x0805 +#define PCI_DEVICE_ID_UPCI_RM3_8PORT 0x080C +#define PCI_DEVICE_ID_UPCI_RM3_4PORT 0x080D +#define PCI_DEVICE_ID_CRP16INTF 0x0903 + +#define PCI_VENDOR_ID_CYCLADES 0x120e +#define PCI_DEVICE_ID_CYCLOM_Y_Lo 0x0100 +#define PCI_DEVICE_ID_CYCLOM_Y_Hi 0x0101 +#define PCI_DEVICE_ID_CYCLOM_4Y_Lo 0x0102 +#define PCI_DEVICE_ID_CYCLOM_4Y_Hi 0x0103 +#define PCI_DEVICE_ID_CYCLOM_8Y_Lo 0x0104 +#define PCI_DEVICE_ID_CYCLOM_8Y_Hi 0x0105 +#define PCI_DEVICE_ID_CYCLOM_Z_Lo 0x0200 +#define PCI_DEVICE_ID_CYCLOM_Z_Hi 0x0201 +#define PCI_DEVICE_ID_PC300_RX_2 0x0300 +#define PCI_DEVICE_ID_PC300_RX_1 0x0301 +#define PCI_DEVICE_ID_PC300_TE_2 0x0310 +#define PCI_DEVICE_ID_PC300_TE_1 0x0311 +#define PCI_DEVICE_ID_PC300_TE_M_2 0x0320 +#define PCI_DEVICE_ID_PC300_TE_M_1 0x0321 + +#define PCI_VENDOR_ID_ESSENTIAL 0x120f +#define PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER 0x0001 + +#define PCI_VENDOR_ID_O2 0x1217 +#define PCI_DEVICE_ID_O2_6729 0x6729 +#define PCI_DEVICE_ID_O2_6730 0x673a +#define PCI_DEVICE_ID_O2_6832 0x6832 +#define PCI_DEVICE_ID_O2_6836 0x6836 + +#define PCI_VENDOR_ID_3DFX 0x121a +#define PCI_DEVICE_ID_3DFX_VOODOO 0x0001 +#define PCI_DEVICE_ID_3DFX_VOODOO2 0x0002 +#define PCI_DEVICE_ID_3DFX_BANSHEE 0x0003 +#define PCI_DEVICE_ID_3DFX_VOODOO3 0x0005 +#define PCI_DEVICE_ID_3DFX_VOODOO5 0x0009 + +#define PCI_VENDOR_ID_AVM 0x1244 +#define PCI_DEVICE_ID_AVM_B1 0x0700 +#define PCI_DEVICE_ID_AVM_C4 0x0800 +#define PCI_DEVICE_ID_AVM_A1 0x0a00 +#define PCI_DEVICE_ID_AVM_A1_V2 0x0e00 +#define PCI_DEVICE_ID_AVM_C2 0x1100 +#define PCI_DEVICE_ID_AVM_T1 0x1200 + +#define PCI_VENDOR_ID_STALLION 0x124d + +/* Allied Telesyn */ +#define PCI_VENDOR_ID_AT 0x1259 +#define PCI_SUBDEVICE_ID_AT_2700FX 0x2701 +#define PCI_SUBDEVICE_ID_AT_2701FX 0x2703 + +#define PCI_VENDOR_ID_ESS 0x125d +#define PCI_DEVICE_ID_ESS_ESS1968 0x1968 +#define PCI_DEVICE_ID_ESS_ESS1978 0x1978 +#define PCI_DEVICE_ID_ESS_ALLEGRO_1 0x1988 +#define PCI_DEVICE_ID_ESS_ALLEGRO 0x1989 +#define PCI_DEVICE_ID_ESS_CANYON3D_2LE 0x1990 +#define PCI_DEVICE_ID_ESS_CANYON3D_2 0x1992 +#define PCI_DEVICE_ID_ESS_MAESTRO3 0x1998 +#define PCI_DEVICE_ID_ESS_MAESTRO3_1 0x1999 +#define PCI_DEVICE_ID_ESS_MAESTRO3_HW 0x199a +#define PCI_DEVICE_ID_ESS_MAESTRO3_2 0x199b + +#define PCI_VENDOR_ID_SATSAGEM 0x1267 +#define PCI_DEVICE_ID_SATSAGEM_NICCY 0x1016 + +#define PCI_VENDOR_ID_ENSONIQ 0x1274 +#define PCI_DEVICE_ID_ENSONIQ_CT5880 0x5880 +#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000 +#define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371 + +#define PCI_VENDOR_ID_TRANSMETA 0x1279 +#define PCI_DEVICE_ID_EFFICEON 0x0060 + +#define PCI_VENDOR_ID_ROCKWELL 0x127A + +#define PCI_VENDOR_ID_ITE 0x1283 +#define PCI_DEVICE_ID_ITE_8211 0x8211 +#define PCI_DEVICE_ID_ITE_8212 0x8212 +#define PCI_DEVICE_ID_ITE_8213 0x8213 +#define PCI_DEVICE_ID_ITE_8152 0x8152 +#define PCI_DEVICE_ID_ITE_8872 0x8872 +#define PCI_DEVICE_ID_ITE_IT8330G_0 0xe886 + +/* formerly Platform Tech */ +#define PCI_DEVICE_ID_ESS_ESS0100 0x0100 + +#define PCI_VENDOR_ID_ALTEON 0x12ae + +#define PCI_SUBVENDOR_ID_CONNECT_TECH 0x12c4 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232 0x0001 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232 0x0002 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232 0x0003 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485 0x0004 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4 0x0005 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485 0x0006 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2 0x0007 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485 0x0008 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6 0x0009 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1 0x000A +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1 0x000B +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_20MHZ 0x000C +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_PTM 0x000D +#define PCI_SUBDEVICE_ID_CONNECT_TECH_NT960PCI 0x0100 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_2 0x0201 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_4 0x0202 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_232 0x0300 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_232 0x0301 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_232 0x0302 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_1_1 0x0310 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_2 0x0311 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4 0x0312 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2 0x0320 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4 0x0321 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8 0x0322 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_485 0x0330 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_485 0x0331 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_485 0x0332 + +#define PCI_VENDOR_ID_NVIDIA_SGS 0x12d2 +#define PCI_DEVICE_ID_NVIDIA_SGS_RIVA128 0x0018 + +#define PCI_SUBVENDOR_ID_CHASE_PCIFAST 0x12E0 +#define PCI_SUBDEVICE_ID_CHASE_PCIFAST4 0x0031 +#define PCI_SUBDEVICE_ID_CHASE_PCIFAST8 0x0021 +#define PCI_SUBDEVICE_ID_CHASE_PCIFAST16 0x0011 +#define PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC 0x0041 +#define PCI_SUBVENDOR_ID_CHASE_PCIRAS 0x124D +#define PCI_SUBDEVICE_ID_CHASE_PCIRAS4 0xF001 +#define PCI_SUBDEVICE_ID_CHASE_PCIRAS8 0xF010 + +#define PCI_VENDOR_ID_AUREAL 0x12eb +#define PCI_DEVICE_ID_AUREAL_VORTEX_1 0x0001 +#define PCI_DEVICE_ID_AUREAL_VORTEX_2 0x0002 +#define PCI_DEVICE_ID_AUREAL_ADVANTAGE 0x0003 + +#define PCI_VENDOR_ID_ELECTRONICDESIGNGMBH 0x12f8 +#define PCI_DEVICE_ID_LML_33R10 0x8a02 + +#define PCI_VENDOR_ID_ESDGMBH 0x12fe +#define PCI_DEVICE_ID_ESDGMBH_CPCIASIO4 0x0111 + +#define PCI_VENDOR_ID_SIIG 0x131f +#define PCI_SUBVENDOR_ID_SIIG 0x131f +#define PCI_DEVICE_ID_SIIG_1S_10x_550 0x1000 +#define PCI_DEVICE_ID_SIIG_1S_10x_650 0x1001 +#define PCI_DEVICE_ID_SIIG_1S_10x_850 0x1002 +#define PCI_DEVICE_ID_SIIG_1S1P_10x_550 0x1010 +#define PCI_DEVICE_ID_SIIG_1S1P_10x_650 0x1011 +#define PCI_DEVICE_ID_SIIG_1S1P_10x_850 0x1012 +#define PCI_DEVICE_ID_SIIG_1P_10x 0x1020 +#define PCI_DEVICE_ID_SIIG_2P_10x 0x1021 +#define PCI_DEVICE_ID_SIIG_2S_10x_550 0x1030 +#define PCI_DEVICE_ID_SIIG_2S_10x_650 0x1031 +#define PCI_DEVICE_ID_SIIG_2S_10x_850 0x1032 +#define PCI_DEVICE_ID_SIIG_2S1P_10x_550 0x1034 +#define PCI_DEVICE_ID_SIIG_2S1P_10x_650 0x1035 +#define PCI_DEVICE_ID_SIIG_2S1P_10x_850 0x1036 +#define PCI_DEVICE_ID_SIIG_4S_10x_550 0x1050 +#define PCI_DEVICE_ID_SIIG_4S_10x_650 0x1051 +#define PCI_DEVICE_ID_SIIG_4S_10x_850 0x1052 +#define PCI_DEVICE_ID_SIIG_1S_20x_550 0x2000 +#define PCI_DEVICE_ID_SIIG_1S_20x_650 0x2001 +#define PCI_DEVICE_ID_SIIG_1S_20x_850 0x2002 +#define PCI_DEVICE_ID_SIIG_1P_20x 0x2020 +#define PCI_DEVICE_ID_SIIG_2P_20x 0x2021 +#define PCI_DEVICE_ID_SIIG_2S_20x_550 0x2030 +#define PCI_DEVICE_ID_SIIG_2S_20x_650 0x2031 +#define PCI_DEVICE_ID_SIIG_2S_20x_850 0x2032 +#define PCI_DEVICE_ID_SIIG_2P1S_20x_550 0x2040 +#define PCI_DEVICE_ID_SIIG_2P1S_20x_650 0x2041 +#define PCI_DEVICE_ID_SIIG_2P1S_20x_850 0x2042 +#define PCI_DEVICE_ID_SIIG_1S1P_20x_550 0x2010 +#define PCI_DEVICE_ID_SIIG_1S1P_20x_650 0x2011 +#define PCI_DEVICE_ID_SIIG_1S1P_20x_850 0x2012 +#define PCI_DEVICE_ID_SIIG_4S_20x_550 0x2050 +#define PCI_DEVICE_ID_SIIG_4S_20x_650 0x2051 +#define PCI_DEVICE_ID_SIIG_4S_20x_850 0x2052 +#define PCI_DEVICE_ID_SIIG_2S1P_20x_550 0x2060 +#define PCI_DEVICE_ID_SIIG_2S1P_20x_650 0x2061 +#define PCI_DEVICE_ID_SIIG_2S1P_20x_850 0x2062 +#define PCI_DEVICE_ID_SIIG_8S_20x_550 0x2080 +#define PCI_DEVICE_ID_SIIG_8S_20x_650 0x2081 +#define PCI_DEVICE_ID_SIIG_8S_20x_850 0x2082 +#define PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL 0x2050 + +#define PCI_VENDOR_ID_RADISYS 0x1331 + +#define PCI_VENDOR_ID_MICRO_MEMORY 0x1332 +#define PCI_DEVICE_ID_MICRO_MEMORY_5415CN 0x5415 +#define PCI_DEVICE_ID_MICRO_MEMORY_5425CN 0x5425 +#define PCI_DEVICE_ID_MICRO_MEMORY_6155 0x6155 + +#define PCI_VENDOR_ID_DOMEX 0x134a +#define PCI_DEVICE_ID_DOMEX_DMX3191D 0x0001 + +#define PCI_VENDOR_ID_INTASHIELD 0x135a +#define PCI_DEVICE_ID_INTASHIELD_IS200 0x0d80 +#define PCI_DEVICE_ID_INTASHIELD_IS400 0x0dc0 + +#define PCI_VENDOR_ID_QUATECH 0x135C +#define PCI_DEVICE_ID_QUATECH_QSC100 0x0010 +#define PCI_DEVICE_ID_QUATECH_DSC100 0x0020 +#define PCI_DEVICE_ID_QUATECH_ESC100D 0x0050 +#define PCI_DEVICE_ID_QUATECH_ESC100M 0x0060 +#define PCI_DEVICE_ID_QUATECH_SPPXP_100 0x0278 + +#define PCI_VENDOR_ID_SEALEVEL 0x135e +#define PCI_DEVICE_ID_SEALEVEL_U530 0x7101 +#define PCI_DEVICE_ID_SEALEVEL_UCOMM2 0x7201 +#define PCI_DEVICE_ID_SEALEVEL_UCOMM422 0x7402 +#define PCI_DEVICE_ID_SEALEVEL_UCOMM232 0x7202 +#define PCI_DEVICE_ID_SEALEVEL_COMM4 0x7401 +#define PCI_DEVICE_ID_SEALEVEL_COMM8 0x7801 +#define PCI_DEVICE_ID_SEALEVEL_UCOMM8 0x7804 + +#define PCI_VENDOR_ID_HYPERCOPE 0x1365 +#define PCI_DEVICE_ID_HYPERCOPE_PLX 0x9050 +#define PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO 0x0104 +#define PCI_SUBDEVICE_ID_HYPERCOPE_ERGO 0x0106 +#define PCI_SUBDEVICE_ID_HYPERCOPE_METRO 0x0107 +#define PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2 0x0108 + +#define PCI_VENDOR_ID_KAWASAKI 0x136b +#define PCI_DEVICE_ID_MCHIP_KL5A72002 0xff01 + +#define PCI_VENDOR_ID_CNET 0x1371 +#define PCI_DEVICE_ID_CNET_GIGACARD 0x434e + +#define PCI_VENDOR_ID_LMC 0x1376 +#define PCI_DEVICE_ID_LMC_HSSI 0x0003 +#define PCI_DEVICE_ID_LMC_DS3 0x0004 +#define PCI_DEVICE_ID_LMC_SSI 0x0005 +#define PCI_DEVICE_ID_LMC_T1 0x0006 + +#define PCI_VENDOR_ID_NETGEAR 0x1385 +#define PCI_DEVICE_ID_NETGEAR_GA620 0x620a + +#define PCI_VENDOR_ID_APPLICOM 0x1389 +#define PCI_DEVICE_ID_APPLICOM_PCIGENERIC 0x0001 +#define PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN 0x0002 +#define PCI_DEVICE_ID_APPLICOM_PCI2000PFB 0x0003 + +#define PCI_VENDOR_ID_MOXA 0x1393 +#define PCI_DEVICE_ID_MOXA_RC7000 0x0001 +#define PCI_DEVICE_ID_MOXA_CP102 0x1020 +#define PCI_DEVICE_ID_MOXA_CP102UL 0x1021 +#define PCI_DEVICE_ID_MOXA_CP102U 0x1022 +#define PCI_DEVICE_ID_MOXA_C104 0x1040 +#define PCI_DEVICE_ID_MOXA_CP104U 0x1041 +#define PCI_DEVICE_ID_MOXA_CP104JU 0x1042 +#define PCI_DEVICE_ID_MOXA_CP104EL 0x1043 +#define PCI_DEVICE_ID_MOXA_CT114 0x1140 +#define PCI_DEVICE_ID_MOXA_CP114 0x1141 +#define PCI_DEVICE_ID_MOXA_CP118U 0x1180 +#define PCI_DEVICE_ID_MOXA_CP118EL 0x1181 +#define PCI_DEVICE_ID_MOXA_CP132 0x1320 +#define PCI_DEVICE_ID_MOXA_CP132U 0x1321 +#define PCI_DEVICE_ID_MOXA_CP134U 0x1340 +#define PCI_DEVICE_ID_MOXA_C168 0x1680 +#define PCI_DEVICE_ID_MOXA_CP168U 0x1681 +#define PCI_DEVICE_ID_MOXA_CP168EL 0x1682 +#define PCI_DEVICE_ID_MOXA_CP204J 0x2040 +#define PCI_DEVICE_ID_MOXA_C218 0x2180 +#define PCI_DEVICE_ID_MOXA_C320 0x3200 + +#define PCI_VENDOR_ID_CCD 0x1397 +#define PCI_DEVICE_ID_CCD_HFC4S 0x08B4 +#define PCI_SUBDEVICE_ID_CCD_PMX2S 0x1234 +#define PCI_DEVICE_ID_CCD_HFC8S 0x16B8 +#define PCI_DEVICE_ID_CCD_2BD0 0x2bd0 +#define PCI_DEVICE_ID_CCD_HFCE1 0x30B1 +#define PCI_SUBDEVICE_ID_CCD_SPD4S 0x3136 +#define PCI_SUBDEVICE_ID_CCD_SPDE1 0x3137 +#define PCI_DEVICE_ID_CCD_B000 0xb000 +#define PCI_DEVICE_ID_CCD_B006 0xb006 +#define PCI_DEVICE_ID_CCD_B007 0xb007 +#define PCI_DEVICE_ID_CCD_B008 0xb008 +#define PCI_DEVICE_ID_CCD_B009 0xb009 +#define PCI_DEVICE_ID_CCD_B00A 0xb00a +#define PCI_DEVICE_ID_CCD_B00B 0xb00b +#define PCI_DEVICE_ID_CCD_B00C 0xb00c +#define PCI_DEVICE_ID_CCD_B100 0xb100 +#define PCI_SUBDEVICE_ID_CCD_IOB4ST 0xB520 +#define PCI_SUBDEVICE_ID_CCD_IOB8STR 0xB521 +#define PCI_SUBDEVICE_ID_CCD_IOB8ST 0xB522 +#define PCI_SUBDEVICE_ID_CCD_IOB1E1 0xB523 +#define PCI_SUBDEVICE_ID_CCD_SWYX4S 0xB540 +#define PCI_SUBDEVICE_ID_CCD_JH4S20 0xB550 +#define PCI_SUBDEVICE_ID_CCD_IOB8ST_1 0xB552 +#define PCI_SUBDEVICE_ID_CCD_BN4S 0xB560 +#define PCI_SUBDEVICE_ID_CCD_BN8S 0xB562 +#define PCI_SUBDEVICE_ID_CCD_BNE1 0xB563 +#define PCI_SUBDEVICE_ID_CCD_BNE1D 0xB564 +#define PCI_SUBDEVICE_ID_CCD_BNE1DP 0xB565 +#define PCI_SUBDEVICE_ID_CCD_BN2S 0xB566 +#define PCI_SUBDEVICE_ID_CCD_BN1SM 0xB567 +#define PCI_SUBDEVICE_ID_CCD_BN4SM 0xB568 +#define PCI_SUBDEVICE_ID_CCD_BN2SM 0xB569 +#define PCI_SUBDEVICE_ID_CCD_BNE1M 0xB56A +#define PCI_SUBDEVICE_ID_CCD_BN8SP 0xB56B +#define PCI_SUBDEVICE_ID_CCD_HFC4S 0xB620 +#define PCI_SUBDEVICE_ID_CCD_HFC8S 0xB622 +#define PCI_DEVICE_ID_CCD_B700 0xb700 +#define PCI_DEVICE_ID_CCD_B701 0xb701 +#define PCI_SUBDEVICE_ID_CCD_HFCE1 0xC523 +#define PCI_SUBDEVICE_ID_CCD_OV2S 0xE884 +#define PCI_SUBDEVICE_ID_CCD_OV4S 0xE888 +#define PCI_SUBDEVICE_ID_CCD_OV8S 0xE998 + +#define PCI_VENDOR_ID_EXAR 0x13a8 +#define PCI_DEVICE_ID_EXAR_XR17C152 0x0152 +#define PCI_DEVICE_ID_EXAR_XR17C154 0x0154 +#define PCI_DEVICE_ID_EXAR_XR17C158 0x0158 + +#define PCI_VENDOR_ID_MICROGATE 0x13c0 +#define PCI_DEVICE_ID_MICROGATE_USC 0x0010 +#define PCI_DEVICE_ID_MICROGATE_SCA 0x0030 + +#define PCI_VENDOR_ID_3WARE 0x13C1 +#define PCI_DEVICE_ID_3WARE_1000 0x1000 +#define PCI_DEVICE_ID_3WARE_7000 0x1001 +#define PCI_DEVICE_ID_3WARE_9000 0x1002 + +#define PCI_VENDOR_ID_IOMEGA 0x13ca +#define PCI_DEVICE_ID_IOMEGA_BUZ 0x4231 + +#define PCI_VENDOR_ID_ABOCOM 0x13D1 +#define PCI_DEVICE_ID_ABOCOM_2BD1 0x2BD1 + +#define PCI_VENDOR_ID_SUNDANCE 0x13f0 + +#define PCI_VENDOR_ID_CMEDIA 0x13f6 +#define PCI_DEVICE_ID_CMEDIA_CM8338A 0x0100 +#define PCI_DEVICE_ID_CMEDIA_CM8338B 0x0101 +#define PCI_DEVICE_ID_CMEDIA_CM8738 0x0111 +#define PCI_DEVICE_ID_CMEDIA_CM8738B 0x0112 + +#define PCI_VENDOR_ID_LAVA 0x1407 +#define PCI_DEVICE_ID_LAVA_DSERIAL 0x0100 /* 2x 16550 */ +#define PCI_DEVICE_ID_LAVA_QUATRO_A 0x0101 /* 2x 16550, half of 4 port */ +#define PCI_DEVICE_ID_LAVA_QUATRO_B 0x0102 /* 2x 16550, half of 4 port */ +#define PCI_DEVICE_ID_LAVA_OCTO_A 0x0180 /* 4x 16550A, half of 8 port */ +#define PCI_DEVICE_ID_LAVA_OCTO_B 0x0181 /* 4x 16550A, half of 8 port */ +#define PCI_DEVICE_ID_LAVA_PORT_PLUS 0x0200 /* 2x 16650 */ +#define PCI_DEVICE_ID_LAVA_QUAD_A 0x0201 /* 2x 16650, half of 4 port */ +#define PCI_DEVICE_ID_LAVA_QUAD_B 0x0202 /* 2x 16650, half of 4 port */ +#define PCI_DEVICE_ID_LAVA_SSERIAL 0x0500 /* 1x 16550 */ +#define PCI_DEVICE_ID_LAVA_PORT_650 0x0600 /* 1x 16650 */ +#define PCI_DEVICE_ID_LAVA_PARALLEL 0x8000 +#define PCI_DEVICE_ID_LAVA_DUAL_PAR_A 0x8002 /* The Lava Dual Parallel is */ +#define PCI_DEVICE_ID_LAVA_DUAL_PAR_B 0x8003 /* two PCI devices on a card */ +#define PCI_DEVICE_ID_LAVA_BOCA_IOPPAR 0x8800 + +#define PCI_VENDOR_ID_TIMEDIA 0x1409 +#define PCI_DEVICE_ID_TIMEDIA_1889 0x7168 + +#define PCI_VENDOR_ID_ICE 0x1412 +#define PCI_DEVICE_ID_ICE_1712 0x1712 +#define PCI_DEVICE_ID_VT1724 0x1724 + +#define PCI_VENDOR_ID_OXSEMI 0x1415 +#define PCI_DEVICE_ID_OXSEMI_12PCI840 0x8403 +#define PCI_DEVICE_ID_OXSEMI_PCIe840 0xC000 +#define PCI_DEVICE_ID_OXSEMI_PCIe840_G 0xC004 +#define PCI_DEVICE_ID_OXSEMI_PCIe952_0 0xC100 +#define PCI_DEVICE_ID_OXSEMI_PCIe952_0_G 0xC104 +#define PCI_DEVICE_ID_OXSEMI_PCIe952_1 0xC110 +#define PCI_DEVICE_ID_OXSEMI_PCIe952_1_G 0xC114 +#define PCI_DEVICE_ID_OXSEMI_PCIe952_1_U 0xC118 +#define PCI_DEVICE_ID_OXSEMI_PCIe952_1_GU 0xC11C +#define PCI_DEVICE_ID_OXSEMI_16PCI954 0x9501 +#define PCI_DEVICE_ID_OXSEMI_16PCI95N 0x9511 +#define PCI_DEVICE_ID_OXSEMI_16PCI954PP 0x9513 +#define PCI_DEVICE_ID_OXSEMI_16PCI952 0x9521 +#define PCI_DEVICE_ID_OXSEMI_16PCI952PP 0x9523 + +#define PCI_VENDOR_ID_CHELSIO 0x1425 + +#define PCI_VENDOR_ID_SAMSUNG 0x144d + +#define PCI_VENDOR_ID_MYRICOM 0x14c1 + +#define PCI_VENDOR_ID_TITAN 0x14D2 +#define PCI_DEVICE_ID_TITAN_010L 0x8001 +#define PCI_DEVICE_ID_TITAN_100L 0x8010 +#define PCI_DEVICE_ID_TITAN_110L 0x8011 +#define PCI_DEVICE_ID_TITAN_200L 0x8020 +#define PCI_DEVICE_ID_TITAN_210L 0x8021 +#define PCI_DEVICE_ID_TITAN_400L 0x8040 +#define PCI_DEVICE_ID_TITAN_800L 0x8080 +#define PCI_DEVICE_ID_TITAN_100 0xA001 +#define PCI_DEVICE_ID_TITAN_200 0xA005 +#define PCI_DEVICE_ID_TITAN_400 0xA003 +#define PCI_DEVICE_ID_TITAN_800B 0xA004 + +#define PCI_VENDOR_ID_PANACOM 0x14d4 +#define PCI_DEVICE_ID_PANACOM_QUADMODEM 0x0400 +#define PCI_DEVICE_ID_PANACOM_DUALMODEM 0x0402 + +#define PCI_VENDOR_ID_SIPACKETS 0x14d9 +#define PCI_DEVICE_ID_SP1011 0x0010 + +#define PCI_VENDOR_ID_AFAVLAB 0x14db +#define PCI_DEVICE_ID_AFAVLAB_P028 0x2180 +#define PCI_DEVICE_ID_AFAVLAB_P030 0x2182 +#define PCI_SUBDEVICE_ID_AFAVLAB_P061 0x2150 + +#define PCI_VENDOR_ID_BROADCOM 0x14e4 +#define PCI_DEVICE_ID_TIGON3_5752 0x1600 +#define PCI_DEVICE_ID_TIGON3_5752M 0x1601 +#define PCI_DEVICE_ID_NX2_5709 0x1639 +#define PCI_DEVICE_ID_NX2_5709S 0x163a +#define PCI_DEVICE_ID_TIGON3_5700 0x1644 +#define PCI_DEVICE_ID_TIGON3_5701 0x1645 +#define PCI_DEVICE_ID_TIGON3_5702 0x1646 +#define PCI_DEVICE_ID_TIGON3_5703 0x1647 +#define PCI_DEVICE_ID_TIGON3_5704 0x1648 +#define PCI_DEVICE_ID_TIGON3_5704S_2 0x1649 +#define PCI_DEVICE_ID_NX2_5706 0x164a +#define PCI_DEVICE_ID_NX2_5708 0x164c +#define PCI_DEVICE_ID_TIGON3_5702FE 0x164d +#define PCI_DEVICE_ID_NX2_57710 0x164e +#define PCI_DEVICE_ID_NX2_57711 0x164f +#define PCI_DEVICE_ID_NX2_57711E 0x1650 +#define PCI_DEVICE_ID_TIGON3_5705 0x1653 +#define PCI_DEVICE_ID_TIGON3_5705_2 0x1654 +#define PCI_DEVICE_ID_TIGON3_5720 0x1658 +#define PCI_DEVICE_ID_TIGON3_5721 0x1659 +#define PCI_DEVICE_ID_TIGON3_5722 0x165a +#define PCI_DEVICE_ID_TIGON3_5723 0x165b +#define PCI_DEVICE_ID_TIGON3_5705M 0x165d +#define PCI_DEVICE_ID_TIGON3_5705M_2 0x165e +#define PCI_DEVICE_ID_TIGON3_5714 0x1668 +#define PCI_DEVICE_ID_TIGON3_5714S 0x1669 +#define PCI_DEVICE_ID_TIGON3_5780 0x166a +#define PCI_DEVICE_ID_TIGON3_5780S 0x166b +#define PCI_DEVICE_ID_TIGON3_5705F 0x166e +#define PCI_DEVICE_ID_TIGON3_5754M 0x1672 +#define PCI_DEVICE_ID_TIGON3_5755M 0x1673 +#define PCI_DEVICE_ID_TIGON3_5756 0x1674 +#define PCI_DEVICE_ID_TIGON3_5750 0x1676 +#define PCI_DEVICE_ID_TIGON3_5751 0x1677 +#define PCI_DEVICE_ID_TIGON3_5715 0x1678 +#define PCI_DEVICE_ID_TIGON3_5715S 0x1679 +#define PCI_DEVICE_ID_TIGON3_5754 0x167a +#define PCI_DEVICE_ID_TIGON3_5755 0x167b +#define PCI_DEVICE_ID_TIGON3_5750M 0x167c +#define PCI_DEVICE_ID_TIGON3_5751M 0x167d +#define PCI_DEVICE_ID_TIGON3_5751F 0x167e +#define PCI_DEVICE_ID_TIGON3_5787F 0x167f +#define PCI_DEVICE_ID_TIGON3_5761E 0x1680 +#define PCI_DEVICE_ID_TIGON3_5761 0x1681 +#define PCI_DEVICE_ID_TIGON3_5764 0x1684 +#define PCI_DEVICE_ID_TIGON3_5787M 0x1693 +#define PCI_DEVICE_ID_TIGON3_5782 0x1696 +#define PCI_DEVICE_ID_TIGON3_5784 0x1698 +#define PCI_DEVICE_ID_TIGON3_5785 0x1699 +#define PCI_DEVICE_ID_TIGON3_5786 0x169a +#define PCI_DEVICE_ID_TIGON3_5787 0x169b +#define PCI_DEVICE_ID_TIGON3_5788 0x169c +#define PCI_DEVICE_ID_TIGON3_5789 0x169d +#define PCI_DEVICE_ID_TIGON3_5702X 0x16a6 +#define PCI_DEVICE_ID_TIGON3_5703X 0x16a7 +#define PCI_DEVICE_ID_TIGON3_5704S 0x16a8 +#define PCI_DEVICE_ID_NX2_5706S 0x16aa +#define PCI_DEVICE_ID_NX2_5708S 0x16ac +#define PCI_DEVICE_ID_TIGON3_5702A3 0x16c6 +#define PCI_DEVICE_ID_TIGON3_5703A3 0x16c7 +#define PCI_DEVICE_ID_TIGON3_5781 0x16dd +#define PCI_DEVICE_ID_TIGON3_5753 0x16f7 +#define PCI_DEVICE_ID_TIGON3_5753M 0x16fd +#define PCI_DEVICE_ID_TIGON3_5753F 0x16fe +#define PCI_DEVICE_ID_TIGON3_5901 0x170d +#define PCI_DEVICE_ID_BCM4401B1 0x170c +#define PCI_DEVICE_ID_TIGON3_5901_2 0x170e +#define PCI_DEVICE_ID_TIGON3_5906 0x1712 +#define PCI_DEVICE_ID_TIGON3_5906M 0x1713 +#define PCI_DEVICE_ID_BCM4401 0x4401 +#define PCI_DEVICE_ID_BCM4401B0 0x4402 + +#define PCI_VENDOR_ID_TOPIC 0x151f +#define PCI_DEVICE_ID_TOPIC_TP560 0x0000 + +#define PCI_VENDOR_ID_MAINPINE 0x1522 +#define PCI_DEVICE_ID_MAINPINE_PBRIDGE 0x0100 +#define PCI_VENDOR_ID_ENE 0x1524 +#define PCI_DEVICE_ID_ENE_CB712_SD 0x0550 +#define PCI_DEVICE_ID_ENE_CB712_SD_2 0x0551 +#define PCI_DEVICE_ID_ENE_CB714_SD 0x0750 +#define PCI_DEVICE_ID_ENE_CB714_SD_2 0x0751 +#define PCI_DEVICE_ID_ENE_1211 0x1211 +#define PCI_DEVICE_ID_ENE_1225 0x1225 +#define PCI_DEVICE_ID_ENE_1410 0x1410 +#define PCI_DEVICE_ID_ENE_710 0x1411 +#define PCI_DEVICE_ID_ENE_712 0x1412 +#define PCI_DEVICE_ID_ENE_1420 0x1420 +#define PCI_DEVICE_ID_ENE_720 0x1421 +#define PCI_DEVICE_ID_ENE_722 0x1422 + +#define PCI_SUBVENDOR_ID_PERLE 0x155f +#define PCI_SUBDEVICE_ID_PCI_RAS4 0xf001 +#define PCI_SUBDEVICE_ID_PCI_RAS8 0xf010 + +#define PCI_VENDOR_ID_SYBA 0x1592 +#define PCI_DEVICE_ID_SYBA_2P_EPP 0x0782 +#define PCI_DEVICE_ID_SYBA_1P_ECP 0x0783 + +#define PCI_VENDOR_ID_MORETON 0x15aa +#define PCI_DEVICE_ID_RASTEL_2PORT 0x2000 + +#define PCI_VENDOR_ID_ZOLTRIX 0x15b0 +#define PCI_DEVICE_ID_ZOLTRIX_2BD0 0x2bd0 + +#define PCI_VENDOR_ID_MELLANOX 0x15b3 +#define PCI_DEVICE_ID_MELLANOX_TAVOR 0x5a44 +#define PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE 0x5a46 +#define PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 0x6278 +#define PCI_DEVICE_ID_MELLANOX_ARBEL 0x6282 +#define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c +#define PCI_DEVICE_ID_MELLANOX_SINAI 0x6274 + +#define PCI_VENDOR_ID_QUICKNET 0x15e2 +#define PCI_DEVICE_ID_QUICKNET_XJ 0x0500 + +/* + * ADDI-DATA GmbH communication cards + */ +#define PCI_VENDOR_ID_ADDIDATA_OLD 0x10E8 +#define PCI_VENDOR_ID_ADDIDATA 0x15B8 +#define PCI_DEVICE_ID_ADDIDATA_APCI7500 0x7000 +#define PCI_DEVICE_ID_ADDIDATA_APCI7420 0x7001 +#define PCI_DEVICE_ID_ADDIDATA_APCI7300 0x7002 +#define PCI_DEVICE_ID_ADDIDATA_APCI7800 0x818E +#define PCI_DEVICE_ID_ADDIDATA_APCI7500_2 0x7009 +#define PCI_DEVICE_ID_ADDIDATA_APCI7420_2 0x700A +#define PCI_DEVICE_ID_ADDIDATA_APCI7300_2 0x700B +#define PCI_DEVICE_ID_ADDIDATA_APCI7500_3 0x700C +#define PCI_DEVICE_ID_ADDIDATA_APCI7420_3 0x700D +#define PCI_DEVICE_ID_ADDIDATA_APCI7300_3 0x700E +#define PCI_DEVICE_ID_ADDIDATA_APCI7800_3 0x700F + +#define PCI_VENDOR_ID_PDC 0x15e9 + +#define PCI_VENDOR_ID_FARSITE 0x1619 +#define PCI_DEVICE_ID_FARSITE_T2P 0x0400 +#define PCI_DEVICE_ID_FARSITE_T4P 0x0440 +#define PCI_DEVICE_ID_FARSITE_T1U 0x0610 +#define PCI_DEVICE_ID_FARSITE_T2U 0x0620 +#define PCI_DEVICE_ID_FARSITE_T4U 0x0640 +#define PCI_DEVICE_ID_FARSITE_TE1 0x1610 +#define PCI_DEVICE_ID_FARSITE_TE1C 0x1612 + +#define PCI_VENDOR_ID_ARIMA 0x161f + +#define PCI_VENDOR_ID_BROCADE 0x1657 + +#define PCI_VENDOR_ID_SIBYTE 0x166d +#define PCI_DEVICE_ID_BCM1250_PCI 0x0001 +#define PCI_DEVICE_ID_BCM1250_HT 0x0002 + +#define PCI_VENDOR_ID_ATHEROS 0x168c + +#define PCI_VENDOR_ID_NETCELL 0x169c +#define PCI_DEVICE_ID_REVOLUTION 0x0044 + +#define PCI_VENDOR_ID_CENATEK 0x16CA +#define PCI_DEVICE_ID_CENATEK_IDE 0x0001 + +#define PCI_VENDOR_ID_VITESSE 0x1725 +#define PCI_DEVICE_ID_VITESSE_VSC7174 0x7174 + +#define PCI_VENDOR_ID_LINKSYS 0x1737 +#define PCI_DEVICE_ID_LINKSYS_EG1064 0x1064 + +#define PCI_VENDOR_ID_ALTIMA 0x173b +#define PCI_DEVICE_ID_ALTIMA_AC1000 0x03e8 +#define PCI_DEVICE_ID_ALTIMA_AC1001 0x03e9 +#define PCI_DEVICE_ID_ALTIMA_AC9100 0x03ea +#define PCI_DEVICE_ID_ALTIMA_AC1003 0x03eb + +#define PCI_VENDOR_ID_BELKIN 0x1799 +#define PCI_DEVICE_ID_BELKIN_F5D7010V7 0x701f + +#define PCI_VENDOR_ID_RDC 0x17f3 +#define PCI_DEVICE_ID_RDC_R6020 0x6020 +#define PCI_DEVICE_ID_RDC_R6030 0x6030 +#define PCI_DEVICE_ID_RDC_R6040 0x6040 +#define PCI_DEVICE_ID_RDC_R6060 0x6060 +#define PCI_DEVICE_ID_RDC_R6061 0x6061 + +#define PCI_VENDOR_ID_LENOVO 0x17aa + +#define PCI_VENDOR_ID_ARECA 0x17d3 +#define PCI_DEVICE_ID_ARECA_1110 0x1110 +#define PCI_DEVICE_ID_ARECA_1120 0x1120 +#define PCI_DEVICE_ID_ARECA_1130 0x1130 +#define PCI_DEVICE_ID_ARECA_1160 0x1160 +#define PCI_DEVICE_ID_ARECA_1170 0x1170 +#define PCI_DEVICE_ID_ARECA_1200 0x1200 +#define PCI_DEVICE_ID_ARECA_1201 0x1201 +#define PCI_DEVICE_ID_ARECA_1202 0x1202 +#define PCI_DEVICE_ID_ARECA_1210 0x1210 +#define PCI_DEVICE_ID_ARECA_1220 0x1220 +#define PCI_DEVICE_ID_ARECA_1230 0x1230 +#define PCI_DEVICE_ID_ARECA_1260 0x1260 +#define PCI_DEVICE_ID_ARECA_1270 0x1270 +#define PCI_DEVICE_ID_ARECA_1280 0x1280 +#define PCI_DEVICE_ID_ARECA_1380 0x1380 +#define PCI_DEVICE_ID_ARECA_1381 0x1381 +#define PCI_DEVICE_ID_ARECA_1680 0x1680 +#define PCI_DEVICE_ID_ARECA_1681 0x1681 + +#define PCI_VENDOR_ID_S2IO 0x17d5 +#define PCI_DEVICE_ID_S2IO_WIN 0x5731 +#define PCI_DEVICE_ID_S2IO_UNI 0x5831 +#define PCI_DEVICE_ID_HERC_WIN 0x5732 +#define PCI_DEVICE_ID_HERC_UNI 0x5832 + +#define PCI_VENDOR_ID_SITECOM 0x182d +#define PCI_DEVICE_ID_SITECOM_DC105V2 0x3069 + +#define PCI_VENDOR_ID_TOPSPIN 0x1867 + +#define PCI_VENDOR_ID_TDI 0x192E +#define PCI_DEVICE_ID_TDI_EHCI 0x0101 + +#define PCI_VENDOR_ID_FREESCALE 0x1957 +#define PCI_DEVICE_ID_MPC8548E 0x0012 +#define PCI_DEVICE_ID_MPC8548 0x0013 +#define PCI_DEVICE_ID_MPC8543E 0x0014 +#define PCI_DEVICE_ID_MPC8543 0x0015 +#define PCI_DEVICE_ID_MPC8547E 0x0018 +#define PCI_DEVICE_ID_MPC8545E 0x0019 +#define PCI_DEVICE_ID_MPC8545 0x001a +#define PCI_DEVICE_ID_MPC8568E 0x0020 +#define PCI_DEVICE_ID_MPC8568 0x0021 +#define PCI_DEVICE_ID_MPC8567E 0x0022 +#define PCI_DEVICE_ID_MPC8567 0x0023 +#define PCI_DEVICE_ID_MPC8533E 0x0030 +#define PCI_DEVICE_ID_MPC8533 0x0031 +#define PCI_DEVICE_ID_MPC8544E 0x0032 +#define PCI_DEVICE_ID_MPC8544 0x0033 +#define PCI_DEVICE_ID_MPC8572E 0x0040 +#define PCI_DEVICE_ID_MPC8572 0x0041 +#define PCI_DEVICE_ID_MPC8536E 0x0050 +#define PCI_DEVICE_ID_MPC8536 0x0051 +#define PCI_DEVICE_ID_MPC8641 0x7010 +#define PCI_DEVICE_ID_MPC8641D 0x7011 +#define PCI_DEVICE_ID_MPC8610 0x7018 + +#define PCI_VENDOR_ID_PASEMI 0x1959 + +#define PCI_VENDOR_ID_ATTANSIC 0x1969 +#define PCI_DEVICE_ID_ATTANSIC_L1 0x1048 +#define PCI_DEVICE_ID_ATTANSIC_L2 0x2048 + +#define PCI_VENDOR_ID_JMICRON 0x197B +#define PCI_DEVICE_ID_JMICRON_JMB360 0x2360 +#define PCI_DEVICE_ID_JMICRON_JMB361 0x2361 +#define PCI_DEVICE_ID_JMICRON_JMB363 0x2363 +#define PCI_DEVICE_ID_JMICRON_JMB365 0x2365 +#define PCI_DEVICE_ID_JMICRON_JMB366 0x2366 +#define PCI_DEVICE_ID_JMICRON_JMB368 0x2368 +#define PCI_DEVICE_ID_JMICRON_JMB38X_SD 0x2381 +#define PCI_DEVICE_ID_JMICRON_JMB38X_MMC 0x2382 +#define PCI_DEVICE_ID_JMICRON_JMB38X_MS 0x2383 + +#define PCI_VENDOR_ID_KORENIX 0x1982 +#define PCI_DEVICE_ID_KORENIX_JETCARDF0 0x1600 +#define PCI_DEVICE_ID_KORENIX_JETCARDF1 0x16ff + +#define PCI_VENDOR_ID_TEKRAM 0x1de1 +#define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29 + +#define PCI_VENDOR_ID_TEHUTI 0x1fc9 +#define PCI_DEVICE_ID_TEHUTI_3009 0x3009 +#define PCI_DEVICE_ID_TEHUTI_3010 0x3010 +#define PCI_DEVICE_ID_TEHUTI_3014 0x3014 + +#define PCI_VENDOR_ID_HINT 0x3388 +#define PCI_DEVICE_ID_HINT_VXPROII_IDE 0x8013 + +#define PCI_VENDOR_ID_3DLABS 0x3d3d +#define PCI_DEVICE_ID_3DLABS_PERMEDIA2 0x0007 +#define PCI_DEVICE_ID_3DLABS_PERMEDIA2V 0x0009 + +#define PCI_VENDOR_ID_NETXEN 0x4040 +#define PCI_DEVICE_ID_NX2031_10GXSR 0x0001 +#define PCI_DEVICE_ID_NX2031_10GCX4 0x0002 +#define PCI_DEVICE_ID_NX2031_4GCU 0x0003 +#define PCI_DEVICE_ID_NX2031_IMEZ 0x0004 +#define PCI_DEVICE_ID_NX2031_HMEZ 0x0005 +#define PCI_DEVICE_ID_NX2031_XG_MGMT 0x0024 +#define PCI_DEVICE_ID_NX2031_XG_MGMT2 0x0025 +#define PCI_DEVICE_ID_NX3031 0x0100 + +#define PCI_VENDOR_ID_AKS 0x416c +#define PCI_DEVICE_ID_AKS_ALADDINCARD 0x0100 + +#define PCI_VENDOR_ID_S3 0x5333 +#define PCI_DEVICE_ID_S3_TRIO 0x8811 +#define PCI_DEVICE_ID_S3_868 0x8880 +#define PCI_DEVICE_ID_S3_968 0x88f0 +#define PCI_DEVICE_ID_S3_SAVAGE4 0x8a25 +#define PCI_DEVICE_ID_S3_PROSAVAGE8 0x8d04 +#define PCI_DEVICE_ID_S3_SONICVIBES 0xca00 + +#define PCI_VENDOR_ID_DUNORD 0x5544 +#define PCI_DEVICE_ID_DUNORD_I3000 0x0001 + +#define PCI_VENDOR_ID_DCI 0x6666 +#define PCI_DEVICE_ID_DCI_PCCOM4 0x0001 +#define PCI_DEVICE_ID_DCI_PCCOM8 0x0002 +#define PCI_DEVICE_ID_DCI_PCCOM2 0x0004 + +#define PCI_VENDOR_ID_INTEL 0x8086 +#define PCI_DEVICE_ID_INTEL_EESSC 0x0008 +#define PCI_DEVICE_ID_INTEL_PXHD_0 0x0320 +#define PCI_DEVICE_ID_INTEL_PXHD_1 0x0321 +#define PCI_DEVICE_ID_INTEL_PXH_0 0x0329 +#define PCI_DEVICE_ID_INTEL_PXH_1 0x032A +#define PCI_DEVICE_ID_INTEL_PXHV 0x032C +#define PCI_DEVICE_ID_INTEL_82375 0x0482 +#define PCI_DEVICE_ID_INTEL_82424 0x0483 +#define PCI_DEVICE_ID_INTEL_82378 0x0484 +#define PCI_DEVICE_ID_INTEL_I960 0x0960 +#define PCI_DEVICE_ID_INTEL_I960RM 0x0962 +#define PCI_DEVICE_ID_INTEL_82815_MC 0x1130 +#define PCI_DEVICE_ID_INTEL_82815_CGC 0x1132 +#define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221 +#define PCI_DEVICE_ID_INTEL_7505_0 0x2550 +#define PCI_DEVICE_ID_INTEL_7205_0 0x255d +#define PCI_DEVICE_ID_INTEL_82437 0x122d +#define PCI_DEVICE_ID_INTEL_82371FB_0 0x122e +#define PCI_DEVICE_ID_INTEL_82371FB_1 0x1230 +#define PCI_DEVICE_ID_INTEL_82371MX 0x1234 +#define PCI_DEVICE_ID_INTEL_82441 0x1237 +#define PCI_DEVICE_ID_INTEL_82380FB 0x124b +#define PCI_DEVICE_ID_INTEL_82439 0x1250 +#define PCI_DEVICE_ID_INTEL_80960_RP 0x1960 +#define PCI_DEVICE_ID_INTEL_82840_HB 0x1a21 +#define PCI_DEVICE_ID_INTEL_82845_HB 0x1a30 +#define PCI_DEVICE_ID_INTEL_IOAT 0x1a38 +#define PCI_DEVICE_ID_INTEL_82801AA_0 0x2410 +#define PCI_DEVICE_ID_INTEL_82801AA_1 0x2411 +#define PCI_DEVICE_ID_INTEL_82801AA_3 0x2413 +#define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415 +#define PCI_DEVICE_ID_INTEL_82801AA_6 0x2416 +#define PCI_DEVICE_ID_INTEL_82801AA_8 0x2418 +#define PCI_DEVICE_ID_INTEL_82801AB_0 0x2420 +#define PCI_DEVICE_ID_INTEL_82801AB_1 0x2421 +#define PCI_DEVICE_ID_INTEL_82801AB_3 0x2423 +#define PCI_DEVICE_ID_INTEL_82801AB_5 0x2425 +#define PCI_DEVICE_ID_INTEL_82801AB_6 0x2426 +#define PCI_DEVICE_ID_INTEL_82801AB_8 0x2428 +#define PCI_DEVICE_ID_INTEL_82801BA_0 0x2440 +#define PCI_DEVICE_ID_INTEL_82801BA_2 0x2443 +#define PCI_DEVICE_ID_INTEL_82801BA_4 0x2445 +#define PCI_DEVICE_ID_INTEL_82801BA_6 0x2448 +#define PCI_DEVICE_ID_INTEL_82801BA_8 0x244a +#define PCI_DEVICE_ID_INTEL_82801BA_9 0x244b +#define PCI_DEVICE_ID_INTEL_82801BA_10 0x244c +#define PCI_DEVICE_ID_INTEL_82801BA_11 0x244e +#define PCI_DEVICE_ID_INTEL_82801E_0 0x2450 +#define PCI_DEVICE_ID_INTEL_82801E_11 0x245b +#define PCI_DEVICE_ID_INTEL_82801CA_0 0x2480 +#define PCI_DEVICE_ID_INTEL_82801CA_3 0x2483 +#define PCI_DEVICE_ID_INTEL_82801CA_5 0x2485 +#define PCI_DEVICE_ID_INTEL_82801CA_6 0x2486 +#define PCI_DEVICE_ID_INTEL_82801CA_10 0x248a +#define PCI_DEVICE_ID_INTEL_82801CA_11 0x248b +#define PCI_DEVICE_ID_INTEL_82801CA_12 0x248c +#define PCI_DEVICE_ID_INTEL_82801DB_0 0x24c0 +#define PCI_DEVICE_ID_INTEL_82801DB_1 0x24c1 +#define PCI_DEVICE_ID_INTEL_82801DB_3 0x24c3 +#define PCI_DEVICE_ID_INTEL_82801DB_5 0x24c5 +#define PCI_DEVICE_ID_INTEL_82801DB_6 0x24c6 +#define PCI_DEVICE_ID_INTEL_82801DB_9 0x24c9 +#define PCI_DEVICE_ID_INTEL_82801DB_10 0x24ca +#define PCI_DEVICE_ID_INTEL_82801DB_11 0x24cb +#define PCI_DEVICE_ID_INTEL_82801DB_12 0x24cc +#define PCI_DEVICE_ID_INTEL_82801EB_0 0x24d0 +#define PCI_DEVICE_ID_INTEL_82801EB_1 0x24d1 +#define PCI_DEVICE_ID_INTEL_82801EB_3 0x24d3 +#define PCI_DEVICE_ID_INTEL_82801EB_5 0x24d5 +#define PCI_DEVICE_ID_INTEL_82801EB_6 0x24d6 +#define PCI_DEVICE_ID_INTEL_82801EB_11 0x24db +#define PCI_DEVICE_ID_INTEL_82801EB_12 0x24dc +#define PCI_DEVICE_ID_INTEL_82801EB_13 0x24dd +#define PCI_DEVICE_ID_INTEL_ESB_1 0x25a1 +#define PCI_DEVICE_ID_INTEL_ESB_2 0x25a2 +#define PCI_DEVICE_ID_INTEL_ESB_4 0x25a4 +#define PCI_DEVICE_ID_INTEL_ESB_5 0x25a6 +#define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab +#define PCI_DEVICE_ID_INTEL_82820_HB 0x2500 +#define PCI_DEVICE_ID_INTEL_82820_UP_HB 0x2501 +#define PCI_DEVICE_ID_INTEL_82850_HB 0x2530 +#define PCI_DEVICE_ID_INTEL_82860_HB 0x2531 +#define PCI_DEVICE_ID_INTEL_E7501_MCH 0x254c +#define PCI_DEVICE_ID_INTEL_82845G_HB 0x2560 +#define PCI_DEVICE_ID_INTEL_82845G_IG 0x2562 +#define PCI_DEVICE_ID_INTEL_82865_HB 0x2570 +#define PCI_DEVICE_ID_INTEL_82865_IG 0x2572 +#define PCI_DEVICE_ID_INTEL_82875_HB 0x2578 +#define PCI_DEVICE_ID_INTEL_82915G_HB 0x2580 +#define PCI_DEVICE_ID_INTEL_82915G_IG 0x2582 +#define PCI_DEVICE_ID_INTEL_82915GM_HB 0x2590 +#define PCI_DEVICE_ID_INTEL_82915GM_IG 0x2592 +#define PCI_DEVICE_ID_INTEL_5000_ERR 0x25F0 +#define PCI_DEVICE_ID_INTEL_5000_FBD0 0x25F5 +#define PCI_DEVICE_ID_INTEL_5000_FBD1 0x25F6 +#define PCI_DEVICE_ID_INTEL_82945G_HB 0x2770 +#define PCI_DEVICE_ID_INTEL_82945G_IG 0x2772 +#define PCI_DEVICE_ID_INTEL_3000_HB 0x2778 +#define PCI_DEVICE_ID_INTEL_82945GM_HB 0x27A0 +#define PCI_DEVICE_ID_INTEL_82945GM_IG 0x27A2 +#define PCI_DEVICE_ID_INTEL_ICH6_0 0x2640 +#define PCI_DEVICE_ID_INTEL_ICH6_1 0x2641 +#define PCI_DEVICE_ID_INTEL_ICH6_2 0x2642 +#define PCI_DEVICE_ID_INTEL_ICH6_16 0x266a +#define PCI_DEVICE_ID_INTEL_ICH6_17 0x266d +#define PCI_DEVICE_ID_INTEL_ICH6_18 0x266e +#define PCI_DEVICE_ID_INTEL_ICH6_19 0x266f +#define PCI_DEVICE_ID_INTEL_ESB2_0 0x2670 +#define PCI_DEVICE_ID_INTEL_ESB2_14 0x2698 +#define PCI_DEVICE_ID_INTEL_ESB2_17 0x269b +#define PCI_DEVICE_ID_INTEL_ESB2_18 0x269e +#define PCI_DEVICE_ID_INTEL_ICH7_0 0x27b8 +#define PCI_DEVICE_ID_INTEL_ICH7_1 0x27b9 +#define PCI_DEVICE_ID_INTEL_ICH7_30 0x27b0 +#define PCI_DEVICE_ID_INTEL_ICH7_31 0x27bd +#define PCI_DEVICE_ID_INTEL_ICH7_17 0x27da +#define PCI_DEVICE_ID_INTEL_ICH7_19 0x27dd +#define PCI_DEVICE_ID_INTEL_ICH7_20 0x27de +#define PCI_DEVICE_ID_INTEL_ICH7_21 0x27df +#define PCI_DEVICE_ID_INTEL_ICH8_0 0x2810 +#define PCI_DEVICE_ID_INTEL_ICH8_1 0x2811 +#define PCI_DEVICE_ID_INTEL_ICH8_2 0x2812 +#define PCI_DEVICE_ID_INTEL_ICH8_3 0x2814 +#define PCI_DEVICE_ID_INTEL_ICH8_4 0x2815 +#define PCI_DEVICE_ID_INTEL_ICH8_5 0x283e +#define PCI_DEVICE_ID_INTEL_ICH8_6 0x2850 +#define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910 +#define PCI_DEVICE_ID_INTEL_ICH9_1 0x2917 +#define PCI_DEVICE_ID_INTEL_ICH9_2 0x2912 +#define PCI_DEVICE_ID_INTEL_ICH9_3 0x2913 +#define PCI_DEVICE_ID_INTEL_ICH9_4 0x2914 +#define PCI_DEVICE_ID_INTEL_ICH9_5 0x2919 +#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930 +#define PCI_DEVICE_ID_INTEL_ICH9_7 0x2916 +#define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918 +#define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340 +#define PCI_DEVICE_ID_INTEL_IOAT_TBG4 0x3429 +#define PCI_DEVICE_ID_INTEL_IOAT_TBG5 0x342a +#define PCI_DEVICE_ID_INTEL_IOAT_TBG6 0x342b +#define PCI_DEVICE_ID_INTEL_IOAT_TBG7 0x342c +#define PCI_DEVICE_ID_INTEL_IOAT_TBG0 0x3430 +#define PCI_DEVICE_ID_INTEL_IOAT_TBG1 0x3431 +#define PCI_DEVICE_ID_INTEL_IOAT_TBG2 0x3432 +#define PCI_DEVICE_ID_INTEL_IOAT_TBG3 0x3433 +#define PCI_DEVICE_ID_INTEL_82830_HB 0x3575 +#define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577 +#define PCI_DEVICE_ID_INTEL_82855GM_HB 0x3580 +#define PCI_DEVICE_ID_INTEL_82855GM_IG 0x3582 +#define PCI_DEVICE_ID_INTEL_E7520_MCH 0x3590 +#define PCI_DEVICE_ID_INTEL_E7320_MCH 0x3592 +#define PCI_DEVICE_ID_INTEL_MCH_PA 0x3595 +#define PCI_DEVICE_ID_INTEL_MCH_PA1 0x3596 +#define PCI_DEVICE_ID_INTEL_MCH_PB 0x3597 +#define PCI_DEVICE_ID_INTEL_MCH_PB1 0x3598 +#define PCI_DEVICE_ID_INTEL_MCH_PC 0x3599 +#define PCI_DEVICE_ID_INTEL_MCH_PC1 0x359a +#define PCI_DEVICE_ID_INTEL_E7525_MCH 0x359e +#define PCI_DEVICE_ID_INTEL_IOAT_CNB 0x360b +#define PCI_DEVICE_ID_INTEL_FBD_CNB 0x360c +#define PCI_DEVICE_ID_INTEL_ICH10_0 0x3a14 +#define PCI_DEVICE_ID_INTEL_ICH10_1 0x3a16 +#define PCI_DEVICE_ID_INTEL_ICH10_2 0x3a18 +#define PCI_DEVICE_ID_INTEL_ICH10_3 0x3a1a +#define PCI_DEVICE_ID_INTEL_ICH10_4 0x3a30 +#define PCI_DEVICE_ID_INTEL_ICH10_5 0x3a60 +#define PCI_DEVICE_ID_INTEL_PCH_LPC_MIN 0x3b00 +#define PCI_DEVICE_ID_INTEL_PCH_LPC_MAX 0x3b1f +#define PCI_DEVICE_ID_INTEL_PCH_SMBUS 0x3b30 +#define PCI_DEVICE_ID_INTEL_IOAT_SNB 0x402f +#define PCI_DEVICE_ID_INTEL_5100_16 0x65f0 +#define PCI_DEVICE_ID_INTEL_5100_21 0x65f5 +#define PCI_DEVICE_ID_INTEL_5100_22 0x65f6 +#define PCI_DEVICE_ID_INTEL_5400_ERR 0x4030 +#define PCI_DEVICE_ID_INTEL_5400_FBD0 0x4035 +#define PCI_DEVICE_ID_INTEL_5400_FBD1 0x4036 +#define PCI_DEVICE_ID_INTEL_IOAT_SCNB 0x65ff +#define PCI_DEVICE_ID_INTEL_TOLAPAI_0 0x5031 +#define PCI_DEVICE_ID_INTEL_TOLAPAI_1 0x5032 +#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000 +#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010 +#define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020 +#define PCI_DEVICE_ID_INTEL_82437VX 0x7030 +#define PCI_DEVICE_ID_INTEL_82439TX 0x7100 +#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110 +#define PCI_DEVICE_ID_INTEL_82371AB 0x7111 +#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112 +#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113 +#define PCI_DEVICE_ID_INTEL_82810_MC1 0x7120 +#define PCI_DEVICE_ID_INTEL_82810_IG1 0x7121 +#define PCI_DEVICE_ID_INTEL_82810_MC3 0x7122 +#define PCI_DEVICE_ID_INTEL_82810_IG3 0x7123 +#define PCI_DEVICE_ID_INTEL_82810E_MC 0x7124 +#define PCI_DEVICE_ID_INTEL_82810E_IG 0x7125 +#define PCI_DEVICE_ID_INTEL_82443LX_0 0x7180 +#define PCI_DEVICE_ID_INTEL_82443LX_1 0x7181 +#define PCI_DEVICE_ID_INTEL_82443BX_0 0x7190 +#define PCI_DEVICE_ID_INTEL_82443BX_1 0x7191 +#define PCI_DEVICE_ID_INTEL_82443BX_2 0x7192 +#define PCI_DEVICE_ID_INTEL_440MX 0x7195 +#define PCI_DEVICE_ID_INTEL_440MX_6 0x7196 +#define PCI_DEVICE_ID_INTEL_82443MX_0 0x7198 +#define PCI_DEVICE_ID_INTEL_82443MX_1 0x7199 +#define PCI_DEVICE_ID_INTEL_82443MX_3 0x719b +#define PCI_DEVICE_ID_INTEL_82443GX_0 0x71a0 +#define PCI_DEVICE_ID_INTEL_82443GX_2 0x71a2 +#define PCI_DEVICE_ID_INTEL_82372FB_1 0x7601 +#define PCI_DEVICE_ID_INTEL_SCH_LPC 0x8119 +#define PCI_DEVICE_ID_INTEL_SCH_IDE 0x811a +#define PCI_DEVICE_ID_INTEL_82454GX 0x84c4 +#define PCI_DEVICE_ID_INTEL_82450GX 0x84c5 +#define PCI_DEVICE_ID_INTEL_82451NX 0x84ca +#define PCI_DEVICE_ID_INTEL_82454NX 0x84cb +#define PCI_DEVICE_ID_INTEL_84460GX 0x84ea +#define PCI_DEVICE_ID_INTEL_IXP4XX 0x8500 +#define PCI_DEVICE_ID_INTEL_IXP2800 0x9004 +#define PCI_DEVICE_ID_INTEL_S21152BB 0xb152 + +#define PCI_VENDOR_ID_SCALEMP 0x8686 +#define PCI_DEVICE_ID_SCALEMP_VSMP_CTL 0x1010 + +#define PCI_VENDOR_ID_COMPUTONE 0x8e0e +#define PCI_DEVICE_ID_COMPUTONE_IP2EX 0x0291 +#define PCI_DEVICE_ID_COMPUTONE_PG 0x0302 +#define PCI_SUBVENDOR_ID_COMPUTONE 0x8e0e +#define PCI_SUBDEVICE_ID_COMPUTONE_PG4 0x0001 +#define PCI_SUBDEVICE_ID_COMPUTONE_PG8 0x0002 +#define PCI_SUBDEVICE_ID_COMPUTONE_PG6 0x0003 + +#define PCI_VENDOR_ID_KTI 0x8e2e + +#define PCI_VENDOR_ID_ADAPTEC 0x9004 +#define PCI_DEVICE_ID_ADAPTEC_7810 0x1078 +#define PCI_DEVICE_ID_ADAPTEC_7821 0x2178 +#define PCI_DEVICE_ID_ADAPTEC_38602 0x3860 +#define PCI_DEVICE_ID_ADAPTEC_7850 0x5078 +#define PCI_DEVICE_ID_ADAPTEC_7855 0x5578 +#define PCI_DEVICE_ID_ADAPTEC_3860 0x6038 +#define PCI_DEVICE_ID_ADAPTEC_1480A 0x6075 +#define PCI_DEVICE_ID_ADAPTEC_7860 0x6078 +#define PCI_DEVICE_ID_ADAPTEC_7861 0x6178 +#define PCI_DEVICE_ID_ADAPTEC_7870 0x7078 +#define PCI_DEVICE_ID_ADAPTEC_7871 0x7178 +#define PCI_DEVICE_ID_ADAPTEC_7872 0x7278 +#define PCI_DEVICE_ID_ADAPTEC_7873 0x7378 +#define PCI_DEVICE_ID_ADAPTEC_7874 0x7478 +#define PCI_DEVICE_ID_ADAPTEC_7895 0x7895 +#define PCI_DEVICE_ID_ADAPTEC_7880 0x8078 +#define PCI_DEVICE_ID_ADAPTEC_7881 0x8178 +#define PCI_DEVICE_ID_ADAPTEC_7882 0x8278 +#define PCI_DEVICE_ID_ADAPTEC_7883 0x8378 +#define PCI_DEVICE_ID_ADAPTEC_7884 0x8478 +#define PCI_DEVICE_ID_ADAPTEC_7885 0x8578 +#define PCI_DEVICE_ID_ADAPTEC_7886 0x8678 +#define PCI_DEVICE_ID_ADAPTEC_7887 0x8778 +#define PCI_DEVICE_ID_ADAPTEC_7888 0x8878 + +#define PCI_VENDOR_ID_ADAPTEC2 0x9005 +#define PCI_DEVICE_ID_ADAPTEC2_2940U2 0x0010 +#define PCI_DEVICE_ID_ADAPTEC2_2930U2 0x0011 +#define PCI_DEVICE_ID_ADAPTEC2_7890B 0x0013 +#define PCI_DEVICE_ID_ADAPTEC2_7890 0x001f +#define PCI_DEVICE_ID_ADAPTEC2_3940U2 0x0050 +#define PCI_DEVICE_ID_ADAPTEC2_3950U2D 0x0051 +#define PCI_DEVICE_ID_ADAPTEC2_7896 0x005f +#define PCI_DEVICE_ID_ADAPTEC2_7892A 0x0080 +#define PCI_DEVICE_ID_ADAPTEC2_7892B 0x0081 +#define PCI_DEVICE_ID_ADAPTEC2_7892D 0x0083 +#define PCI_DEVICE_ID_ADAPTEC2_7892P 0x008f +#define PCI_DEVICE_ID_ADAPTEC2_7899A 0x00c0 +#define PCI_DEVICE_ID_ADAPTEC2_7899B 0x00c1 +#define PCI_DEVICE_ID_ADAPTEC2_7899D 0x00c3 +#define PCI_DEVICE_ID_ADAPTEC2_7899P 0x00cf +#define PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN 0x0500 +#define PCI_DEVICE_ID_ADAPTEC2_SCAMP 0x0503 + +#define PCI_VENDOR_ID_HOLTEK 0x9412 +#define PCI_DEVICE_ID_HOLTEK_6565 0x6565 + +#define PCI_VENDOR_ID_NETMOS 0x9710 +#define PCI_DEVICE_ID_NETMOS_9705 0x9705 +#define PCI_DEVICE_ID_NETMOS_9715 0x9715 +#define PCI_DEVICE_ID_NETMOS_9735 0x9735 +#define PCI_DEVICE_ID_NETMOS_9745 0x9745 +#define PCI_DEVICE_ID_NETMOS_9755 0x9755 +#define PCI_DEVICE_ID_NETMOS_9805 0x9805 +#define PCI_DEVICE_ID_NETMOS_9815 0x9815 +#define PCI_DEVICE_ID_NETMOS_9835 0x9835 +#define PCI_DEVICE_ID_NETMOS_9845 0x9845 +#define PCI_DEVICE_ID_NETMOS_9855 0x9855 + +#define PCI_VENDOR_ID_3COM_2 0xa727 + +#define PCI_VENDOR_ID_DIGIUM 0xd161 +#define PCI_DEVICE_ID_DIGIUM_HFC4S 0xb410 + +#define PCI_SUBVENDOR_ID_EXSYS 0xd84d +#define PCI_SUBDEVICE_ID_EXSYS_4014 0x4014 +#define PCI_SUBDEVICE_ID_EXSYS_4055 0x4055 + +#define PCI_VENDOR_ID_TIGERJET 0xe159 +#define PCI_DEVICE_ID_TIGERJET_300 0x0001 +#define PCI_DEVICE_ID_TIGERJET_100 0x0002 + +#define PCI_VENDOR_ID_XILINX_RME 0xea60 +#define PCI_DEVICE_ID_RME_DIGI32 0x9896 +#define PCI_DEVICE_ID_RME_DIGI32_PRO 0x9897 +#define PCI_DEVICE_ID_RME_DIGI32_8 0x9898 + +#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 +#define PCI_DEVICE_ID_VIRTIO_BLK 0x1001 diff --git a/bios/seabios/src/pci_regs.h b/bios/seabios/src/pci_regs.h new file mode 100644 index 0000000..e5effd4 --- /dev/null +++ b/bios/seabios/src/pci_regs.h @@ -0,0 +1,556 @@ +/* + * pci_regs.h + * + * PCI standard defines + * Copyright 1994, Drew Eckhardt + * Copyright 1997--1999 Martin Mares + * + * For more information, please consult the following manuals (look at + * http://www.pcisig.com/ for how to get them): + * + * PCI BIOS Specification + * PCI Local Bus Specification + * PCI to PCI Bridge Specification + * PCI System Design Guide + * + * For hypertransport information, please consult the following manuals + * from http://www.hypertransport.org + * + * The Hypertransport I/O Link Specification + */ + +#ifndef LINUX_PCI_REGS_H +#define LINUX_PCI_REGS_H + +/* + * Under PCI, each device has 256 bytes of configuration address space, + * of which the first 64 bytes are standardized as follows: + */ +#define PCI_VENDOR_ID 0x00 /* 16 bits */ +#define PCI_DEVICE_ID 0x02 /* 16 bits */ +#define PCI_COMMAND 0x04 /* 16 bits */ +#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ +#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ +#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */ +#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */ +#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */ +#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */ +#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */ +#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */ +#define PCI_COMMAND_SERR 0x100 /* Enable SERR */ +#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */ +#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */ + +#define PCI_STATUS 0x06 /* 16 bits */ +#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ +#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */ +#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */ +#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */ +#define PCI_STATUS_PARITY 0x100 /* Detected parity error */ +#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */ +#define PCI_STATUS_DEVSEL_FAST 0x000 +#define PCI_STATUS_DEVSEL_MEDIUM 0x200 +#define PCI_STATUS_DEVSEL_SLOW 0x400 +#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */ +#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */ +#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */ +#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */ +#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */ + +#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8 revision */ +#define PCI_REVISION_ID 0x08 /* Revision ID */ +#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */ +#define PCI_CLASS_DEVICE 0x0a /* Device class */ + +#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */ +#define PCI_LATENCY_TIMER 0x0d /* 8 bits */ +#define PCI_HEADER_TYPE 0x0e /* 8 bits */ +#define PCI_HEADER_TYPE_NORMAL 0 +#define PCI_HEADER_TYPE_BRIDGE 1 +#define PCI_HEADER_TYPE_CARDBUS 2 + +#define PCI_BIST 0x0f /* 8 bits */ +#define PCI_BIST_CODE_MASK 0x0f /* Return result */ +#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or less */ +#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */ + +/* + * Base addresses specify locations in memory or I/O space. + * Decoded size can be determined by writing a value of + * 0xffffffff to the register, and reading it back. Only + * 1 bits are decoded. + */ +#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */ +#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */ +#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */ +#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */ +#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */ +#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */ +#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */ +#define PCI_BASE_ADDRESS_SPACE_IO 0x01 +#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00 +#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06 +#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */ +#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */ +#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */ +#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */ +#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL) +#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL) +/* bit 1 is reserved if address_space = 1 */ + +/* Header type 0 (normal devices) */ +#define PCI_CARDBUS_CIS 0x28 +#define PCI_SUBSYSTEM_VENDOR_ID 0x2c +#define PCI_SUBSYSTEM_ID 0x2e +#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */ +#define PCI_ROM_ADDRESS_ENABLE 0x01 +#define PCI_ROM_ADDRESS_MASK (~0x7ffUL) + +#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */ + +/* 0x35-0x3b are reserved */ +#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ +#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ +#define PCI_MIN_GNT 0x3e /* 8 bits */ +#define PCI_MAX_LAT 0x3f /* 8 bits */ + +/* Header type 1 (PCI-to-PCI bridges) */ +#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */ +#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */ +#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */ +#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */ +#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */ +#define PCI_IO_LIMIT 0x1d +#define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */ +#define PCI_IO_RANGE_TYPE_16 0x00 +#define PCI_IO_RANGE_TYPE_32 0x01 +#define PCI_IO_RANGE_MASK (~0x0fUL) +#define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */ +#define PCI_MEMORY_BASE 0x20 /* Memory range behind */ +#define PCI_MEMORY_LIMIT 0x22 +#define PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL +#define PCI_MEMORY_RANGE_MASK (~0x0fUL) +#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */ +#define PCI_PREF_MEMORY_LIMIT 0x26 +#define PCI_PREF_RANGE_TYPE_MASK 0x0fUL +#define PCI_PREF_RANGE_TYPE_32 0x00 +#define PCI_PREF_RANGE_TYPE_64 0x01 +#define PCI_PREF_RANGE_MASK (~0x0fUL) +#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */ +#define PCI_PREF_LIMIT_UPPER32 0x2c +#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */ +#define PCI_IO_LIMIT_UPPER16 0x32 +/* 0x34 same as for htype 0 */ +/* 0x35-0x3b is reserved */ +#define PCI_ROM_ADDRESS1 0x38 /* Same as PCI_ROM_ADDRESS, but for htype 1 */ +/* 0x3c-0x3d are same as for htype 0 */ +#define PCI_BRIDGE_CONTROL 0x3e +#define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on secondary interface */ +#define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */ +#define PCI_BRIDGE_CTL_ISA 0x04 /* Enable ISA mode */ +#define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */ +#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */ +#define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */ +#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on secondary interface */ + +/* Header type 2 (CardBus bridges) */ +#define PCI_CB_CAPABILITY_LIST 0x14 +/* 0x15 reserved */ +#define PCI_CB_SEC_STATUS 0x16 /* Secondary status */ +#define PCI_CB_PRIMARY_BUS 0x18 /* PCI bus number */ +#define PCI_CB_CARD_BUS 0x19 /* CardBus bus number */ +#define PCI_CB_SUBORDINATE_BUS 0x1a /* Subordinate bus number */ +#define PCI_CB_LATENCY_TIMER 0x1b /* CardBus latency timer */ +#define PCI_CB_MEMORY_BASE_0 0x1c +#define PCI_CB_MEMORY_LIMIT_0 0x20 +#define PCI_CB_MEMORY_BASE_1 0x24 +#define PCI_CB_MEMORY_LIMIT_1 0x28 +#define PCI_CB_IO_BASE_0 0x2c +#define PCI_CB_IO_BASE_0_HI 0x2e +#define PCI_CB_IO_LIMIT_0 0x30 +#define PCI_CB_IO_LIMIT_0_HI 0x32 +#define PCI_CB_IO_BASE_1 0x34 +#define PCI_CB_IO_BASE_1_HI 0x36 +#define PCI_CB_IO_LIMIT_1 0x38 +#define PCI_CB_IO_LIMIT_1_HI 0x3a +#define PCI_CB_IO_RANGE_MASK (~0x03UL) +/* 0x3c-0x3d are same as for htype 0 */ +#define PCI_CB_BRIDGE_CONTROL 0x3e +#define PCI_CB_BRIDGE_CTL_PARITY 0x01 /* Similar to standard bridge control register */ +#define PCI_CB_BRIDGE_CTL_SERR 0x02 +#define PCI_CB_BRIDGE_CTL_ISA 0x04 +#define PCI_CB_BRIDGE_CTL_VGA 0x08 +#define PCI_CB_BRIDGE_CTL_MASTER_ABORT 0x20 +#define PCI_CB_BRIDGE_CTL_CB_RESET 0x40 /* CardBus reset */ +#define PCI_CB_BRIDGE_CTL_16BIT_INT 0x80 /* Enable interrupt for 16-bit cards */ +#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both memory regions */ +#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200 +#define PCI_CB_BRIDGE_CTL_POST_WRITES 0x400 +#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40 +#define PCI_CB_SUBSYSTEM_ID 0x42 +#define PCI_CB_LEGACY_MODE_BASE 0x44 /* 16-bit PC Card legacy mode base address (ExCa) */ +/* 0x48-0x7f reserved */ + +/* Capability lists */ + +#define PCI_CAP_LIST_ID 0 /* Capability ID */ +#define PCI_CAP_ID_PM 0x01 /* Power Management */ +#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */ +#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */ +#define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */ +#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ +#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ +#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ +#define PCI_CAP_ID_HT 0x08 /* HyperTransport */ +#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific */ +#define PCI_CAP_ID_DBG 0x0A /* Debug port */ +#define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */ +#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ +#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */ +#define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */ +#define PCI_CAP_ID_EXP 0x10 /* PCI Express */ +#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ +#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ +#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ +#define PCI_CAP_SIZEOF 4 + +/* Power Management Registers */ + +#define PCI_PM_PMC 2 /* PM Capabilities Register */ +#define PCI_PM_CAP_VER_MASK 0x0007 /* Version */ +#define PCI_PM_CAP_PME_CLOCK 0x0008 /* PME clock required */ +#define PCI_PM_CAP_RESERVED 0x0010 /* Reserved field */ +#define PCI_PM_CAP_DSI 0x0020 /* Device specific initialization */ +#define PCI_PM_CAP_AUX_POWER 0x01C0 /* Auxilliary power support mask */ +#define PCI_PM_CAP_D1 0x0200 /* D1 power state support */ +#define PCI_PM_CAP_D2 0x0400 /* D2 power state support */ +#define PCI_PM_CAP_PME 0x0800 /* PME pin supported */ +#define PCI_PM_CAP_PME_MASK 0xF800 /* PME Mask of all supported states */ +#define PCI_PM_CAP_PME_D0 0x0800 /* PME# from D0 */ +#define PCI_PM_CAP_PME_D1 0x1000 /* PME# from D1 */ +#define PCI_PM_CAP_PME_D2 0x2000 /* PME# from D2 */ +#define PCI_PM_CAP_PME_D3 0x4000 /* PME# from D3 (hot) */ +#define PCI_PM_CAP_PME_D3cold 0x8000 /* PME# from D3 (cold) */ +#define PCI_PM_CAP_PME_SHIFT 11 /* Start of the PME Mask in PMC */ +#define PCI_PM_CTRL 4 /* PM control and status register */ +#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to D3) */ +#define PCI_PM_CTRL_NO_SOFT_RESET 0x0004 /* No reset for D3hot->D0 */ +#define PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */ +#define PCI_PM_CTRL_DATA_SEL_MASK 0x1e00 /* Data select (??) */ +#define PCI_PM_CTRL_DATA_SCALE_MASK 0x6000 /* Data scale (??) */ +#define PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */ +#define PCI_PM_PPB_EXTENSIONS 6 /* PPB support extensions (??) */ +#define PCI_PM_PPB_B2_B3 0x40 /* Stop clock when in D3hot (??) */ +#define PCI_PM_BPCC_ENABLE 0x80 /* Bus power/clock control enable (??) */ +#define PCI_PM_DATA_REGISTER 7 /* (??) */ +#define PCI_PM_SIZEOF 8 + +/* AGP registers */ + +#define PCI_AGP_VERSION 2 /* BCD version number */ +#define PCI_AGP_RFU 3 /* Rest of capability flags */ +#define PCI_AGP_STATUS 4 /* Status register */ +#define PCI_AGP_STATUS_RQ_MASK 0xff000000 /* Maximum number of requests - 1 */ +#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing supported */ +#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing supported */ +#define PCI_AGP_STATUS_FW 0x0010 /* FW transfers supported */ +#define PCI_AGP_STATUS_RATE4 0x0004 /* 4x transfer rate supported */ +#define PCI_AGP_STATUS_RATE2 0x0002 /* 2x transfer rate supported */ +#define PCI_AGP_STATUS_RATE1 0x0001 /* 1x transfer rate supported */ +#define PCI_AGP_COMMAND 8 /* Control register */ +#define PCI_AGP_COMMAND_RQ_MASK 0xff000000 /* Master: Maximum number of requests */ +#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enabled */ +#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP transactions */ +#define PCI_AGP_COMMAND_64BIT 0x0020 /* Allow processing of 64-bit addresses */ +#define PCI_AGP_COMMAND_FW 0x0010 /* Force FW transfers */ +#define PCI_AGP_COMMAND_RATE4 0x0004 /* Use 4x rate */ +#define PCI_AGP_COMMAND_RATE2 0x0002 /* Use 2x rate */ +#define PCI_AGP_COMMAND_RATE1 0x0001 /* Use 1x rate */ +#define PCI_AGP_SIZEOF 12 + +/* Vital Product Data */ + +#define PCI_VPD_ADDR 2 /* Address to access (15 bits!) */ +#define PCI_VPD_ADDR_MASK 0x7fff /* Address mask */ +#define PCI_VPD_ADDR_F 0x8000 /* Write 0, 1 indicates completion */ +#define PCI_VPD_DATA 4 /* 32-bits of data returned here */ + +/* Slot Identification */ + +#define PCI_SID_ESR 2 /* Expansion Slot Register */ +#define PCI_SID_ESR_NSLOTS 0x1f /* Number of expansion slots available */ +#define PCI_SID_ESR_FIC 0x20 /* First In Chassis Flag */ +#define PCI_SID_CHASSIS_NR 3 /* Chassis Number */ + +/* Message Signalled Interrupts registers */ + +#define PCI_MSI_FLAGS 2 /* Various flags */ +#define PCI_MSI_FLAGS_64BIT 0x80 /* 64-bit addresses allowed */ +#define PCI_MSI_FLAGS_QSIZE 0x70 /* Message queue size configured */ +#define PCI_MSI_FLAGS_QMASK 0x0e /* Maximum queue size available */ +#define PCI_MSI_FLAGS_ENABLE 0x01 /* MSI feature enabled */ +#define PCI_MSI_FLAGS_MASKBIT 0x100 /* 64-bit mask bits allowed */ +#define PCI_MSI_RFU 3 /* Rest of capability flags */ +#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */ +#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */ +#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */ +#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */ +#define PCI_MSI_MASK_BIT 16 /* Mask bits register */ + +/* MSI-X registers (these are at offset PCI_MSIX_FLAGS) */ +#define PCI_MSIX_FLAGS 2 +#define PCI_MSIX_FLAGS_QSIZE 0x7FF +#define PCI_MSIX_FLAGS_ENABLE (1 << 15) +#define PCI_MSIX_FLAGS_MASKALL (1 << 14) +#define PCI_MSIX_FLAGS_BIRMASK (7 << 0) +#define PCI_MSIX_FLAGS_BITMASK (1 << 0) + +/* CompactPCI Hotswap Register */ + +#define PCI_CHSWP_CSR 2 /* Control and Status Register */ +#define PCI_CHSWP_DHA 0x01 /* Device Hiding Arm */ +#define PCI_CHSWP_EIM 0x02 /* ENUM# Signal Mask */ +#define PCI_CHSWP_PIE 0x04 /* Pending Insert or Extract */ +#define PCI_CHSWP_LOO 0x08 /* LED On / Off */ +#define PCI_CHSWP_PI 0x30 /* Programming Interface */ +#define PCI_CHSWP_EXT 0x40 /* ENUM# status - extraction */ +#define PCI_CHSWP_INS 0x80 /* ENUM# status - insertion */ + +/* PCI-X registers */ + +#define PCI_X_CMD 2 /* Modes & Features */ +#define PCI_X_CMD_DPERR_E 0x0001 /* Data Parity Error Recovery Enable */ +#define PCI_X_CMD_ERO 0x0002 /* Enable Relaxed Ordering */ +#define PCI_X_CMD_READ_512 0x0000 /* 512 byte maximum read byte count */ +#define PCI_X_CMD_READ_1K 0x0004 /* 1Kbyte maximum read byte count */ +#define PCI_X_CMD_READ_2K 0x0008 /* 2Kbyte maximum read byte count */ +#define PCI_X_CMD_READ_4K 0x000c /* 4Kbyte maximum read byte count */ +#define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */ + /* Max # of outstanding split transactions */ +#define PCI_X_CMD_SPLIT_1 0x0000 /* Max 1 */ +#define PCI_X_CMD_SPLIT_2 0x0010 /* Max 2 */ +#define PCI_X_CMD_SPLIT_3 0x0020 /* Max 3 */ +#define PCI_X_CMD_SPLIT_4 0x0030 /* Max 4 */ +#define PCI_X_CMD_SPLIT_8 0x0040 /* Max 8 */ +#define PCI_X_CMD_SPLIT_12 0x0050 /* Max 12 */ +#define PCI_X_CMD_SPLIT_16 0x0060 /* Max 16 */ +#define PCI_X_CMD_SPLIT_32 0x0070 /* Max 32 */ +#define PCI_X_CMD_MAX_SPLIT 0x0070 /* Max Outstanding Split Transactions */ +#define PCI_X_CMD_VERSION(x) (((x) >> 12) & 3) /* Version */ +#define PCI_X_STATUS 4 /* PCI-X capabilities */ +#define PCI_X_STATUS_DEVFN 0x000000ff /* A copy of devfn */ +#define PCI_X_STATUS_BUS 0x0000ff00 /* A copy of bus nr */ +#define PCI_X_STATUS_64BIT 0x00010000 /* 64-bit device */ +#define PCI_X_STATUS_133MHZ 0x00020000 /* 133 MHz capable */ +#define PCI_X_STATUS_SPL_DISC 0x00040000 /* Split Completion Discarded */ +#define PCI_X_STATUS_UNX_SPL 0x00080000 /* Unexpected Split Completion */ +#define PCI_X_STATUS_COMPLEX 0x00100000 /* Device Complexity */ +#define PCI_X_STATUS_MAX_READ 0x00600000 /* Designed Max Memory Read Count */ +#define PCI_X_STATUS_MAX_SPLIT 0x03800000 /* Designed Max Outstanding Split Transactions */ +#define PCI_X_STATUS_MAX_CUM 0x1c000000 /* Designed Max Cumulative Read Size */ +#define PCI_X_STATUS_SPL_ERR 0x20000000 /* Rcvd Split Completion Error Msg */ +#define PCI_X_STATUS_266MHZ 0x40000000 /* 266 MHz capable */ +#define PCI_X_STATUS_533MHZ 0x80000000 /* 533 MHz capable */ + +/* PCI Express capability registers */ + +#define PCI_EXP_FLAGS 2 /* Capabilities register */ +#define PCI_EXP_FLAGS_VERS 0x000f /* Capability version */ +#define PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */ +#define PCI_EXP_TYPE_ENDPOINT 0x0 /* Express Endpoint */ +#define PCI_EXP_TYPE_LEG_END 0x1 /* Legacy Endpoint */ +#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */ +#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */ +#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */ +#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCI/PCI-X Bridge */ +#define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */ +#define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */ +#define PCI_EXP_DEVCAP 4 /* Device capabilities */ +#define PCI_EXP_DEVCAP_PAYLOAD 0x07 /* Max_Payload_Size */ +#define PCI_EXP_DEVCAP_PHANTOM 0x18 /* Phantom functions */ +#define PCI_EXP_DEVCAP_EXT_TAG 0x20 /* Extended tags */ +#define PCI_EXP_DEVCAP_L0S 0x1c0 /* L0s Acceptable Latency */ +#define PCI_EXP_DEVCAP_L1 0xe00 /* L1 Acceptable Latency */ +#define PCI_EXP_DEVCAP_ATN_BUT 0x1000 /* Attention Button Present */ +#define PCI_EXP_DEVCAP_ATN_IND 0x2000 /* Attention Indicator Present */ +#define PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Present */ +#define PCI_EXP_DEVCAP_RBER 0x8000 /* Role-Based Error Reporting */ +#define PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */ +#define PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */ +#define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */ +#define PCI_EXP_DEVCTL 8 /* Device Control */ +#define PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */ +#define PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */ +#define PCI_EXP_DEVCTL_FERE 0x0004 /* Fatal Error Reporting Enable */ +#define PCI_EXP_DEVCTL_URRE 0x0008 /* Unsupported Request Reporting En. */ +#define PCI_EXP_DEVCTL_RELAX_EN 0x0010 /* Enable relaxed ordering */ +#define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */ +#define PCI_EXP_DEVCTL_EXT_TAG 0x0100 /* Extended Tag Field Enable */ +#define PCI_EXP_DEVCTL_PHANTOM 0x0200 /* Phantom Functions Enable */ +#define PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable */ +#define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */ +#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ +#define PCI_EXP_DEVCTL_BCR_FLR 0x8000 /* Bridge Configuration Retry / FLR */ +#define PCI_EXP_DEVSTA 10 /* Device Status */ +#define PCI_EXP_DEVSTA_CED 0x01 /* Correctable Error Detected */ +#define PCI_EXP_DEVSTA_NFED 0x02 /* Non-Fatal Error Detected */ +#define PCI_EXP_DEVSTA_FED 0x04 /* Fatal Error Detected */ +#define PCI_EXP_DEVSTA_URD 0x08 /* Unsupported Request Detected */ +#define PCI_EXP_DEVSTA_AUXPD 0x10 /* AUX Power Detected */ +#define PCI_EXP_DEVSTA_TRPND 0x20 /* Transactions Pending */ +#define PCI_EXP_LNKCAP 12 /* Link Capabilities */ +#define PCI_EXP_LNKCAP_ASPMS 0xc00 /* ASPM Support */ +#define PCI_EXP_LNKCAP_L0SEL 0x7000 /* L0s Exit Latency */ +#define PCI_EXP_LNKCAP_L1EL 0x38000 /* L1 Exit Latency */ +#define PCI_EXP_LNKCAP_CLKPM 0x40000 /* L1 Clock Power Management */ +#define PCI_EXP_LNKCTL 16 /* Link Control */ +#define PCI_EXP_LNKCTL_RL 0x20 /* Retrain Link */ +#define PCI_EXP_LNKCTL_CCC 0x40 /* Common Clock COnfiguration */ +#define PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */ +#define PCI_EXP_LNKSTA 18 /* Link Status */ +#define PCI_EXP_LNKSTA_LT 0x800 /* Link Training */ +#define PCI_EXP_LNKSTA_SLC 0x1000 /* Slot Clock Configuration */ +#define PCI_EXP_SLTCAP 20 /* Slot Capabilities */ +#define PCI_EXP_SLTCTL 24 /* Slot Control */ +#define PCI_EXP_SLTSTA 26 /* Slot Status */ +#define PCI_EXP_RTCTL 28 /* Root Control */ +#define PCI_EXP_RTCTL_SECEE 0x01 /* System Error on Correctable Error */ +#define PCI_EXP_RTCTL_SENFEE 0x02 /* System Error on Non-Fatal Error */ +#define PCI_EXP_RTCTL_SEFEE 0x04 /* System Error on Fatal Error */ +#define PCI_EXP_RTCTL_PMEIE 0x08 /* PME Interrupt Enable */ +#define PCI_EXP_RTCTL_CRSSVE 0x10 /* CRS Software Visibility Enable */ +#define PCI_EXP_RTCAP 30 /* Root Capabilities */ +#define PCI_EXP_RTSTA 32 /* Root Status */ +#define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */ +#define PCI_EXP_DEVCAP2_ARI 0x20 /* Alternative Routing-ID */ +#define PCI_EXP_DEVCTL2 40 /* Device Control 2 */ +#define PCI_EXP_DEVCTL2_ARI 0x20 /* Alternative Routing-ID */ + +/* Extended Capabilities (PCI-X 2.0 and Express) */ +#define PCI_EXT_CAP_ID(header) (header & 0x0000ffff) +#define PCI_EXT_CAP_VER(header) ((header >> 16) & 0xf) +#define PCI_EXT_CAP_NEXT(header) ((header >> 20) & 0xffc) + +#define PCI_EXT_CAP_ID_ERR 1 +#define PCI_EXT_CAP_ID_VC 2 +#define PCI_EXT_CAP_ID_DSN 3 +#define PCI_EXT_CAP_ID_PWR 4 +#define PCI_EXT_CAP_ID_ARI 14 + +/* Advanced Error Reporting */ +#define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */ +#define PCI_ERR_UNC_TRAIN 0x00000001 /* Training */ +#define PCI_ERR_UNC_DLP 0x00000010 /* Data Link Protocol */ +#define PCI_ERR_UNC_POISON_TLP 0x00001000 /* Poisoned TLP */ +#define PCI_ERR_UNC_FCP 0x00002000 /* Flow Control Protocol */ +#define PCI_ERR_UNC_COMP_TIME 0x00004000 /* Completion Timeout */ +#define PCI_ERR_UNC_COMP_ABORT 0x00008000 /* Completer Abort */ +#define PCI_ERR_UNC_UNX_COMP 0x00010000 /* Unexpected Completion */ +#define PCI_ERR_UNC_RX_OVER 0x00020000 /* Receiver Overflow */ +#define PCI_ERR_UNC_MALF_TLP 0x00040000 /* Malformed TLP */ +#define PCI_ERR_UNC_ECRC 0x00080000 /* ECRC Error Status */ +#define PCI_ERR_UNC_UNSUP 0x00100000 /* Unsupported Request */ +#define PCI_ERR_UNCOR_MASK 8 /* Uncorrectable Error Mask */ + /* Same bits as above */ +#define PCI_ERR_UNCOR_SEVER 12 /* Uncorrectable Error Severity */ + /* Same bits as above */ +#define PCI_ERR_COR_STATUS 16 /* Correctable Error Status */ +#define PCI_ERR_COR_RCVR 0x00000001 /* Receiver Error Status */ +#define PCI_ERR_COR_BAD_TLP 0x00000040 /* Bad TLP Status */ +#define PCI_ERR_COR_BAD_DLLP 0x00000080 /* Bad DLLP Status */ +#define PCI_ERR_COR_REP_ROLL 0x00000100 /* REPLAY_NUM Rollover */ +#define PCI_ERR_COR_REP_TIMER 0x00001000 /* Replay Timer Timeout */ +#define PCI_ERR_COR_MASK 20 /* Correctable Error Mask */ + /* Same bits as above */ +#define PCI_ERR_CAP 24 /* Advanced Error Capabilities */ +#define PCI_ERR_CAP_FEP(x) ((x) & 31) /* First Error Pointer */ +#define PCI_ERR_CAP_ECRC_GENC 0x00000020 /* ECRC Generation Capable */ +#define PCI_ERR_CAP_ECRC_GENE 0x00000040 /* ECRC Generation Enable */ +#define PCI_ERR_CAP_ECRC_CHKC 0x00000080 /* ECRC Check Capable */ +#define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */ +#define PCI_ERR_HEADER_LOG 28 /* Header Log Register (16 bytes) */ +#define PCI_ERR_ROOT_COMMAND 44 /* Root Error Command */ +/* Correctable Err Reporting Enable */ +#define PCI_ERR_ROOT_CMD_COR_EN 0x00000001 +/* Non-fatal Err Reporting Enable */ +#define PCI_ERR_ROOT_CMD_NONFATAL_EN 0x00000002 +/* Fatal Err Reporting Enable */ +#define PCI_ERR_ROOT_CMD_FATAL_EN 0x00000004 +#define PCI_ERR_ROOT_STATUS 48 +#define PCI_ERR_ROOT_COR_RCV 0x00000001 /* ERR_COR Received */ +/* Multi ERR_COR Received */ +#define PCI_ERR_ROOT_MULTI_COR_RCV 0x00000002 +/* ERR_FATAL/NONFATAL Recevied */ +#define PCI_ERR_ROOT_UNCOR_RCV 0x00000004 +/* Multi ERR_FATAL/NONFATAL Recevied */ +#define PCI_ERR_ROOT_MULTI_UNCOR_RCV 0x00000008 +#define PCI_ERR_ROOT_FIRST_FATAL 0x00000010 /* First Fatal */ +#define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020 /* Non-Fatal Received */ +#define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Received */ +#define PCI_ERR_ROOT_COR_SRC 52 +#define PCI_ERR_ROOT_SRC 54 + +/* Virtual Channel */ +#define PCI_VC_PORT_REG1 4 +#define PCI_VC_PORT_REG2 8 +#define PCI_VC_PORT_CTRL 12 +#define PCI_VC_PORT_STATUS 14 +#define PCI_VC_RES_CAP 16 +#define PCI_VC_RES_CTRL 20 +#define PCI_VC_RES_STATUS 26 + +/* Power Budgeting */ +#define PCI_PWR_DSR 4 /* Data Select Register */ +#define PCI_PWR_DATA 8 /* Data Register */ +#define PCI_PWR_DATA_BASE(x) ((x) & 0xff) /* Base Power */ +#define PCI_PWR_DATA_SCALE(x) (((x) >> 8) & 3) /* Data Scale */ +#define PCI_PWR_DATA_PM_SUB(x) (((x) >> 10) & 7) /* PM Sub State */ +#define PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3) /* PM State */ +#define PCI_PWR_DATA_TYPE(x) (((x) >> 15) & 7) /* Type */ +#define PCI_PWR_DATA_RAIL(x) (((x) >> 18) & 7) /* Power Rail */ +#define PCI_PWR_CAP 12 /* Capability */ +#define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */ + +/* + * Hypertransport sub capability types + * + * Unfortunately there are both 3 bit and 5 bit capability types defined + * in the HT spec, catering for that is a little messy. You probably don't + * want to use these directly, just use pci_find_ht_capability() and it + * will do the right thing for you. + */ +#define HT_3BIT_CAP_MASK 0xE0 +#define HT_CAPTYPE_SLAVE 0x00 /* Slave/Primary link configuration */ +#define HT_CAPTYPE_HOST 0x20 /* Host/Secondary link configuration */ + +#define HT_5BIT_CAP_MASK 0xF8 +#define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */ +#define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address remapping */ +#define HT_CAPTYPE_REMAPPING_64 0xA2 /* 64 bit address remapping */ +#define HT_CAPTYPE_UNITID_CLUMP 0x90 /* Unit ID clumping */ +#define HT_CAPTYPE_EXTCONF 0x98 /* Extended Configuration Space Access */ +#define HT_CAPTYPE_MSI_MAPPING 0xA8 /* MSI Mapping Capability */ +#define HT_MSI_FLAGS 0x02 /* Offset to flags */ +#define HT_MSI_FLAGS_ENABLE 0x1 /* Mapping enable */ +#define HT_MSI_FLAGS_FIXED 0x2 /* Fixed mapping only */ +#define HT_MSI_FIXED_ADDR 0x00000000FEE00000ULL /* Fixed addr */ +#define HT_MSI_ADDR_LO 0x04 /* Offset to low addr bits */ +#define HT_MSI_ADDR_LO_MASK 0xFFF00000 /* Low address bit mask */ +#define HT_MSI_ADDR_HI 0x08 /* Offset to high addr bits */ +#define HT_CAPTYPE_DIRECT_ROUTE 0xB0 /* Direct routing configuration */ +#define HT_CAPTYPE_VCSET 0xB8 /* Virtual Channel configuration */ +#define HT_CAPTYPE_ERROR_RETRY 0xC0 /* Retry on error configuration */ +#define HT_CAPTYPE_GEN3 0xD0 /* Generation 3 hypertransport configuration */ +#define HT_CAPTYPE_PM 0xE0 /* Hypertransport powermanagement configuration */ + +/* Alternative Routing-ID Interpretation */ +#define PCI_ARI_CAP 0x04 /* ARI Capability Register */ +#define PCI_ARI_CAP_MFVC 0x0001 /* MFVC Function Groups Capability */ +#define PCI_ARI_CAP_ACS 0x0002 /* ACS Function Groups Capability */ +#define PCI_ARI_CAP_NFN(x) (((x) >> 8) & 0xff) /* Next Function Number */ +#define PCI_ARI_CTRL 0x06 /* ARI Control Register */ +#define PCI_ARI_CTRL_MFVC 0x0001 /* MFVC Function Groups Enable */ +#define PCI_ARI_CTRL_ACS 0x0002 /* ACS Function Groups Enable */ +#define PCI_ARI_CTRL_FG(x) (((x) >> 4) & 7) /* Function Group */ + +#endif /* LINUX_PCI_REGS_H */ diff --git a/bios/seabios/src/pcibios.c b/bios/seabios/src/pcibios.c new file mode 100644 index 0000000..8b792fb --- /dev/null +++ b/bios/seabios/src/pcibios.c @@ -0,0 +1,237 @@ +// PCI BIOS (int 1a/b1) calls +// +// Copyright (C) 2008 Kevin O'Connor +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "types.h" // u32 +#include "util.h" // handle_1ab1 +#include "pci.h" // pci_config_readl +#include "bregs.h" // struct bregs +#include "biosvar.h" // GET_EBDA +#include "pci_regs.h" // PCI_VENDOR_ID + +// romlayout.S +extern void entry_bios32(void); +extern void entry_pcibios32(void); + +#define RET_FUNC_NOT_SUPPORTED 0x81 +#define RET_BAD_VENDOR_ID 0x83 +#define RET_DEVICE_NOT_FOUND 0x86 +#define RET_BUFFER_TOO_SMALL 0x89 + +// installation check +static void +handle_1ab101(struct bregs *regs) +{ + regs->al = 0x01; // Flags - "Config Mechanism #1" supported. + regs->bx = 0x0210; // PCI version 2.10 + regs->cl = GET_GLOBAL(MaxPCIBus); + regs->edx = 0x20494350; // "PCI " + regs->edi = (u32)entry_pcibios32 + BUILD_BIOS_ADDR; + set_code_success(regs); +} + +// find pci device +static void +handle_1ab102(struct bregs *regs) +{ + u32 id = (regs->cx << 16) | regs->dx; + int count = regs->si; + int bus = -1; + while (bus < GET_GLOBAL(MaxPCIBus)) { + bus++; + int bdf; + foreachbdf(bdf, bus) { + u32 v = pci_config_readl(bdf, PCI_VENDOR_ID); + if (v != id) + continue; + if (count--) + continue; + regs->bx = bdf; + set_code_success(regs); + return; + } + } + set_code_invalid(regs, RET_DEVICE_NOT_FOUND); +} + +// find class code +static void +handle_1ab103(struct bregs *regs) +{ + int count = regs->si; + u32 classprog = regs->ecx; + int bus = -1; + while (bus < GET_GLOBAL(MaxPCIBus)) { + bus++; + int bdf; + foreachbdf(bdf, bus) { + u32 v = pci_config_readl(bdf, PCI_CLASS_REVISION); + if ((v>>8) != classprog) + continue; + if (count--) + continue; + regs->bx = bdf; + set_code_success(regs); + return; + } + } + set_code_invalid(regs, RET_DEVICE_NOT_FOUND); +} + +// read configuration byte +static void +handle_1ab108(struct bregs *regs) +{ + regs->cl = pci_config_readb(regs->bx, regs->di); + set_code_success(regs); +} + +// read configuration word +static void +handle_1ab109(struct bregs *regs) +{ + regs->cx = pci_config_readw(regs->bx, regs->di); + set_code_success(regs); +} + +// read configuration dword +static void +handle_1ab10a(struct bregs *regs) +{ + regs->ecx = pci_config_readl(regs->bx, regs->di); + set_code_success(regs); +} + +// write configuration byte +static void +handle_1ab10b(struct bregs *regs) +{ + pci_config_writeb(regs->bx, regs->di, regs->cl); + set_code_success(regs); +} + +// write configuration word +static void +handle_1ab10c(struct bregs *regs) +{ + pci_config_writew(regs->bx, regs->di, regs->cx); + set_code_success(regs); +} + +// write configuration dword +static void +handle_1ab10d(struct bregs *regs) +{ + pci_config_writel(regs->bx, regs->di, regs->ecx); + set_code_success(regs); +} + +// get irq routing options +static void +handle_1ab10e(struct bregs *regs) +{ + struct pir_header *pirtable_g = (void*)(GET_GLOBAL(PirOffset) + 0); + if (! pirtable_g) { + set_code_invalid(regs, RET_FUNC_NOT_SUPPORTED); + return; + } + + struct param_s { + u16 size; + u16 buf_off; + u16 buf_seg; + } *param_far = (void*)(regs->di+0); + + // Validate and update size. + u16 bufsize = GET_FARVAR(regs->es, param_far->size); + u16 pirsize = GET_GLOBAL(pirtable_g->size) - sizeof(struct pir_header); + SET_FARVAR(regs->es, param_far->size, pirsize); + if (bufsize < pirsize) { + set_code_invalid(regs, RET_BUFFER_TOO_SMALL); + return; + } + + // Get dest buffer. + void *buf_far = (void*)(GET_FARVAR(regs->es, param_far->buf_off)+0); + u16 buf_seg = GET_FARVAR(regs->es, param_far->buf_seg); + + // Memcpy pir table slots to dest buffer. + memcpy_far(buf_seg, buf_far + , get_global_seg() + , (void*)(pirtable_g->slots) + get_global_offset() + , pirsize); + + // XXX - bochs bios sets bx to (1 << 9) | (1 << 11) + regs->bx = GET_GLOBAL(pirtable_g->exclusive_irqs); + set_code_success(regs); +} + +static void +handle_1ab1XX(struct bregs *regs) +{ + set_code_unimplemented(regs, RET_FUNC_NOT_SUPPORTED); +} + +void +handle_1ab1(struct bregs *regs) +{ + //debug_stub(regs); + + if (! CONFIG_PCIBIOS) { + set_invalid(regs); + return; + } + + switch (regs->al) { + case 0x01: handle_1ab101(regs); break; + case 0x02: handle_1ab102(regs); break; + case 0x03: handle_1ab103(regs); break; + case 0x08: handle_1ab108(regs); break; + case 0x09: handle_1ab109(regs); break; + case 0x0a: handle_1ab10a(regs); break; + case 0x0b: handle_1ab10b(regs); break; + case 0x0c: handle_1ab10c(regs); break; + case 0x0d: handle_1ab10d(regs); break; + case 0x0e: handle_1ab10e(regs); break; + default: handle_1ab1XX(regs); break; + } +} + + +/**************************************************************** + * 32bit interface + ****************************************************************/ + +// Entry point for 32bit pci bios functions. +void VISIBLE32SEG +handle_pcibios32(struct bregs *regs) +{ + debug_enter(regs, DEBUG_HDL_pcibios32); + handle_1ab1(regs); +} + +struct bios32_s { + u32 signature; + u32 entry; + u8 version; + u8 length; + u8 checksum; + u8 reserved[5]; +} PACKED; + +struct bios32_s BIOS32HEADER __aligned(16) VAR16EXPORT = { + .signature = 0x5f32335f, // _32_ + .length = sizeof(BIOS32HEADER) / 16, +}; + +void +bios32_setup(void) +{ + dprintf(3, "init bios32\n"); + + BIOS32HEADER.entry = (u32)entry_bios32; + BIOS32HEADER.checksum -= checksum(&BIOS32HEADER, sizeof(BIOS32HEADER)); +} diff --git a/bios/seabios/src/pciinit.c b/bios/seabios/src/pciinit.c new file mode 100644 index 0000000..0d8758e --- /dev/null +++ b/bios/seabios/src/pciinit.c @@ -0,0 +1,620 @@ +// Initialize PCI devices (on emulators) +// +// Copyright (C) 2008 Kevin O'Connor +// Copyright (C) 2006 Fabrice Bellard +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // dprintf +#include "pci.h" // pci_config_readl +#include "biosvar.h" // GET_EBDA +#include "pci_ids.h" // PCI_VENDOR_ID_INTEL +#include "pci_regs.h" // PCI_COMMAND +#include "xen.h" // usingXen + +#define PCI_IO_INDEX_SHIFT 2 +#define PCI_MEM_INDEX_SHIFT 12 + +#define PCI_BRIDGE_IO_MIN 0x1000 +#define PCI_BRIDGE_MEM_MIN 0x100000 + +enum pci_region_type { + PCI_REGION_TYPE_IO, + PCI_REGION_TYPE_MEM, + PCI_REGION_TYPE_PREFMEM, + PCI_REGION_TYPE_COUNT, +}; + +static const char *region_type_name[] = { + [ PCI_REGION_TYPE_IO ] = "io", + [ PCI_REGION_TYPE_MEM ] = "mem", + [ PCI_REGION_TYPE_PREFMEM ] = "prefmem", +}; + +static struct pci_bus { + struct { + /* pci region stats */ + u32 count[32 - PCI_MEM_INDEX_SHIFT]; + u32 sum, max; + /* seconday bus region sizes */ + u32 size; + /* pci region assignments */ + u32 bases[32 - PCI_MEM_INDEX_SHIFT]; + u32 base; + } r[PCI_REGION_TYPE_COUNT]; +} *busses; +static int busses_count; + +static void pci_bios_init_device_in_bus(int bus); +static void pci_bios_check_device_in_bus(int bus); +static void pci_bios_init_bus_bases(struct pci_bus *bus); +static void pci_bios_map_device_in_bus(int bus); + +static int pci_size_to_index(u32 size, enum pci_region_type type) +{ + int index = __fls(size); + int shift = (type == PCI_REGION_TYPE_IO) ? + PCI_IO_INDEX_SHIFT : PCI_MEM_INDEX_SHIFT; + + if (index < shift) + index = shift; + index -= shift; + return index; +} + +static u32 pci_index_to_size(int index, enum pci_region_type type) +{ + int shift = (type == PCI_REGION_TYPE_IO) ? + PCI_IO_INDEX_SHIFT : PCI_MEM_INDEX_SHIFT; + + return 0x1 << (index + shift); +} + +static enum pci_region_type pci_addr_to_type(u32 addr) +{ + if (addr & PCI_BASE_ADDRESS_SPACE_IO) + return PCI_REGION_TYPE_IO; + if (addr & PCI_BASE_ADDRESS_MEM_PREFETCH) + return PCI_REGION_TYPE_PREFMEM; + return PCI_REGION_TYPE_MEM; +} + +static u32 pci_size_roundup(u32 size) +{ + int index = __fls(size-1)+1; + return 0x1 << index; +} + +/* host irqs corresponding to PCI irqs A-D */ +const u8 pci_irqs[4] = { + 10, 10, 11, 11 +}; + +static u32 pci_bar(u16 bdf, int region_num) +{ + if (region_num != PCI_ROM_SLOT) { + return PCI_BASE_ADDRESS_0 + region_num * 4; + } + +#define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80 + u8 type = pci_config_readb(bdf, PCI_HEADER_TYPE); + type &= ~PCI_HEADER_TYPE_MULTI_FUNCTION; + return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS; +} + +static void pci_set_io_region_addr(u16 bdf, int region_num, u32 addr) +{ + u32 ofs; + + ofs = pci_bar(bdf, region_num); + + pci_config_writel(bdf, ofs, addr); +} + +/* return the global irq number corresponding to a given device irq + pin. We could also use the bus number to have a more precise + mapping. */ +static int pci_slot_get_pirq(u16 bdf, int irq_num) +{ + int slot_addend = pci_bdf_to_dev(bdf) - 1; + return (irq_num + slot_addend) & 3; +} + +/* PIIX3/PIIX4 PCI to ISA bridge */ +static void piix_isa_bridge_init(struct pci_device *pci, void *arg) +{ + int i, irq; + u8 elcr[2]; + + elcr[0] = 0x00; + elcr[1] = 0x00; + for (i = 0; i < 4; i++) { + irq = pci_irqs[i]; + /* set to trigger level */ + elcr[irq >> 3] |= (1 << (irq & 7)); + /* activate irq remapping in PIIX */ + pci_config_writeb(pci->bdf, 0x60 + i, irq); + } + outb(elcr[0], 0x4d0); + outb(elcr[1], 0x4d1); + dprintf(1, "PIIX3/PIIX4 init: elcr=%02x %02x\n", elcr[0], elcr[1]); +} + +static const struct pci_device_id pci_isa_bridge_tbl[] = { + /* PIIX3/PIIX4 PCI to ISA bridge */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, + piix_isa_bridge_init), + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, + piix_isa_bridge_init), + + PCI_DEVICE_END +}; + +#define PCI_IO_ALIGN 4096 +#define PCI_IO_SHIFT 8 +#define PCI_MEMORY_ALIGN (1UL << 20) +#define PCI_MEMORY_SHIFT 16 +#define PCI_PREF_MEMORY_ALIGN (1UL << 20) +#define PCI_PREF_MEMORY_SHIFT 16 + +static void storage_ide_init(struct pci_device *pci, void *arg) +{ + u16 bdf = pci->bdf; + /* IDE: we map it as in ISA mode */ + pci_set_io_region_addr(bdf, 0, PORT_ATA1_CMD_BASE); + pci_set_io_region_addr(bdf, 1, PORT_ATA1_CTRL_BASE); + pci_set_io_region_addr(bdf, 2, PORT_ATA2_CMD_BASE); + pci_set_io_region_addr(bdf, 3, PORT_ATA2_CTRL_BASE); +} + +/* PIIX3/PIIX4 IDE */ +static void piix_ide_init(struct pci_device *pci, void *arg) +{ + u16 bdf = pci->bdf; + pci_config_writew(bdf, 0x40, 0x8000); // enable IDE0 + pci_config_writew(bdf, 0x42, 0x8000); // enable IDE1 +} + +static void pic_ibm_init(struct pci_device *pci, void *arg) +{ + /* PIC, IBM, MPIC & MPIC2 */ + pci_set_io_region_addr(pci->bdf, 0, 0x80800000 + 0x00040000); +} + +static void apple_macio_init(struct pci_device *pci, void *arg) +{ + /* macio bridge */ + pci_set_io_region_addr(pci->bdf, 0, 0x80800000); +} + +static const struct pci_device_id pci_class_tbl[] = { + /* STORAGE IDE */ + PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, + PCI_CLASS_STORAGE_IDE, piix_ide_init), + PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB, + PCI_CLASS_STORAGE_IDE, piix_ide_init), + PCI_DEVICE_CLASS(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE, + storage_ide_init), + + /* PIC, IBM, MIPC & MPIC2 */ + PCI_DEVICE_CLASS(PCI_VENDOR_ID_IBM, 0x0046, PCI_CLASS_SYSTEM_PIC, + pic_ibm_init), + PCI_DEVICE_CLASS(PCI_VENDOR_ID_IBM, 0xFFFF, PCI_CLASS_SYSTEM_PIC, + pic_ibm_init), + + /* 0xff00 */ + PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0017, 0xff00, apple_macio_init), + PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0022, 0xff00, apple_macio_init), + + PCI_DEVICE_END, +}; + +/* PIIX4 Power Management device (for ACPI) */ +static void piix4_pm_init(struct pci_device *pci, void *arg) +{ + u16 bdf = pci->bdf; + // acpi sci is hardwired to 9 + pci_config_writeb(bdf, PCI_INTERRUPT_LINE, 9); + + pci_config_writel(bdf, 0x40, PORT_ACPI_PM_BASE | 1); + pci_config_writeb(bdf, 0x80, 0x01); /* enable PM io space */ + pci_config_writel(bdf, 0x90, PORT_SMB_BASE | 1); + pci_config_writeb(bdf, 0xd2, 0x09); /* enable SMBus io space */ +} + +static const struct pci_device_id pci_device_tbl[] = { + /* PIIX4 Power Management device (for ACPI) */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, + piix4_pm_init), + + PCI_DEVICE_END, +}; + +static void pci_bios_init_device(struct pci_device *pci) +{ + u16 bdf = pci->bdf; + int pin, pic_irq; + + dprintf(1, "PCI: bus=%d devfn=0x%02x: vendor_id=0x%04x device_id=0x%04x\n" + , pci_bdf_to_bus(bdf), pci_bdf_to_devfn(bdf) + , pci->vendor, pci->device); + pci_init_device(pci_class_tbl, pci, NULL); + + /* enable memory mappings */ + pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + + /* map the interrupt */ + pin = pci_config_readb(bdf, PCI_INTERRUPT_PIN); + if (pin != 0) { + pin = pci_slot_get_pirq(bdf, pin - 1); + pic_irq = pci_irqs[pin]; + pci_config_writeb(bdf, PCI_INTERRUPT_LINE, pic_irq); + } + + pci_init_device(pci_device_tbl, pci, NULL); +} + +static void pci_bios_init_device_in_bus(int bus) +{ + struct pci_device *pci; + foreachpci(pci) { + u8 pci_bus = pci_bdf_to_bus(pci->bdf); + if (pci_bus < bus) + continue; + if (pci_bus > bus) + break; + pci_bios_init_device(pci); + } +} + +static void +pci_bios_init_bus_rec(int bus, u8 *pci_bus) +{ + int bdf; + u16 class; + + dprintf(1, "PCI: %s bus = 0x%x\n", __func__, bus); + + /* prevent accidental access to unintended devices */ + foreachbdf(bdf, bus) { + class = pci_config_readw(bdf, PCI_CLASS_DEVICE); + if (class == PCI_CLASS_BRIDGE_PCI) { + pci_config_writeb(bdf, PCI_SECONDARY_BUS, 255); + pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, 0); + } + } + + foreachbdf(bdf, bus) { + class = pci_config_readw(bdf, PCI_CLASS_DEVICE); + if (class != PCI_CLASS_BRIDGE_PCI) { + continue; + } + dprintf(1, "PCI: %s bdf = 0x%x\n", __func__, bdf); + + u8 pribus = pci_config_readb(bdf, PCI_PRIMARY_BUS); + if (pribus != bus) { + dprintf(1, "PCI: primary bus = 0x%x -> 0x%x\n", pribus, bus); + pci_config_writeb(bdf, PCI_PRIMARY_BUS, bus); + } else { + dprintf(1, "PCI: primary bus = 0x%x\n", pribus); + } + + u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS); + (*pci_bus)++; + if (*pci_bus != secbus) { + dprintf(1, "PCI: secondary bus = 0x%x -> 0x%x\n", + secbus, *pci_bus); + secbus = *pci_bus; + pci_config_writeb(bdf, PCI_SECONDARY_BUS, secbus); + } else { + dprintf(1, "PCI: secondary bus = 0x%x\n", secbus); + } + + /* set to max for access to all subordinate buses. + later set it to accurate value */ + u8 subbus = pci_config_readb(bdf, PCI_SUBORDINATE_BUS); + pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, 255); + + pci_bios_init_bus_rec(secbus, pci_bus); + + if (subbus != *pci_bus) { + dprintf(1, "PCI: subordinate bus = 0x%x -> 0x%x\n", + subbus, *pci_bus); + subbus = *pci_bus; + } else { + dprintf(1, "PCI: subordinate bus = 0x%x\n", subbus); + } + pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, subbus); + } +} + +static void +pci_bios_init_bus(void) +{ + u8 pci_bus = 0; + pci_bios_init_bus_rec(0 /* host bus */, &pci_bus); + busses_count = pci_bus + 1; +} + +static void pci_bios_bus_get_bar(struct pci_bus *bus, int bdf, int bar, + u32 *val, u32 *size) +{ + u32 ofs = pci_bar(bdf, bar); + u32 old = pci_config_readl(bdf, ofs); + u32 mask; + + if (bar == PCI_ROM_SLOT) { + mask = PCI_ROM_ADDRESS_MASK; + pci_config_writel(bdf, ofs, mask); + } else { + if (old & PCI_BASE_ADDRESS_SPACE_IO) + mask = PCI_BASE_ADDRESS_IO_MASK; + else + mask = PCI_BASE_ADDRESS_MEM_MASK; + pci_config_writel(bdf, ofs, ~0); + } + *val = pci_config_readl(bdf, ofs); + pci_config_writel(bdf, ofs, old); + *size = (~(*val & mask)) + 1; +} + +static void pci_bios_bus_reserve(struct pci_bus *bus, int type, u32 size) +{ + u32 index; + + index = pci_size_to_index(size, type); + size = pci_index_to_size(index, type); + bus->r[type].count[index]++; + bus->r[type].sum += size; + if (bus->r[type].max < size) + bus->r[type].max = size; +} + +static u32 pci_bios_bus_get_addr(struct pci_bus *bus, int type, u32 size) +{ + u32 index, addr; + + index = pci_size_to_index(size, type); + addr = bus->r[type].bases[index]; + bus->r[type].bases[index] += pci_index_to_size(index, type); + return addr; +} + +static void pci_bios_check_device(struct pci_bus *bus, struct pci_device *dev) +{ + u16 bdf = dev->bdf; + u32 limit; + int i,type; + + if (dev->class == PCI_CLASS_BRIDGE_PCI) { + if (dev->secondary_bus >= busses_count) { + /* should never trigger */ + dprintf(1, "PCI: bus count too small (%d), skipping bus #%d\n", + busses_count, dev->secondary_bus); + return; + } + struct pci_bus *s = busses + dev->secondary_bus; + pci_bios_check_device_in_bus(dev->secondary_bus); + for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) { + limit = (type == PCI_REGION_TYPE_IO) ? + PCI_BRIDGE_IO_MIN : PCI_BRIDGE_MEM_MIN; + s->r[type].size = s->r[type].sum; + if (s->r[type].size < limit) + s->r[type].size = limit; + s->r[type].size = pci_size_roundup(s->r[type].size); + pci_bios_bus_reserve(bus, type, s->r[type].size); + } + dprintf(1, "PCI: secondary bus %d sizes: io %x, mem %x, prefmem %x\n", + dev->secondary_bus, + s->r[PCI_REGION_TYPE_IO].size, + s->r[PCI_REGION_TYPE_MEM].size, + s->r[PCI_REGION_TYPE_PREFMEM].size); + return; + } + + for (i = 0; i < PCI_NUM_REGIONS; i++) { + u32 val, size; + pci_bios_bus_get_bar(bus, bdf, i, &val, &size); + if (val == 0) { + continue; + } + pci_bios_bus_reserve(bus, pci_addr_to_type(val), size); + dev->bars[i].addr = val; + dev->bars[i].size = size; + dev->bars[i].is64 = (!(val & PCI_BASE_ADDRESS_SPACE_IO) && + (val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64); + + if (dev->bars[i].is64) { + i++; + } + } +} + +static void pci_bios_map_device(struct pci_bus *bus, struct pci_device *dev) +{ + u16 bdf = dev->bdf; + int type, i; + + if (dev->class == PCI_CLASS_BRIDGE_PCI) { + if (dev->secondary_bus >= busses_count) { + return; + } + struct pci_bus *s = busses + dev->secondary_bus; + u32 base, limit; + + for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) { + s->r[type].base = pci_bios_bus_get_addr(bus, type, s->r[type].size); + } + dprintf(1, "PCI: init bases bus %d (secondary)\n", dev->secondary_bus); + pci_bios_init_bus_bases(s); + + base = s->r[PCI_REGION_TYPE_IO].base; + limit = base + s->r[PCI_REGION_TYPE_IO].size - 1; + pci_config_writeb(bdf, PCI_IO_BASE, base >> PCI_IO_SHIFT); + pci_config_writew(bdf, PCI_IO_BASE_UPPER16, 0); + pci_config_writeb(bdf, PCI_IO_LIMIT, limit >> PCI_IO_SHIFT); + pci_config_writew(bdf, PCI_IO_LIMIT_UPPER16, 0); + + base = s->r[PCI_REGION_TYPE_MEM].base; + limit = base + s->r[PCI_REGION_TYPE_MEM].size - 1; + pci_config_writew(bdf, PCI_MEMORY_BASE, base >> PCI_MEMORY_SHIFT); + pci_config_writew(bdf, PCI_MEMORY_LIMIT, limit >> PCI_MEMORY_SHIFT); + + base = s->r[PCI_REGION_TYPE_PREFMEM].base; + limit = base + s->r[PCI_REGION_TYPE_PREFMEM].size - 1; + pci_config_writew(bdf, PCI_PREF_MEMORY_BASE, base >> PCI_PREF_MEMORY_SHIFT); + pci_config_writew(bdf, PCI_PREF_MEMORY_LIMIT, limit >> PCI_PREF_MEMORY_SHIFT); + pci_config_writel(bdf, PCI_PREF_BASE_UPPER32, 0); + pci_config_writel(bdf, PCI_PREF_LIMIT_UPPER32, 0); + + pci_bios_map_device_in_bus(dev->secondary_bus); + return; + } + + for (i = 0; i < PCI_NUM_REGIONS; i++) { + u32 addr; + if (dev->bars[i].addr == 0) { + continue; + } + + addr = pci_bios_bus_get_addr(bus, pci_addr_to_type(dev->bars[i].addr), + dev->bars[i].size); + dprintf(1, " bar %d, addr %x, size %x [%s]\n", + i, addr, dev->bars[i].size, + dev->bars[i].addr & PCI_BASE_ADDRESS_SPACE_IO ? "io" : "mem"); + pci_set_io_region_addr(bdf, i, addr); + + if (dev->bars[i].is64) { + i++; + } + } +} + +static void pci_bios_check_device_in_bus(int bus) +{ + struct pci_device *pci; + + dprintf(1, "PCI: check devices bus %d\n", bus); + foreachpci(pci) { + if (pci_bdf_to_bus(pci->bdf) != bus) + continue; + pci_bios_check_device(&busses[bus], pci); + } +} + +static void pci_bios_map_device_in_bus(int bus) +{ + struct pci_device *pci; + + foreachpci(pci) { + if (pci_bdf_to_bus(pci->bdf) != bus) + continue; + dprintf(1, "PCI: map device bus %d, bfd 0x%x\n", bus, pci->bdf); + pci_bios_map_device(&busses[bus], pci); + } +} + +static void pci_bios_init_bus_bases(struct pci_bus *bus) +{ + u32 base, newbase, size; + int type, i; + + for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) { + dprintf(1, " type %s max %x sum %x base %x\n", region_type_name[type], + bus->r[type].max, bus->r[type].sum, bus->r[type].base); + base = bus->r[type].base; + for (i = ARRAY_SIZE(bus->r[type].count)-1; i >= 0; i--) { + size = pci_index_to_size(i, type); + if (!bus->r[type].count[i]) + continue; + newbase = base + size * bus->r[type].count[i]; + dprintf(1, " size %8x: %d bar(s), %8x -> %8x\n", + size, bus->r[type].count[i], base, newbase - 1); + bus->r[type].bases[i] = base; + base = newbase; + } + } +} + +#define ROOT_BASE(top, sum, max) ALIGN_DOWN((top)-(sum),(max) ?: 1) + +static int pci_bios_init_root_regions(u32 start, u32 end) +{ + struct pci_bus *bus = &busses[0]; + + bus->r[PCI_REGION_TYPE_IO].base = 0xc000; + + if (bus->r[PCI_REGION_TYPE_MEM].sum < bus->r[PCI_REGION_TYPE_PREFMEM].sum) { + bus->r[PCI_REGION_TYPE_MEM].base = + ROOT_BASE(end, + bus->r[PCI_REGION_TYPE_MEM].sum, + bus->r[PCI_REGION_TYPE_MEM].max); + bus->r[PCI_REGION_TYPE_PREFMEM].base = + ROOT_BASE(bus->r[PCI_REGION_TYPE_MEM].base, + bus->r[PCI_REGION_TYPE_PREFMEM].sum, + bus->r[PCI_REGION_TYPE_PREFMEM].max); + if (bus->r[PCI_REGION_TYPE_PREFMEM].base >= start) { + return 0; + } + } else { + bus->r[PCI_REGION_TYPE_PREFMEM].base = + ROOT_BASE(end, + bus->r[PCI_REGION_TYPE_PREFMEM].sum, + bus->r[PCI_REGION_TYPE_PREFMEM].max); + bus->r[PCI_REGION_TYPE_MEM].base = + ROOT_BASE(bus->r[PCI_REGION_TYPE_PREFMEM].base, + bus->r[PCI_REGION_TYPE_MEM].sum, + bus->r[PCI_REGION_TYPE_MEM].max); + if (bus->r[PCI_REGION_TYPE_MEM].base >= start) { + return 0; + } + } + return -1; +} + +void +pci_setup(void) +{ + if (CONFIG_COREBOOT || usingXen()) { + // PCI setup already done by coreboot or Xen - just do probe. + pci_probe_devices(); + return; + } + + dprintf(3, "pci setup\n"); + + u32 start = BUILD_PCIMEM_START; + u32 end = BUILD_PCIMEM_END; + + dprintf(1, "=== PCI bus & bridge init ===\n"); + if (pci_probe_host() != 0) { + return; + } + pci_bios_init_bus(); + + dprintf(1, "=== PCI device probing ===\n"); + pci_probe_devices(); + + dprintf(1, "=== PCI new allocation pass #1 ===\n"); + busses = malloc_tmp(sizeof(*busses) * busses_count); + memset(busses, 0, sizeof(*busses) * busses_count); + pci_bios_check_device_in_bus(0 /* host bus */); + if (pci_bios_init_root_regions(start, end) != 0) { + panic("PCI: out of address space\n"); + } + + dprintf(1, "=== PCI new allocation pass #2 ===\n"); + dprintf(1, "PCI: init bases bus 0 (primary)\n"); + pci_bios_init_bus_bases(&busses[0]); + pci_bios_map_device_in_bus(0 /* host bus */); + + pci_bios_init_device_in_bus(0 /* host bus */); + + struct pci_device *pci; + foreachpci(pci) { + pci_init_device(pci_isa_bridge_tbl, pci, NULL); + } + + free(busses); + busses_count = 0; +} diff --git a/bios/seabios/src/pic.c b/bios/seabios/src/pic.c new file mode 100644 index 0000000..8992a8b --- /dev/null +++ b/bios/seabios/src/pic.c @@ -0,0 +1,52 @@ +// Helpers for working with i8259 interrupt controller. +// +// Copyright (C) 2008 Kevin O'Connor +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "pic.h" // get_pic1_isr +#include "util.h" // dprintf +#include "config.h" // CONFIG_* + +void +set_pics(u8 irq0, u8 irq8) +{ + // Send ICW1 (select OCW1 + will send ICW4) + outb(0x11, PORT_PIC1_CMD); + outb(0x11, PORT_PIC2_CMD); + // Send ICW2 (base irqs: 0x08-0x0f for irq0-7, 0x70-0x77 for irq8-15) + outb(irq0, PORT_PIC1_DATA); + outb(irq8, PORT_PIC2_DATA); + // Send ICW3 (cascaded pic ids) + outb(0x04, PORT_PIC1_DATA); + outb(0x02, PORT_PIC2_DATA); + // Send ICW4 (enable 8086 mode) + outb(0x01, PORT_PIC1_DATA); + outb(0x01, PORT_PIC2_DATA); + // Mask all irqs (except cascaded PIC2 irq) + outb(~PIC1_IRQ2, PORT_PIC1_DATA); + outb(~0, PORT_PIC2_DATA); +} + +void +pic_setup(void) +{ + dprintf(3, "init pic\n"); + set_pics(0x08, 0x70); +} + +// Handler for otherwise unused hardware irqs. +void VISIBLE16 +handle_hwpic1(struct bregs *regs) +{ + dprintf(DEBUG_ISR_hwpic1, "handle_hwpic1 irq=%x\n", get_pic1_isr()); + eoi_pic1(); +} + +void VISIBLE16 +handle_hwpic2(struct bregs *regs) +{ + dprintf(DEBUG_ISR_hwpic2, "handle_hwpic2 irq=%x\n", get_pic2_isr()); + eoi_pic2(); +} diff --git a/bios/seabios/src/pic.h b/bios/seabios/src/pic.h new file mode 100644 index 0000000..c75af3e --- /dev/null +++ b/bios/seabios/src/pic.h @@ -0,0 +1,97 @@ +// Helpers for working with i8259 interrupt controller. +// +// Copyright (C) 2008 Kevin O'Connor +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. +#ifndef __PIC_H +#define __PIC_H + +#include "ioport.h" // PORT_PIC* +#include "biosvar.h" // SET_IVT + +// PORT_PIC1 bitdefs +#define PIC1_IRQ0 (1<<0) +#define PIC1_IRQ1 (1<<1) +#define PIC1_IRQ2 (1<<2) +#define PIC1_IRQ5 (1<<5) +#define PIC1_IRQ6 (1<<6) +// PORT_PIC2 bitdefs +#define PIC2_IRQ8 (1<<0) +#define PIC2_IRQ12 (1<<4) +#define PIC2_IRQ13 (1<<5) +#define PIC2_IRQ14 (1<<6) + +static inline void +eoi_pic1(void) +{ + // Send eoi (select OCW2 + eoi) + outb(0x20, PORT_PIC1_CMD); +} + +static inline void +eoi_pic2(void) +{ + // Send eoi (select OCW2 + eoi) + outb(0x20, PORT_PIC2_CMD); + eoi_pic1(); +} + +static inline void +unmask_pic1(u8 irq) +{ + outb(inb(PORT_PIC1_DATA) & ~irq, PORT_PIC1_DATA); +} + +static inline void +unmask_pic2(u8 irq) +{ + outb(inb(PORT_PIC2_DATA) & ~irq, PORT_PIC2_DATA); +} + +static inline void +mask_pic1(u8 irq) +{ + outb(inb(PORT_PIC1_DATA) | irq, PORT_PIC1_DATA); +} + +static inline void +mask_pic2(u8 irq) +{ + outb(inb(PORT_PIC2_DATA) | irq, PORT_PIC2_DATA); +} + +static inline u8 +get_pic1_isr(void) +{ + // 0x0b == select OCW1 + read ISR + outb(0x0b, PORT_PIC1_CMD); + return inb(PORT_PIC1_CMD); +} + +static inline u8 +get_pic2_isr(void) +{ + // 0x0b == select OCW1 + read ISR + outb(0x0b, PORT_PIC2_CMD); + return inb(PORT_PIC2_CMD); +} + +static inline void +enable_hwirq(int hwirq, struct segoff_s func) +{ + int vector; + if (hwirq < 8) { + unmask_pic1(1 << hwirq); + vector = 0x08 + hwirq; + } else { + unmask_pic2(1 << (hwirq - 8)); + vector = 0x70 + hwirq - 8; + } + SET_IVT(vector, func); +} + +void set_pics(u8 irq0, u8 irq8); +void pic_setup(void); + +#endif // pic.h diff --git a/bios/seabios/src/pirtable.c b/bios/seabios/src/pirtable.c new file mode 100644 index 0000000..4c3f1ff --- /dev/null +++ b/bios/seabios/src/pirtable.c @@ -0,0 +1,105 @@ +// PIR table generation (for emulators) +// +// Copyright (C) 2008 Kevin O'Connor +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "pci.h" // struct pir_header +#include "util.h" // checksum +#include "biosvar.h" // SET_EBDA + +u16 PirOffset VAR16VISIBLE; + +struct pir_table { + struct pir_header pir; + struct pir_slot slots[6]; +} PACKED; + +extern struct pir_table PIR_TABLE; +#if CONFIG_PIRTABLE && !CONFIG_COREBOOT +struct pir_table PIR_TABLE __aligned(16) VAR16EXPORT = { + .pir = { + .version = 0x0100, + .size = sizeof(struct pir_table), + .router_devfunc = 0x08, + .compatible_devid = 0x122e8086, + }, + .slots = { + { + // first slot entry PCI-to-ISA (embedded) + .dev = 1<<3, + .links = { + {.link = 0x60, .bitmap = 0xdef8}, // INTA# + {.link = 0x61, .bitmap = 0xdef8}, // INTB# + {.link = 0x62, .bitmap = 0xdef8}, // INTC# + {.link = 0x63, .bitmap = 0xdef8}, // INTD# + }, + .slot_nr = 0, // embedded + }, { + // second slot entry: 1st PCI slot + .dev = 2<<3, + .links = { + {.link = 0x61, .bitmap = 0xdef8}, // INTA# + {.link = 0x62, .bitmap = 0xdef8}, // INTB# + {.link = 0x63, .bitmap = 0xdef8}, // INTC# + {.link = 0x60, .bitmap = 0xdef8}, // INTD# + }, + .slot_nr = 1, + }, { + // third slot entry: 2nd PCI slot + .dev = 3<<3, + .links = { + {.link = 0x62, .bitmap = 0xdef8}, // INTA# + {.link = 0x63, .bitmap = 0xdef8}, // INTB# + {.link = 0x60, .bitmap = 0xdef8}, // INTC# + {.link = 0x61, .bitmap = 0xdef8}, // INTD# + }, + .slot_nr = 2, + }, { + // 4th slot entry: 3rd PCI slot + .dev = 4<<3, + .links = { + {.link = 0x63, .bitmap = 0xdef8}, // INTA# + {.link = 0x60, .bitmap = 0xdef8}, // INTB# + {.link = 0x61, .bitmap = 0xdef8}, // INTC# + {.link = 0x62, .bitmap = 0xdef8}, // INTD# + }, + .slot_nr = 3, + }, { + // 5th slot entry: 4rd PCI slot + .dev = 5<<3, + .links = { + {.link = 0x60, .bitmap = 0xdef8}, // INTA# + {.link = 0x61, .bitmap = 0xdef8}, // INTB# + {.link = 0x62, .bitmap = 0xdef8}, // INTC# + {.link = 0x63, .bitmap = 0xdef8}, // INTD# + }, + .slot_nr = 4, + }, { + // 6th slot entry: 5rd PCI slot + .dev = 6<<3, + .links = { + {.link = 0x61, .bitmap = 0xdef8}, // INTA# + {.link = 0x62, .bitmap = 0xdef8}, // INTB# + {.link = 0x63, .bitmap = 0xdef8}, // INTC# + {.link = 0x60, .bitmap = 0xdef8}, // INTD# + }, + .slot_nr = 5, + }, + } +}; +#endif // CONFIG_PIRTABLE && !CONFIG_COREBOOT + +void +create_pirtable(void) +{ + if (! CONFIG_PIRTABLE) + return; + + dprintf(3, "init PIR table\n"); + + PIR_TABLE.pir.signature = PIR_SIGNATURE; + PIR_TABLE.pir.checksum -= checksum(&PIR_TABLE, sizeof(PIR_TABLE)); + PirOffset = (u32)&PIR_TABLE.pir - BUILD_BIOS_ADDR; +} diff --git a/bios/seabios/src/pmm.c b/bios/seabios/src/pmm.c new file mode 100644 index 0000000..82a0b1d --- /dev/null +++ b/bios/seabios/src/pmm.c @@ -0,0 +1,603 @@ +// Post memory manager (PMM) calls +// +// Copyright (C) 2009 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // checksum +#include "config.h" // BUILD_BIOS_ADDR +#include "memmap.h" // struct e820entry +#include "farptr.h" // GET_FARVAR +#include "biosvar.h" // GET_BDA + +// Information on a reserved area. +struct allocinfo_s { + struct allocinfo_s *next, **pprev; + void *data, *dataend, *allocend; +}; + +// Information on a tracked memory allocation. +struct allocdetail_s { + struct allocinfo_s detailinfo; + struct allocinfo_s datainfo; + u32 handle; +}; + +// The various memory zones. +struct zone_s { + struct allocinfo_s *info; +}; + +struct zone_s ZoneLow, ZoneHigh, ZoneFSeg, ZoneTmpLow, ZoneTmpHigh; + +static struct zone_s *Zones[] = { + &ZoneTmpLow, &ZoneLow, &ZoneFSeg, &ZoneTmpHigh, &ZoneHigh +}; + + +/**************************************************************** + * low-level memory reservations + ****************************************************************/ + +// Find and reserve space from a given zone +static void * +allocSpace(struct zone_s *zone, u32 size, u32 align, struct allocinfo_s *fill) +{ + struct allocinfo_s *info; + for (info = zone->info; info; info = info->next) { + void *dataend = info->dataend; + void *allocend = info->allocend; + void *newallocend = (void*)ALIGN_DOWN((u32)allocend - size, align); + if (newallocend >= dataend && newallocend <= allocend) { + // Found space - now reserve it. + struct allocinfo_s **pprev = info->pprev; + if (!fill) + fill = newallocend; + fill->next = info; + fill->pprev = pprev; + fill->data = newallocend; + fill->dataend = newallocend + size; + fill->allocend = allocend; + + info->allocend = newallocend; + info->pprev = &fill->next; + *pprev = fill; + return newallocend; + } + } + return NULL; +} + +// Release space allocated with allocSpace() +static void +freeSpace(struct allocinfo_s *info) +{ + struct allocinfo_s *next = info->next; + struct allocinfo_s **pprev = info->pprev; + *pprev = next; + if (next) { + if (next->allocend == info->data) + next->allocend = info->allocend; + next->pprev = pprev; + } +} + +// Add new memory to a zone +static void +addSpace(struct zone_s *zone, void *start, void *end) +{ + // Find position to add space + struct allocinfo_s **pprev = &zone->info, *info; + for (;;) { + info = *pprev; + if (!info || info->data < start) + break; + pprev = &info->next; + } + + // Add space using temporary allocation info. + struct allocdetail_s tempdetail; + tempdetail.datainfo.next = info; + tempdetail.datainfo.pprev = pprev; + tempdetail.datainfo.data = tempdetail.datainfo.dataend = start; + tempdetail.datainfo.allocend = end; + *pprev = &tempdetail.datainfo; + if (info) + info->pprev = &tempdetail.datainfo.next; + + // Allocate final allocation info. + struct allocdetail_s *detail = allocSpace( + &ZoneTmpHigh, sizeof(*detail), MALLOC_MIN_ALIGN, NULL); + if (!detail) { + detail = allocSpace(&ZoneTmpLow, sizeof(*detail) + , MALLOC_MIN_ALIGN, NULL); + if (!detail) { + *tempdetail.datainfo.pprev = tempdetail.datainfo.next; + if (tempdetail.datainfo.next) + tempdetail.datainfo.next->pprev = tempdetail.datainfo.pprev; + warn_noalloc(); + return; + } + } + + // Replace temp alloc space with final alloc space + memcpy(&detail->datainfo, &tempdetail.datainfo, sizeof(detail->datainfo)); + detail->handle = PMM_DEFAULT_HANDLE; + + *tempdetail.datainfo.pprev = &detail->datainfo; + if (tempdetail.datainfo.next) + tempdetail.datainfo.next->pprev = &detail->datainfo.next; +} + +// Search all zones for an allocation obtained from allocSpace() +static struct allocinfo_s * +findAlloc(void *data) +{ + int i; + for (i=0; iinfo; info; info = info->next) + if (info->data == data) + return info; + } + return NULL; +} + +// Return the last sentinal node of a zone +static struct allocinfo_s * +findLast(struct zone_s *zone) +{ + struct allocinfo_s *info = zone->info; + if (!info) + return NULL; + for (;;) { + struct allocinfo_s *next = info->next; + if (!next) + return info; + info = next; + } +} + + +/**************************************************************** + * Setup + ****************************************************************/ + +void +malloc_setup(void) +{ + ASSERT32FLAT(); + dprintf(3, "malloc setup\n"); + + // Populate temp high ram + u32 highram = 0; + int i; + for (i=e820_count-1; i>=0; i--) { + struct e820entry *en = &e820_list[i]; + u64 end = en->start + en->size; + if (end < 1024*1024) + break; + if (en->type != E820_RAM || end > 0xffffffff) + continue; + u32 s = en->start, e = end; + if (!highram) { + u32 newe = ALIGN_DOWN(e - CONFIG_MAX_HIGHTABLE, MALLOC_MIN_ALIGN); + if (newe <= e && newe >= s) { + highram = newe; + e = newe; + } + } + addSpace(&ZoneTmpHigh, (void*)s, (void*)e); + } + + // Populate other regions + addSpace(&ZoneTmpLow, (void*)BUILD_STACK_ADDR, (void*)BUILD_EBDA_MINIMUM); + addSpace(&ZoneFSeg, BiosTableSpace, &BiosTableSpace[CONFIG_MAX_BIOSTABLE]); + addSpace(&ZoneLow, (void*)BUILD_LOWRAM_END, (void*)BUILD_LOWRAM_END); + if (highram) { + addSpace(&ZoneHigh, (void*)highram + , (void*)highram + CONFIG_MAX_HIGHTABLE); + add_e820(highram, CONFIG_MAX_HIGHTABLE, E820_RESERVED); + } +} + +// Update pointers after code relocation. +void +malloc_fixupreloc(void) +{ + ASSERT32FLAT(); + if (!CONFIG_RELOCATE_INIT) + return; + dprintf(3, "malloc fixup reloc\n"); + + int i; + for (i=0; iinfo->pprev = &zone->info; + } + + // Add space free'd during relocation in f-segment to ZoneFSeg + extern u8 code32init_end[]; + if ((u32)code32init_end > BUILD_BIOS_ADDR) { + memset((void*)BUILD_BIOS_ADDR, 0, (u32)code32init_end - BUILD_BIOS_ADDR); + addSpace(&ZoneFSeg, (void*)BUILD_BIOS_ADDR, code32init_end); + } +} + +void +malloc_finalize(void) +{ + ASSERT32FLAT(); + dprintf(3, "malloc finalize\n"); + + // Reserve more low-mem if needed. + u32 endlow = GET_BDA(mem_size_kb)*1024; + add_e820(endlow, BUILD_LOWRAM_END-endlow, E820_RESERVED); + + // Give back unused high ram. + struct allocinfo_s *info = findLast(&ZoneHigh); + if (info) { + u32 giveback = ALIGN_DOWN(info->allocend - info->dataend, PAGE_SIZE); + add_e820((u32)info->dataend, giveback, E820_RAM); + dprintf(1, "Returned %d bytes of ZoneHigh\n", giveback); + } +} + + +/**************************************************************** + * ebda movement + ****************************************************************/ + +// Move ebda +static int +relocate_ebda(u32 newebda, u32 oldebda, u8 ebda_size) +{ + u32 lowram = GET_BDA(mem_size_kb) * 1024; + if (oldebda != lowram) + // EBDA isn't at end of ram - give up. + return -1; + + // Do copy + memmove((void*)newebda, (void*)oldebda, ebda_size * 1024); + + // Update indexes + dprintf(1, "ebda moved from %x to %x\n", oldebda, newebda); + SET_BDA(mem_size_kb, newebda / 1024); + SET_BDA(ebda_seg, FLATPTR_TO_SEG(newebda)); + return 0; +} + +// Support expanding the ZoneLow dynamically. +static void +zonelow_expand(u32 size, u32 align) +{ + struct allocinfo_s *info = findLast(&ZoneLow); + if (!info) + return; + u32 oldpos = (u32)info->allocend; + u32 newpos = ALIGN_DOWN(oldpos - size, align); + u32 bottom = (u32)info->dataend; + if (newpos >= bottom && newpos <= oldpos) + // Space already present. + return; + u16 ebda_seg = get_ebda_seg(); + u32 ebda_pos = (u32)MAKE_FLATPTR(ebda_seg, 0); + u8 ebda_size = GET_EBDA2(ebda_seg, size); + u32 ebda_end = ebda_pos + ebda_size * 1024; + if (ebda_end != bottom) + // Something else is after ebda - can't use any existing space. + newpos = ALIGN_DOWN(ebda_end - size, align); + u32 newbottom = ALIGN_DOWN(newpos, 1024); + u32 newebda = ALIGN_DOWN(newbottom - ebda_size * 1024, 1024); + if (newebda < BUILD_EBDA_MINIMUM) + // Not enough space. + return; + + // Move ebda + int ret = relocate_ebda(newebda, ebda_pos, ebda_size); + if (ret) + return; + + // Update zone + if (ebda_end == bottom) { + info->data = (void*)newbottom; + info->dataend = (void*)newbottom; + } else + addSpace(&ZoneLow, (void*)newbottom, (void*)ebda_end); +} + +// Check if can expand the given zone to fulfill an allocation +static void * +allocExpandSpace(struct zone_s *zone, u32 size, u32 align + , struct allocinfo_s *fill) +{ + void *data = allocSpace(zone, size, align, fill); + if (data || zone != &ZoneLow) + return data; + + // Make sure to not move ebda while an optionrom is running. + if (unlikely(wait_preempt())) { + data = allocSpace(zone, size, align, fill); + if (data) + return data; + } + + zonelow_expand(size, align); + return allocSpace(zone, size, align, fill); +} + + +/**************************************************************** + * tracked memory allocations + ****************************************************************/ + +// Allocate memory from the given zone and track it as a PMM allocation +void * __malloc +pmm_malloc(struct zone_s *zone, u32 handle, u32 size, u32 align) +{ + ASSERT32FLAT(); + if (!size) + return NULL; + + // Find and reserve space for bookkeeping. + struct allocdetail_s *detail = allocSpace( + &ZoneTmpHigh, sizeof(*detail), MALLOC_MIN_ALIGN, NULL); + if (!detail) { + detail = allocSpace(&ZoneTmpLow, sizeof(*detail) + , MALLOC_MIN_ALIGN, NULL); + if (!detail) + return NULL; + } + + // Find and reserve space for main allocation + void *data = allocExpandSpace(zone, size, align, &detail->datainfo); + if (!data) { + freeSpace(&detail->detailinfo); + return NULL; + } + + dprintf(8, "pmm_malloc zone=%p handle=%x size=%d align=%x" + " ret=%p (detail=%p)\n" + , zone, handle, size, align + , data, detail); + detail->handle = handle; + + return data; +} + +// Free a data block allocated with pmm_malloc +int +pmm_free(void *data) +{ + ASSERT32FLAT(); + struct allocinfo_s *info = findAlloc(data); + if (!info || data == (void*)info || data == info->dataend) + return -1; + struct allocdetail_s *detail = container_of( + info, struct allocdetail_s, datainfo); + dprintf(8, "pmm_free %p (detail=%p)\n", data, detail); + freeSpace(info); + freeSpace(&detail->detailinfo); + return 0; +} + +// Find the amount of free space in a given zone. +static u32 +pmm_getspace(struct zone_s *zone) +{ + // XXX - doesn't account for ZoneLow being able to grow. + // XXX - results not reliable when CONFIG_THREAD_OPTIONROMS + u32 maxspace = 0; + struct allocinfo_s *info; + for (info = zone->info; info; info = info->next) { + u32 space = info->allocend - info->dataend; + if (space > maxspace) + maxspace = space; + } + + if (zone != &ZoneTmpHigh && zone != &ZoneTmpLow) + return maxspace; + // Account for space needed for PMM tracking. + u32 reserve = ALIGN(sizeof(struct allocdetail_s), MALLOC_MIN_ALIGN); + if (maxspace <= reserve) + return 0; + return maxspace - reserve; +} + +// Find the data block allocated with pmm_malloc with a given handle. +static void * +pmm_find(u32 handle) +{ + int i; + for (i=0; iinfo; info; info = info->next) { + if (info->data != (void*)info) + continue; + struct allocdetail_s *detail = container_of( + info, struct allocdetail_s, detailinfo); + if (detail->handle == handle) + return detail->datainfo.data; + } + } + return NULL; +} + + +/**************************************************************** + * pmm interface + ****************************************************************/ + +struct pmmheader { + u32 signature; + u8 version; + u8 length; + u8 checksum; + u16 entry_offset; + u16 entry_seg; + u8 reserved[5]; +} PACKED; + +extern struct pmmheader PMMHEADER; + +#define PMM_SIGNATURE 0x4d4d5024 // $PMM + +#if CONFIG_PMM +struct pmmheader PMMHEADER __aligned(16) VAR16EXPORT = { + .version = 0x01, + .length = sizeof(PMMHEADER), + .entry_seg = SEG_BIOS, +}; +#endif + +#define PMM_FUNCTION_NOT_SUPPORTED 0xffffffff + +// PMM - allocate +static u32 +handle_pmm00(u16 *args) +{ + u32 length = *(u32*)&args[1], handle = *(u32*)&args[3]; + u16 flags = args[5]; + dprintf(3, "pmm00: length=%x handle=%x flags=%x\n" + , length, handle, flags); + struct zone_s *lowzone = &ZoneTmpLow, *highzone = &ZoneTmpHigh; + if (flags & 8) { + // Permanent memory request. + lowzone = &ZoneLow; + highzone = &ZoneHigh; + } + if (!length) { + // Memory size request + switch (flags & 3) { + default: + case 0: + return 0; + case 1: + return pmm_getspace(lowzone); + case 2: + return pmm_getspace(highzone); + case 3: { + u32 spacelow = pmm_getspace(lowzone); + u32 spacehigh = pmm_getspace(highzone); + if (spacelow > spacehigh) + return spacelow; + return spacehigh; + } + } + } + u32 size = length * 16; + if ((s32)size <= 0) + return 0; + u32 align = MALLOC_MIN_ALIGN; + if (flags & 4) { + align = 1<<__ffs(size); + if (align < MALLOC_MIN_ALIGN) + align = MALLOC_MIN_ALIGN; + } + switch (flags & 3) { + default: + case 0: + return 0; + case 1: + return (u32)pmm_malloc(lowzone, handle, size, align); + case 2: + return (u32)pmm_malloc(highzone, handle, size, align); + case 3: { + void *data = pmm_malloc(lowzone, handle, size, align); + if (data) + return (u32)data; + return (u32)pmm_malloc(highzone, handle, size, align); + } + } +} + +// PMM - find +static u32 +handle_pmm01(u16 *args) +{ + u32 handle = *(u32*)&args[1]; + dprintf(3, "pmm01: handle=%x\n", handle); + if (handle == PMM_DEFAULT_HANDLE) + return 0; + return (u32)pmm_find(handle); +} + +// PMM - deallocate +static u32 +handle_pmm02(u16 *args) +{ + u32 buffer = *(u32*)&args[1]; + dprintf(3, "pmm02: buffer=%x\n", buffer); + int ret = pmm_free((void*)buffer); + if (ret) + // Error + return 1; + return 0; +} + +static u32 +handle_pmmXX(u16 *args) +{ + return PMM_FUNCTION_NOT_SUPPORTED; +} + +u32 VISIBLE32INIT +handle_pmm(u16 *args) +{ + ASSERT32FLAT(); + if (! CONFIG_PMM) + return PMM_FUNCTION_NOT_SUPPORTED; + + u16 arg1 = args[0]; + dprintf(DEBUG_HDL_pmm, "pmm call arg1=%x\n", arg1); + + int oldpreempt; + if (CONFIG_THREAD_OPTIONROMS) { + // Not a preemption event - don't wait in wait_preempt() + oldpreempt = CanPreempt; + CanPreempt = 0; + } + + u32 ret; + switch (arg1) { + case 0x00: ret = handle_pmm00(args); break; + case 0x01: ret = handle_pmm01(args); break; + case 0x02: ret = handle_pmm02(args); break; + default: ret = handle_pmmXX(args); break; + } + + if (CONFIG_THREAD_OPTIONROMS) + CanPreempt = oldpreempt; + + return ret; +} + +// romlayout.S +extern void entry_pmm(void); + +void +pmm_setup(void) +{ + if (! CONFIG_PMM) + return; + + dprintf(3, "init PMM\n"); + + PMMHEADER.signature = PMM_SIGNATURE; + PMMHEADER.entry_offset = (u32)entry_pmm - BUILD_BIOS_ADDR; + PMMHEADER.checksum -= checksum(&PMMHEADER, sizeof(PMMHEADER)); +} + +void +pmm_finalize(void) +{ + if (! CONFIG_PMM) + return; + + dprintf(3, "finalize PMM\n"); + + PMMHEADER.signature = 0; + PMMHEADER.entry_offset = 0; +} diff --git a/bios/seabios/src/pnpbios.c b/bios/seabios/src/pnpbios.c new file mode 100644 index 0000000..b1bebc9 --- /dev/null +++ b/bios/seabios/src/pnpbios.c @@ -0,0 +1,103 @@ +// PNP BIOS calls +// +// Copyright (C) 2008 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // checksum +#include "config.h" // BUILD_BIOS_ADDR +#include "farptr.h" // SET_FARVAR + +struct pnpheader { + u32 signature; + u8 version; + u8 length; + u16 control; + u8 checksum; + u32 eventloc; + u16 real_ip; + u16 real_cs; + u16 prot_ip; + u32 prot_base; + u32 oemid; + u16 real_ds; + u32 prot_database; +} PACKED; + +extern struct pnpheader PNPHEADER; +extern char pnp_string[]; + +#if CONFIG_PNPBIOS +struct pnpheader PNPHEADER __aligned(16) VAR16EXPORT = { + .signature = PNP_SIGNATURE, + .version = 0x10, + .length = sizeof(PNPHEADER), + .real_cs = SEG_BIOS, + .prot_base = BUILD_BIOS_ADDR, + .real_ds = SEG_BIOS, + .prot_database = BUILD_BIOS_ADDR, +}; +#else +// We need a copy of this string in the 0xf000 segment, but we are not +// actually a PnP BIOS, so make sure it is *not* aligned, so OSes will +// not see it if they scan. +char pnp_string[] __aligned(2) VAR16VISIBLE = " $PnP"; +#endif + +#define FUNCTION_NOT_SUPPORTED 0x82 + +// BBS - Get Version and Installation Check +static u16 +handle_pnp60(u16 *args) +{ + u16 version_ptr = args[1]; + u16 version_seg = args[2]; + SET_FARVAR(version_seg, *(u16*)(version_ptr+0), 0x0101); + return 0; +} + +static u16 +handle_pnpXX(u16 *args) +{ + return FUNCTION_NOT_SUPPORTED; +} + +u16 VISIBLE16 +handle_pnp(u16 *args) +{ + if (! CONFIG_PNPBIOS) + return FUNCTION_NOT_SUPPORTED; + + u16 arg1 = args[0]; + dprintf(DEBUG_HDL_pnp, "pnp call arg1=%x\n", arg1); + + switch (arg1) { + case 0x60: return handle_pnp60(args); + default: return handle_pnpXX(args); + } +} + +u16 +get_pnp_offset(void) +{ + if (! CONFIG_PNPBIOS) + return (u32)pnp_string + 1 - BUILD_BIOS_ADDR; + return (u32)&PNPHEADER - BUILD_BIOS_ADDR; +} + +// romlayout.S +extern void entry_pnp_real(void); +extern void entry_pnp_prot(void); + +void +pnp_setup(void) +{ + if (! CONFIG_PNPBIOS) + return; + + dprintf(3, "init PNPBIOS table\n"); + + PNPHEADER.real_ip = (u32)entry_pnp_real - BUILD_BIOS_ADDR; + PNPHEADER.prot_ip = (u32)entry_pnp_prot - BUILD_BIOS_ADDR; + PNPHEADER.checksum -= checksum(&PNPHEADER, sizeof(PNPHEADER)); +} diff --git a/bios/seabios/src/post.c b/bios/seabios/src/post.c new file mode 100644 index 0000000..b4ad1fa --- /dev/null +++ b/bios/seabios/src/post.c @@ -0,0 +1,377 @@ +// 32bit code to Power On Self Test (POST) a machine. +// +// Copyright (C) 2008-2010 Kevin O'Connor +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "ioport.h" // PORT_* +#include "config.h" // CONFIG_* +#include "cmos.h" // CMOS_* +#include "util.h" // memset +#include "biosvar.h" // struct bios_data_area_s +#include "disk.h" // floppy_drive_setup +#include "ata.h" // ata_setup +#include "ahci.h" // ahci_setup +#include "memmap.h" // add_e820 +#include "pic.h" // pic_setup +#include "pci.h" // create_pirtable +#include "acpi.h" // acpi_bios_init +#include "bregs.h" // struct bregs +#include "mptable.h" // mptable_init +#include "boot.h" // IPL +#include "usb.h" // usb_setup +#include "smbios.h" // smbios_init +#include "paravirt.h" // qemu_cfg_port_probe +#include "xen.h" // xen_probe_hvm_info +#include "ps2port.h" // ps2port_setup +#include "virtio-blk.h" // virtio_blk_setup + + +/**************************************************************** + * BIOS init + ****************************************************************/ + +static void +init_ivt(void) +{ + dprintf(3, "init ivt\n"); + + // Initialize all vectors to the default handler. + int i; + for (i=0; i<256; i++) + SET_IVT(i, FUNC16(entry_iret_official)); + + // Initialize all hw vectors to a default hw handler. + for (i=0x08; i<=0x0f; i++) + SET_IVT(i, FUNC16(entry_hwpic1)); + for (i=0x70; i<=0x77; i++) + SET_IVT(i, FUNC16(entry_hwpic2)); + + // Initialize software handlers. + SET_IVT(0x02, FUNC16(entry_02)); + SET_IVT(0x10, FUNC16(entry_10)); + SET_IVT(0x11, FUNC16(entry_11)); + SET_IVT(0x12, FUNC16(entry_12)); + SET_IVT(0x13, FUNC16(entry_13_official)); + SET_IVT(0x14, FUNC16(entry_14)); + SET_IVT(0x15, FUNC16(entry_15)); + SET_IVT(0x16, FUNC16(entry_16)); + SET_IVT(0x17, FUNC16(entry_17)); + SET_IVT(0x18, FUNC16(entry_18)); + SET_IVT(0x19, FUNC16(entry_19_official)); + SET_IVT(0x1a, FUNC16(entry_1a)); + SET_IVT(0x40, FUNC16(entry_40)); + + // INT 60h-66h reserved for user interrupt + for (i=0x60; i<=0x66; i++) + SET_IVT(i, SEGOFF(0, 0)); + + // set vector 0x79 to zero + // this is used by 'gardian angel' protection system + SET_IVT(0x79, SEGOFF(0, 0)); + + SET_IVT(0x1E, SEGOFF(SEG_BIOS, (u32)&diskette_param_table2 - BUILD_BIOS_ADDR)); +} + +static void +init_bda(void) +{ + dprintf(3, "init bda\n"); + + struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0); + memset(bda, 0, sizeof(*bda)); + + int esize = EBDA_SIZE_START; + SET_BDA(mem_size_kb, BUILD_LOWRAM_END/1024 - esize); + u16 ebda_seg = EBDA_SEGMENT_START; + SET_BDA(ebda_seg, ebda_seg); + + // Init ebda + struct extended_bios_data_area_s *ebda = get_ebda_ptr(); + memset(ebda, 0, sizeof(*ebda)); + ebda->size = esize; + + add_e820((u32)MAKE_FLATPTR(ebda_seg, 0), GET_EBDA2(ebda_seg, size) * 1024 + , E820_RESERVED); +} + +static void +ram_probe(void) +{ + dprintf(3, "Find memory size\n"); + if (CONFIG_COREBOOT) { + coreboot_setup(); + } else if (usingXen()) { + xen_setup(); + } else { + // On emulators, get memory size from nvram. + u32 rs = ((inb_cmos(CMOS_MEM_EXTMEM2_LOW) << 16) + | (inb_cmos(CMOS_MEM_EXTMEM2_HIGH) << 24)); + if (rs) + rs += 16 * 1024 * 1024; + else + rs = (((inb_cmos(CMOS_MEM_EXTMEM_LOW) << 10) + | (inb_cmos(CMOS_MEM_EXTMEM_HIGH) << 18)) + + 1 * 1024 * 1024); + RamSize = rs; + add_e820(0, rs, E820_RAM); + + // Check for memory over 4Gig + u64 high = ((inb_cmos(CMOS_MEM_HIGHMEM_LOW) << 16) + | ((u32)inb_cmos(CMOS_MEM_HIGHMEM_MID) << 24) + | ((u64)inb_cmos(CMOS_MEM_HIGHMEM_HIGH) << 32)); + RamSizeOver4G = high; + add_e820(0x100000000ull, high, E820_RAM); + + /* reserve 256KB BIOS area at the end of 4 GB */ + add_e820(0xfffc0000, 256*1024, E820_RESERVED); + } + + // Don't declare any memory between 0xa0000 and 0x100000 + add_e820(BUILD_LOWRAM_END, BUILD_BIOS_ADDR-BUILD_LOWRAM_END, E820_HOLE); + + // Mark known areas as reserved. + add_e820(BUILD_BIOS_ADDR, BUILD_BIOS_SIZE, E820_RESERVED); + + u32 count = qemu_cfg_e820_entries(); + if (count) { + struct e820_reservation entry; + int i; + + for (i = 0; i < count; i++) { + qemu_cfg_e820_load_next(&entry); + add_e820(entry.address, entry.length, entry.type); + } + } else if (kvm_para_available()) { + // Backwards compatibility - provide hard coded range. + // 4 pages before the bios, 3 pages for vmx tss pages, the + // other page for EPT real mode pagetable + add_e820(0xfffbc000, 4*4096, E820_RESERVED); + } + + dprintf(1, "Ram Size=0x%08x (0x%08x%08x high)\n" + , RamSize, (u32)(RamSizeOver4G >> 32), (u32)RamSizeOver4G); +} + +static void +init_bios_tables(void) +{ + if (CONFIG_COREBOOT) { + coreboot_copy_biostable(); + return; + } + if (usingXen()) { + xen_copy_biostables(); + return; + } + + create_pirtable(); + + mptable_init(); + + smbios_init(); + + acpi_bios_init(); +} + +// Initialize hardware devices +static void +init_hw(void) +{ + usb_setup(); + ps2port_setup(); + lpt_setup(); + serial_setup(); + + floppy_setup(); + ata_setup(); + ahci_setup(); + cbfs_payload_setup(); + ramdisk_setup(); + virtio_blk_setup(); +} + +// Begin the boot process by invoking an int0x19 in 16bit mode. +void VISIBLE32FLAT +startBoot(void) +{ + // Clear low-memory allocations (required by PMM spec). + memset((void*)BUILD_STACK_ADDR, 0, BUILD_EBDA_MINIMUM - BUILD_STACK_ADDR); + + dprintf(3, "Jump to int19\n"); + struct bregs br; + memset(&br, 0, sizeof(br)); + br.flags = F_IF; + call16_int(0x19, &br); +} + +// Main setup code. +static void +maininit(void) +{ + // Running at new code address - do code relocation fixups + malloc_fixupreloc(); + + // Setup ivt/bda/ebda + init_ivt(); + init_bda(); + + // Init base pc hardware. + pic_setup(); + timer_setup(); + mathcp_setup(); + + // Initialize mtrr + mtrr_setup(); + + // Initialize pci + pci_setup(); + smm_init(); + + // Setup Xen hypercalls + xen_init_hypercalls(); + + // Initialize internal tables + boot_setup(); + + // Start hardware initialization (if optionrom threading) + if (CONFIG_THREADS && CONFIG_THREAD_OPTIONROMS) + init_hw(); + + // Find and initialize other cpus + smp_probe(); + + // Setup interfaces that option roms may need + bios32_setup(); + pmm_setup(); + pnp_setup(); + kbd_setup(); + mouse_setup(); + init_bios_tables(); + + // Run vga option rom + vga_setup(); + + // Do hardware initialization (if running synchronously) + if (!CONFIG_THREADS || !CONFIG_THREAD_OPTIONROMS) { + init_hw(); + wait_threads(); + } + + // Run option roms + optionrom_setup(); + + // Run BCVs and show optional boot menu + boot_prep(); + + // Finalize data structures before boot + cdemu_setup(); + pmm_finalize(); + malloc_finalize(); + memmap_finalize(); + + // Setup bios checksum. + BiosChecksum -= checksum((u8*)BUILD_BIOS_ADDR, BUILD_BIOS_SIZE); + + // Write protect bios memory. + make_bios_readonly(); + + // Invoke int 19 to start boot process. + startBoot(); +} + + +/**************************************************************** + * POST entry and code relocation + ****************************************************************/ + +// Update given relocs for the code at 'dest' with a given 'delta' +static void +updateRelocs(void *dest, u32 *rstart, u32 *rend, u32 delta) +{ + u32 *reloc; + for (reloc = rstart; reloc < rend; reloc++) + *((u32*)(dest + *reloc)) += delta; +} + +// Relocate init code and then call maininit() at new address. +static void +reloc_init(void) +{ + if (!CONFIG_RELOCATE_INIT) { + maininit(); + return; + } + // Symbols populated by the build. + extern u8 code32flat_start[]; + extern u8 _reloc_min_align[]; + extern u32 _reloc_abs_start[], _reloc_abs_end[]; + extern u32 _reloc_rel_start[], _reloc_rel_end[]; + extern u32 _reloc_init_start[], _reloc_init_end[]; + extern u8 code32init_start[], code32init_end[]; + + // Allocate space for init code. + u32 initsize = code32init_end - code32init_start; + u32 align = (u32)&_reloc_min_align; + void *dest = memalign_tmp(align, initsize); + if (!dest) + panic("No space for init relocation.\n"); + + // Copy code and update relocs (init absolute, init relative, and runtime) + dprintf(1, "Relocating init from %p to %p (size %d)\n" + , code32init_start, dest, initsize); + s32 delta = dest - (void*)code32init_start; + memcpy(dest, code32init_start, initsize); + updateRelocs(dest, _reloc_abs_start, _reloc_abs_end, delta); + updateRelocs(dest, _reloc_rel_start, _reloc_rel_end, -delta); + updateRelocs(code32flat_start, _reloc_init_start, _reloc_init_end, delta); + + // Call maininit() in relocated code. + void (*func)(void) = (void*)maininit + delta; + barrier(); + func(); +} + +// Setup for code relocation and then call reloc_init +void VISIBLE32INIT +dopost(void) +{ + HaveRunPost = 1; + + // Detect ram and setup internal malloc. + qemu_cfg_port_probe(); + ram_probe(); + malloc_setup(); + + // Relocate initialization code and call maininit(). + reloc_init(); +} + +// Entry point for Power On Self Test (POST) - the BIOS initilization +// phase. This function makes the memory at 0xc0000-0xfffff +// read/writable and then calls dopost(). +void VISIBLE32FLAT +handle_post(void) +{ + debug_serial_setup(); + dprintf(1, "Start bios (version %s)\n", VERSION); + + // Enable CPU caching + setcr0(getcr0() & ~(CR0_CD|CR0_NW)); + + // Clear CMOS reboot flag. + outb_cmos(0, CMOS_RESET_CODE); + + // Make sure legacy DMA isn't running. + init_dma(); + + // Check if we are running under Xen. + xen_probe(); + + // Allow writes to modify bios area (0xf0000) + make_bios_writable(); + + // Now that memory is read/writable - start post process. + dopost(); +} diff --git a/bios/seabios/src/ps2port.c b/bios/seabios/src/ps2port.c new file mode 100644 index 0000000..58335af --- /dev/null +++ b/bios/seabios/src/ps2port.c @@ -0,0 +1,494 @@ +// Support for handling the PS/2 mouse/keyboard ports. +// +// Copyright (C) 2008 Kevin O'Connor +// Several ideas taken from code Copyright (c) 1999-2004 Vojtech Pavlik +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "ioport.h" // inb +#include "util.h" // dprintf +#include "paravirt.h" // romfile_loadint +#include "biosvar.h" // GET_EBDA +#include "ps2port.h" // ps2_kbd_command +#include "pic.h" // eoi_pic1 + + +/**************************************************************** + * Low level i8042 commands. + ****************************************************************/ + +// Timeout value. +#define I8042_CTL_TIMEOUT 10000 + +#define I8042_BUFFER_SIZE 16 + +static int +i8042_wait_read(void) +{ + dprintf(7, "i8042_wait_read\n"); + int i; + for (i=0; i> 8) & 0xf; + int send = (command >> 12) & 0xf; + + // Send the command. + int ret = i8042_wait_write(); + if (ret) + return ret; + outb(command, PORT_PS2_STATUS); + + // Send parameters (if any). + int i; + for (i = 0; i < send; i++) { + ret = i8042_wait_write(); + if (ret) + return ret; + outb(param[i], PORT_PS2_DATA); + } + + // Receive parameters (if any). + for (i = 0; i < receive; i++) { + ret = i8042_wait_read(); + if (ret) + return ret; + param[i] = inb(PORT_PS2_DATA); + dprintf(7, "i8042 param=%x\n", param[i]); + } + + return 0; +} + +static int +i8042_command(int command, u8 *param) +{ + dprintf(7, "i8042_command cmd=%x\n", command); + int ret = __i8042_command(command, param); + if (ret) + dprintf(2, "i8042 command %x failed\n", command); + return ret; +} + +static int +i8042_kbd_write(u8 c) +{ + dprintf(7, "i8042_kbd_write c=%d\n", c); + int ret = i8042_wait_write(); + if (! ret) + outb(c, PORT_PS2_DATA); + return ret; +} + +static int +i8042_aux_write(u8 c) +{ + return i8042_command(I8042_CMD_AUX_SEND, &c); +} + +void +i8042_reboot(void) +{ + int i; + for (i=0; i<10; i++) { + i8042_wait_write(); + udelay(50); + outb(0xfe, PORT_PS2_STATUS); /* pulse reset low */ + udelay(50); + } +} + + +/**************************************************************** + * Device commands. + ****************************************************************/ + +#define PS2_RET_ACK 0xfa +#define PS2_RET_NAK 0xfe + +static int +ps2_recvbyte(int aux, int needack, int timeout) +{ + u64 end = calc_future_tsc(timeout); + for (;;) { + u8 status = inb(PORT_PS2_STATUS); + if (status & I8042_STR_OBF) { + u8 data = inb(PORT_PS2_DATA); + dprintf(7, "ps2 read %x\n", data); + + if (!!(status & I8042_STR_AUXDATA) == aux) { + if (!needack) + return data; + if (data == PS2_RET_ACK) + return data; + if (data == PS2_RET_NAK) { + dprintf(1, "Got ps2 nak (status=%x)\n", status); + return data; + } + } + + // This data not part of command - just discard it. + dprintf(1, "Discarding ps2 data %02x (status=%02x)\n", data, status); + } + + if (check_tsc(end)) { + // Don't warn on second byte of a reset + if (timeout > 100) + warn_timeout(); + return -1; + } + yield(); + } +} + +static int +ps2_sendbyte(int aux, u8 command, int timeout) +{ + dprintf(7, "ps2_sendbyte aux=%d cmd=%x\n", aux, command); + int ret; + if (aux) + ret = i8042_aux_write(command); + else + ret = i8042_kbd_write(command); + if (ret) + return ret; + + // Read ack. + ret = ps2_recvbyte(aux, 1, timeout); + if (ret < 0) + return ret; + if (ret != PS2_RET_ACK) + return -1; + + return 0; +} + +static int +__ps2_command(int aux, int command, u8 *param) +{ + int ret2; + int receive = (command >> 8) & 0xf; + int send = (command >> 12) & 0xf; + + // Disable interrupts and keyboard/mouse. + u8 ps2ctr = GET_EBDA(ps2ctr); + u8 newctr = ((ps2ctr | I8042_CTR_AUXDIS | I8042_CTR_KBDDIS) + & ~(I8042_CTR_KBDINT|I8042_CTR_AUXINT)); + dprintf(6, "i8042 ctr old=%x new=%x\n", ps2ctr, newctr); + int ret = i8042_command(I8042_CMD_CTL_WCTR, &newctr); + if (ret) + return ret; + + // Flush any interrupts already pending. + yield(); + + // Enable port command is being sent to. + if (aux) + newctr &= ~I8042_CTR_AUXDIS; + else + newctr &= ~I8042_CTR_KBDDIS; + ret = i8042_command(I8042_CMD_CTL_WCTR, &newctr); + if (ret) + goto fail; + + if (command == ATKBD_CMD_RESET_BAT) { + // Reset is special wrt timeouts and bytes received. + + // Send command. + ret = ps2_sendbyte(aux, command, 1000); + if (ret) + goto fail; + + // Receive parameters. + ret = ps2_recvbyte(aux, 0, 4000); + if (ret < 0) + goto fail; + param[0] = ret; + ret = ps2_recvbyte(aux, 0, 100); + if (ret < 0) + // Some devices only respond with one byte on reset. + ret = 0; + param[1] = ret; + } else if (command == ATKBD_CMD_GETID) { + // Getid is special wrt bytes received. + + // Send command. + ret = ps2_sendbyte(aux, command, 200); + if (ret) + goto fail; + + // Receive parameters. + ret = ps2_recvbyte(aux, 0, 500); + if (ret < 0) + goto fail; + param[0] = ret; + if (ret == 0xab || ret == 0xac || ret == 0x2b || ret == 0x5d + || ret == 0x60 || ret == 0x47) { + // These ids (keyboards) return two bytes. + ret = ps2_recvbyte(aux, 0, 500); + if (ret < 0) + goto fail; + param[1] = ret; + } else { + param[1] = 0; + } + } else { + // Send command. + ret = ps2_sendbyte(aux, command, 200); + if (ret) + goto fail; + + // Send parameters (if any). + int i; + for (i = 0; i < send; i++) { + ret = ps2_sendbyte(aux, param[i], 200); + if (ret) + goto fail; + } + + // Receive parameters (if any). + for (i = 0; i < receive; i++) { + ret = ps2_recvbyte(aux, 0, 500); + if (ret < 0) + goto fail; + param[i] = ret; + } + } + + ret = 0; + +fail: + // Restore interrupts and keyboard/mouse. + ret2 = i8042_command(I8042_CMD_CTL_WCTR, &ps2ctr); + if (ret2) + return ret2; + + return ret; +} + +static int +ps2_command(int aux, int command, u8 *param) +{ + dprintf(7, "ps2_command aux=%d cmd=%x\n", aux, command); + int ret = __ps2_command(aux, command, param); + if (ret) + dprintf(2, "ps2 command %x failed (aux=%d)\n", command, aux); + return ret; +} + +int +ps2_kbd_command(int command, u8 *param) +{ + return ps2_command(0, command, param); +} + +int +ps2_mouse_command(int command, u8 *param) +{ + // Update ps2ctr for mouse enable/disable. + if (command == PSMOUSE_CMD_ENABLE || command == PSMOUSE_CMD_DISABLE) { + u16 ebda_seg = get_ebda_seg(); + u8 ps2ctr = GET_EBDA2(ebda_seg, ps2ctr); + if (command == PSMOUSE_CMD_ENABLE) + ps2ctr = (ps2ctr | I8042_CTR_AUXINT) & ~I8042_CTR_AUXDIS; + else + ps2ctr = (ps2ctr | I8042_CTR_AUXDIS) & ~I8042_CTR_AUXINT; + SET_EBDA2(ebda_seg, ps2ctr, ps2ctr); + } + + return ps2_command(1, command, param); +} + + +/**************************************************************** + * IRQ handlers + ****************************************************************/ + +// INT74h : PS/2 mouse hardware interrupt +void VISIBLE16 +handle_74(void) +{ + if (! CONFIG_PS2PORT) + return; + + debug_isr(DEBUG_ISR_74); + + u8 v = inb(PORT_PS2_STATUS); + if ((v & (I8042_STR_OBF|I8042_STR_AUXDATA)) + != (I8042_STR_OBF|I8042_STR_AUXDATA)) { + dprintf(1, "ps2 mouse irq but no mouse data.\n"); + goto done; + } + v = inb(PORT_PS2_DATA); + + if (!(GET_EBDA(ps2ctr) & I8042_CTR_AUXINT)) + // Interrupts not enabled. + goto done; + + process_mouse(v); + +done: + eoi_pic2(); +} + +// INT09h : Keyboard Hardware Service Entry Point +void VISIBLE16 +handle_09(void) +{ + if (! CONFIG_PS2PORT) + return; + + debug_isr(DEBUG_ISR_09); + + // read key from keyboard controller + u8 v = inb(PORT_PS2_STATUS); + if (v & I8042_STR_AUXDATA) { + dprintf(1, "ps2 keyboard irq but found mouse data?!\n"); + goto done; + } + v = inb(PORT_PS2_DATA); + + if (!(GET_EBDA(ps2ctr) & I8042_CTR_KBDINT)) + // Interrupts not enabled. + goto done; + + process_key(v); + +done: + eoi_pic1(); +} + + +/**************************************************************** + * Setup + ****************************************************************/ + +static void +keyboard_init(void *data) +{ + /* flush incoming keys */ + int ret = i8042_flush(); + if (ret) + return; + + // Controller self-test. + u8 param[2]; + ret = i8042_command(I8042_CMD_CTL_TEST, param); + if (ret) + return; + if (param[0] != 0x55) { + dprintf(1, "i8042 self test failed (got %x not 0x55)\n", param[0]); + return; + } + + // Controller keyboard test. + ret = i8042_command(I8042_CMD_KBD_TEST, param); + if (ret) + return; + if (param[0] != 0x00) { + dprintf(1, "i8042 keyboard test failed (got %x not 0x00)\n", param[0]); + return; + } + + // Disable keyboard and mouse events. + SET_EBDA(ps2ctr, I8042_CTR_KBDDIS | I8042_CTR_AUXDIS); + + + /* ------------------- keyboard side ------------------------*/ + /* reset keyboard and self test (keyboard side) */ + int spinupdelay = romfile_loadint("etc/ps2-keyboard-spinup", 0); + u64 end = calc_future_tsc(spinupdelay); + for (;;) { + ret = ps2_kbd_command(ATKBD_CMD_RESET_BAT, param); + if (!ret) + break; + if (check_tsc(end)) { + if (spinupdelay) + warn_timeout(); + return; + } + yield(); + } + if (param[0] != 0xaa) { + dprintf(1, "keyboard self test failed (got %x not 0xaa)\n", param[0]); + return; + } + + /* Disable keyboard */ + ret = ps2_kbd_command(ATKBD_CMD_RESET_DIS, NULL); + if (ret) + return; + + // Set scancode command (mode 2) + param[0] = 0x02; + ret = ps2_kbd_command(ATKBD_CMD_SSCANSET, param); + if (ret) + return; + + // Keyboard Mode: disable mouse, scan code convert, enable kbd IRQ + SET_EBDA(ps2ctr, I8042_CTR_AUXDIS | I8042_CTR_XLATE | I8042_CTR_KBDINT); + + /* Enable keyboard */ + ret = ps2_kbd_command(ATKBD_CMD_ENABLE, NULL); + if (ret) + return; + + dprintf(1, "PS2 keyboard initialized\n"); +} + +void +ps2port_setup(void) +{ + ASSERT32FLAT(); + if (! CONFIG_PS2PORT) + return; + dprintf(3, "init ps2port\n"); + + enable_hwirq(1, FUNC16(entry_09)); + enable_hwirq(12, FUNC16(entry_74)); + + run_thread(keyboard_init, NULL); +} diff --git a/bios/seabios/src/ps2port.h b/bios/seabios/src/ps2port.h new file mode 100644 index 0000000..dcae391 --- /dev/null +++ b/bios/seabios/src/ps2port.h @@ -0,0 +1,63 @@ +// Basic ps2 port (keyboard/mouse) command handling. +#ifndef __PS2PORT_H +#define __PS2PORT_H + +#include "types.h" // u8 + +// Standard commands. +#define I8042_CMD_CTL_RCTR 0x0120 +#define I8042_CMD_CTL_WCTR 0x1060 +#define I8042_CMD_CTL_TEST 0x01aa + +#define I8042_CMD_KBD_TEST 0x01ab +#define I8042_CMD_KBD_DISABLE 0x00ad +#define I8042_CMD_KBD_ENABLE 0x00ae + +#define I8042_CMD_AUX_DISABLE 0x00a7 +#define I8042_CMD_AUX_ENABLE 0x00a8 +#define I8042_CMD_AUX_SEND 0x10d4 + +// Keyboard commands +#define ATKBD_CMD_SETLEDS 0x10ed +#define ATKBD_CMD_SSCANSET 0x10f0 +#define ATKBD_CMD_GETID 0x02f2 +#define ATKBD_CMD_ENABLE 0x00f4 +#define ATKBD_CMD_RESET_DIS 0x00f5 +#define ATKBD_CMD_RESET_BAT 0x02ff + +// Mouse commands +#define PSMOUSE_CMD_SETSCALE11 0x00e6 +#define PSMOUSE_CMD_SETSCALE21 0x00e7 +#define PSMOUSE_CMD_SETRES 0x10e8 +#define PSMOUSE_CMD_GETINFO 0x03e9 +#define PSMOUSE_CMD_GETID 0x02f2 +#define PSMOUSE_CMD_SETRATE 0x10f3 +#define PSMOUSE_CMD_ENABLE 0x00f4 +#define PSMOUSE_CMD_DISABLE 0x00f5 +#define PSMOUSE_CMD_RESET_BAT 0x02ff + +// Status register bits. +#define I8042_STR_PARITY 0x80 +#define I8042_STR_TIMEOUT 0x40 +#define I8042_STR_AUXDATA 0x20 +#define I8042_STR_KEYLOCK 0x10 +#define I8042_STR_CMDDAT 0x08 +#define I8042_STR_MUXERR 0x04 +#define I8042_STR_IBF 0x02 +#define I8042_STR_OBF 0x01 + +// Control register bits. +#define I8042_CTR_KBDINT 0x01 +#define I8042_CTR_AUXINT 0x02 +#define I8042_CTR_IGNKEYLOCK 0x08 +#define I8042_CTR_KBDDIS 0x10 +#define I8042_CTR_AUXDIS 0x20 +#define I8042_CTR_XLATE 0x40 + +// functions +void i8042_reboot(void); +int ps2_kbd_command(int command, u8 *param); +int ps2_mouse_command(int command, u8 *param); +void ps2port_setup(void); + +#endif // ps2port.h diff --git a/bios/seabios/src/ramdisk.c b/bios/seabios/src/ramdisk.c new file mode 100644 index 0000000..bae30e2 --- /dev/null +++ b/bios/seabios/src/ramdisk.c @@ -0,0 +1,105 @@ +// Code for emulating a drive via high-memory accesses. +// +// Copyright (C) 2009 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "disk.h" // process_ramdisk_op +#include "util.h" // dprintf +#include "memmap.h" // add_e820 +#include "biosvar.h" // GET_GLOBAL +#include "bregs.h" // struct bregs +#include "boot.h" // boot_add_floppy + +void +ramdisk_setup(void) +{ + if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH || !CONFIG_FLASH_FLOPPY) + return; + + // Find image. + struct cbfs_file *file = cbfs_findprefix("floppyimg/", NULL); + if (!file) + return; + const char *filename = cbfs_filename(file); + u32 size = cbfs_datasize(file); + dprintf(3, "Found floppy file %s of size %d\n", filename, size); + int ftype = find_floppy_type(size); + if (ftype < 0) { + dprintf(3, "No floppy type found for ramdisk size\n"); + return; + } + + // Allocate ram for image. + void *pos = memalign_tmphigh(PAGE_SIZE, size); + if (!pos) { + warn_noalloc(); + return; + } + add_e820((u32)pos, size, E820_RESERVED); + + // Copy image into ram. + cbfs_copyfile(file, pos, size); + + // Setup driver. + struct drive_s *drive_g = init_floppy((u32)pos, ftype); + if (!drive_g) + return; + drive_g->type = DTYPE_RAMDISK; + dprintf(1, "Mapping CBFS floppy %s to addr %p\n", filename, pos); + char *desc = znprintf(MAXDESCSIZE, "Ramdisk [%s]", &filename[10]); + boot_add_floppy(drive_g, desc, bootprio_find_named_rom(filename, 0)); +} + +static int +ramdisk_copy(struct disk_op_s *op, int iswrite) +{ + u32 offset = GET_GLOBAL(op->drive_g->cntl_id); + offset += (u32)op->lba * DISK_SECTOR_SIZE; + u64 opd = GDT_DATA | GDT_LIMIT(0xfffff) | GDT_BASE((u32)op->buf_fl); + u64 ramd = GDT_DATA | GDT_LIMIT(0xfffff) | GDT_BASE(offset); + + u64 gdt[6]; + if (iswrite) { + gdt[2] = opd; + gdt[3] = ramd; + } else { + gdt[2] = ramd; + gdt[3] = opd; + } + + // Call int 1587 to copy data. + struct bregs br; + memset(&br, 0, sizeof(br)); + br.flags = F_CF|F_IF; + br.ah = 0x87; + br.es = GET_SEG(SS); + br.si = (u32)gdt; + br.cx = op->count * DISK_SECTOR_SIZE / 2; + call16_int(0x15, &br); + + if (br.flags & F_CF) + return DISK_RET_EBADTRACK; + return DISK_RET_SUCCESS; +} + +int +process_ramdisk_op(struct disk_op_s *op) +{ + if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH || !CONFIG_FLASH_FLOPPY) + return 0; + + switch (op->command) { + case CMD_READ: + return ramdisk_copy(op, 0); + case CMD_WRITE: + return ramdisk_copy(op, 1); + case CMD_VERIFY: + case CMD_FORMAT: + case CMD_RESET: + return DISK_RET_SUCCESS; + default: + op->count = 0; + return DISK_RET_EPARAM; + } +} diff --git a/bios/seabios/src/resume.c b/bios/seabios/src/resume.c new file mode 100644 index 0000000..4390fb5 --- /dev/null +++ b/bios/seabios/src/resume.c @@ -0,0 +1,160 @@ +// Code for handling calls to "post" that are resume related. +// +// Copyright (C) 2008,2009 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // dprintf +#include "ioport.h" // outb +#include "pic.h" // eoi_pic2 +#include "biosvar.h" // struct bios_data_area_s +#include "bregs.h" // struct bregs +#include "acpi.h" // find_resume_vector +#include "ps2port.h" // i8042_reboot +#include "pci.h" // pci_reboot +#include "cmos.h" // inb_cmos + +// Indicator if POST phase has been run. +int HaveRunPost VAR16VISIBLE; + +// Reset DMA controller +void +init_dma(void) +{ + // 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); +} + +// Handler for post calls that look like a resume. +void VISIBLE16 +handle_resume(void) +{ + debug_serial_setup(); + int status = inb_cmos(CMOS_RESET_CODE); + outb_cmos(0, CMOS_RESET_CODE); + dprintf(1, "In resume (status=%d)\n", status); + + init_dma(); + + switch (status) { + case 0x01 ... 0x04: + case 0x06 ... 0x09: + panic("Unimplemented shutdown status: %02x\n", status); + + case 0x05: + // flush keyboard (issue EOI) and jump via 40h:0067h + eoi_pic2(); + // NO BREAK + case 0x0a: +#define BDA_JUMP (((struct bios_data_area_s *)0)->jump) + // resume execution by jump via 40h:0067h + asm volatile( + "movw %w1, %%ds\n" + "ljmpw *%0\n" + : : "m"(BDA_JUMP), "r"(SEG_BDA) + ); + break; + + case 0x0b: + // resume execution via IRET via 40h:0067h + asm volatile( + "movw %w1, %%ds\n" + "lssw %0, %%sp\n" + "iretw\n" + : : "m"(BDA_JUMP), "r"(SEG_BDA) + ); + break; + + case 0x0c: + // resume execution via RETF via 40h:0067h + asm volatile( + "movw %w1, %%ds\n" + "lssw %0, %%sp\n" + "lretw\n" + : : "m"(BDA_JUMP), "r"(SEG_BDA) + ); + break; + + default: + break; + } + + // Not a 16bit resume - do remaining checks in 32bit mode + asm volatile( + "movw %w1, %%ss\n" + "movl %0, %%esp\n" + "movl $_cfunc32flat_handle_resume32, %%edx\n" + "jmp transition32\n" + : : "i"(BUILD_S3RESUME_STACK_ADDR), "r"(0), "a"(status) + ); +} + +// Handle an S3 resume event +static void +s3_resume(void) +{ + if (!CONFIG_S3_RESUME) + return; + + u32 s3_resume_vector = find_resume_vector(); + if (!s3_resume_vector) { + dprintf(1, "No resume vector set!\n"); + return; + } + + smm_init(); + + s3_resume_vga_init(); + + make_bios_readonly(); + + // Invoke the resume vector. + struct bregs br; + memset(&br, 0, sizeof(br)); + dprintf(1, "Jump to resume vector (%x)\n", s3_resume_vector); + br.code = FLATPTR_TO_SEGOFF((void*)s3_resume_vector); + call16big(&br); +} + +// Attempt to invoke a hard-reboot. +static void +tryReboot(void) +{ + dprintf(1, "Attempting a hard reboot\n"); + + // Setup for reset on qemu. + if (! CONFIG_COREBOOT) { + qemu_prep_reset(); + if (HaveRunPost) + apm_shutdown(); + } + + // Try keyboard controller reboot. + i8042_reboot(); + + // Try PCI 0xcf9 reboot + pci_reboot(); + + // Try triple fault + asm volatile("int3"); + + panic("Could not reboot"); +} + +void VISIBLE32FLAT +handle_resume32(int status) +{ + ASSERT32FLAT(); + dprintf(1, "In 32bit resume\n"); + + if (status == 0xfe) + s3_resume(); + + // Must be a soft reboot - invoke a hard reboot. + tryReboot(); +} diff --git a/bios/seabios/src/romlayout.S b/bios/seabios/src/romlayout.S new file mode 100644 index 0000000..5983a4a --- /dev/null +++ b/bios/seabios/src/romlayout.S @@ -0,0 +1,554 @@ +// Rom layout and bios assembler to C interface. +// +// Copyright (C) 2008,2009 Kevin O'Connor +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + + +/**************************************************************** + * Include of 16bit C code + ****************************************************************/ + + .code16gcc +#include "ccode.16.s" + +#include "config.h" // CONFIG_* +#include "ioport.h" // PORT_A20 +#include "bregs.h" // CR0_* +#include "cmos.h" // CMOS_RESET_CODE +#include "asm-offsets.h" // BREGS_* +#include "entryfuncs.S" // ENTRY_* + + +/**************************************************************** + * Call trampolines + ****************************************************************/ + +// Place CPU into 32bit mode from 16bit mode. +// %edx = return location (in 32bit mode) +// Clobbers: ecx, flags, segment registers, cr0, idt/gdt + DECLFUNC transition32 +transition32: + movl %eax, %ecx + + // Disable irqs (and clear direction flag) + cli + cld + + // Disable nmi + movl $CMOS_RESET_CODE|NMI_DISABLE_BIT, %eax + outb %al, $PORT_CMOS_INDEX + inb $PORT_CMOS_DATA, %al + + // enable a20 + inb $PORT_A20, %al + orb $A20_ENABLE_BIT, %al + outb %al, $PORT_A20 + + // Set segment descriptors + lidtw %cs:pmode_IDT_info + lgdtw %cs:rombios32_gdt_48 + + // Enable protected mode + movl %cr0, %eax + orl $CR0_PE, %eax + movl %eax, %cr0 + + // start 32bit protected mode code + ljmpl $SEG32_MODE32_CS, $(BUILD_BIOS_ADDR + 1f) + + .code32 +1: + // init data segments + movl $SEG32_MODE32_DS, %eax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + movw %ax, %fs + movw %ax, %gs + + movl %ecx, %eax + jmpl *%edx + +// Place CPU into 16bit mode from 32bit mode. +// %edx = return location (in 16bit mode) +// Clobbers: ecx, flags, segment registers, cr0, idt/gdt + DECLFUNC transition16 + .global transition16big +transition16: + movl %eax, %ecx + + // restore data segment limits to 0xffff + movl $SEG32_MODE16_DS, %eax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + movw %ax, %fs + movw %ax, %gs + +#if CONFIG_DISABLE_A20 + // disable a20 + inb $PORT_A20, %al + andb $~A20_ENABLE_BIT, %al + outb %al, $PORT_A20 +#endif + + // Jump to 16bit mode + ljmpw $SEG32_MODE16_CS, $1f + +transition16big: + movl %eax, %ecx + + movl $SEG32_MODE16BIG_DS, %eax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + movw %ax, %fs + movw %ax, %gs + + ljmpw $SEG32_MODE16BIG_CS, $1f + + .code16gcc +1: + // Disable protected mode + movl %cr0, %eax + andl $~CR0_PE, %eax + movl %eax, %cr0 + + // far jump to flush CPU queue after transition to real mode + ljmpw $SEG_BIOS, $2f + +2: + // restore IDT to normal real-mode defaults + lidtw %cs:rmode_IDT_info + + // Clear segment registers + xorw %ax, %ax + movw %ax, %fs + movw %ax, %gs + movw %ax, %es + movw %ax, %ds + movw %ax, %ss // Assume stack is in segment 0 + + movl %ecx, %eax + jmpl *%edx + +// Call a 16bit function from 16bit mode with a specified cpu register state +// %eax = address of struct bregs +// Clobbers: %e[bcd]x, %e[ds]i, flags + DECLFUNC __call16 +__call16: + // Save %eax, %ebp + pushl %ebp + pushl %eax + + // Setup for iretw call + pushw %cs + pushw $1f // return point + pushw BREGS_flags(%eax) // flags + pushl BREGS_code(%eax) // CS:IP + + // Load calling registers. + movl BREGS_edi(%eax), %edi + movl BREGS_esi(%eax), %esi + movl BREGS_ebp(%eax), %ebp + movl BREGS_ebx(%eax), %ebx + movl BREGS_edx(%eax), %edx + movl BREGS_ecx(%eax), %ecx + movw BREGS_es(%eax), %es + movw BREGS_ds(%eax), %ds + movl %ss:BREGS_eax(%eax), %eax + + // Invoke call + iretw // XXX - just do a lcalll +1: + // Store flags, eax, ecx + pushfw + pushl %eax + movl 0x06(%esp), %eax + movl %ecx, %ss:BREGS_ecx(%eax) + movw %ds, %ss:BREGS_ds(%eax) + movw %ss, %cx + movw %cx, %ds // Restore %ds == %ss + popl %ecx + movl %ecx, BREGS_eax(%eax) + popw %cx + movw %cx, BREGS_flags(%eax) + + // Store remaining registers + movw %es, BREGS_es(%eax) + movl %edi, BREGS_edi(%eax) + movl %esi, BREGS_esi(%eax) + movl %ebp, BREGS_ebp(%eax) + movl %ebx, BREGS_ebx(%eax) + movl %edx, BREGS_edx(%eax) + + // Remove %eax, restore %ebp + popl %eax + popl %ebp + + retl + +// Call a 16bit function from 32bit mode. +// %eax = address of struct bregs +// Clobbers: %e[bcd]x, %e[ds]i, flags, segment registers, idt/gdt + DECLFUNC __call16_from32 + .global __call16big_from32 + .code32 +__call16_from32: + movl $1f, %edx + jmp transition16 +__call16big_from32: + movl $1f, %edx + jmp transition16big + + // Make call. + .code16gcc +1: calll __call16 + // Return via transition32 + movl $(2f + BUILD_BIOS_ADDR), %edx + jmp transition32 + .code32 +2: retl + + .code16gcc +// IRQ trampolines + .macro IRQ_TRAMPOLINE num + DECLFUNC irq_trampoline_0x\num + irq_trampoline_0x\num : + int $0x\num + lretw + .endm + + IRQ_TRAMPOLINE 10 + IRQ_TRAMPOLINE 13 + IRQ_TRAMPOLINE 15 + IRQ_TRAMPOLINE 16 + IRQ_TRAMPOLINE 18 + IRQ_TRAMPOLINE 19 + + +/**************************************************************** + * Misc. entry points. + ****************************************************************/ + +// Resume (and reboot) entry point - called from entry_post + DECLFUNC entry_resume +entry_resume: + // Disable interrupts + cli + cld + // Use a stack in EBDA + movw $SEG_BDA, %ax + movw %ax, %ds + movw BDA_ebda_seg, %ax + movw %ax, %ds + movw %ax, %ss + movl $EBDA_OFFSET_TOP_STACK, %esp + // Call handler. + jmp handle_resume + +// PMM entry point + DECLFUNC entry_pmm +entry_pmm: + pushl %esp // Backup %esp, then clear high bits + movzwl %sp, %esp + pushfl // Save registers clobbered by C code + cli + cld + pushl %eax + pushl %ecx + pushl %edx + pushw %es + pushw %ds + movw %ss, %cx // Move %ss to %ds + movw %cx, %ds + movl $_cfunc32flat_handle_pmm, %eax // Setup: call32(handle_pmm, args, -1) + leal 28(%esp), %edx // %edx points to start of args + movl $-1, %ecx + calll call32 + movw %ax, 12(%esp) // Modify %ax:%dx to return %eax + shrl $16, %eax + movw %ax, 4(%esp) + popw %ds // Restore saved registers + popw %es + popl %edx + popl %ecx + popl %eax + popfl + popl %esp + lretw + +// PnP entry points + DECLFUNC entry_pnp_real + .global entry_pnp_prot +entry_pnp_prot: + pushl %esp + jmp 1f +entry_pnp_real: + pushl %esp // Backup %esp, then clear high bits + movzwl %sp, %esp +1: + pushfl // Save registers clobbered by C code + cli + cld + pushl %eax + pushl %ecx + pushl %edx + pushw %es + pushw %ds + movw %ss, %cx // Move %ss to %ds + movw %cx, %ds + leal 28(%esp), %eax // %eax points to start of u16 args + calll handle_pnp + movw %ax, 12(%esp) // Modify %eax to return %ax + popw %ds + popw %es + popl %edx + popl %ecx + popl %eax + popfl + popl %esp + lretw + +// APM entry points + DECLFUNC entry_apm16 +entry_apm16: + pushfw // save flags + pushl %eax // dummy + ENTRY_ARG handle_apm16 + addw $4, %sp // pop dummy + popfw // restore flags + lretw + + .code32 + DECLFUNC entry_apm32 +entry_apm32: + pushfl + pushl %gs + pushl %cs // Move second descriptor after %cs to %gs + addl $16, (%esp) + popl %gs + ENTRY_ARG_ESP _cfunc32seg_handle_apm32 + popl %gs + popfl + lretl + +// PCI-BIOS 32bit entry point + DECLFUNC entry_pcibios32 +entry_pcibios32: + pushfl + pushl %gs // Backup %gs and set %gs=%ds + pushl %ds + popl %gs + ENTRY_ARG_ESP _cfunc32seg_handle_pcibios32 + popl %gs + popfl + lretl + +// BIOS32 support + EXPORTFUNC entry_bios32 +entry_bios32: + pushfl +#if CONFIG_PCIBIOS + // Check for PCI-BIOS request + cmpl $0x49435024, %eax // $PCI + jne 1f + movl $BUILD_BIOS_ADDR, %ebx + movl $BUILD_BIOS_SIZE, %ecx + movl $entry_pcibios32, %edx + xorb %al, %al + jmp 2f +#endif + // Unknown request +1: movb $0x80, %al + // Return to caller +2: popfl + lretl + +// 32bit elf entry point + EXPORTFUNC entry_elf +entry_elf: + cli + cld + lidtl (BUILD_BIOS_ADDR + pmode_IDT_info) + lgdtl (BUILD_BIOS_ADDR + rombios32_gdt_48) + movl $SEG32_MODE32_DS, %eax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + movl $BUILD_STACK_ADDR, %esp + ljmpl $SEG32_MODE32_CS, $_cfunc32flat_handle_post + + .code16gcc + + +/**************************************************************** + * Interrupt entry points + ****************************************************************/ + + // Main entry point for interrupts without args + DECLFUNC irqentry +irqentry: + ENTRY_ST + iretw + + // Main entry point for interrupts with args + DECLFUNC irqentryarg +irqentryarg: + ENTRY_ARG_ST + iretw + + // Define an entry point for an interrupt (no args passed). + .macro IRQ_ENTRY num + .global entry_\num + entry_\num : + pushl $ handle_\num + jmp irqentry + .endm + + .macro DECL_IRQ_ENTRY num + DECLFUNC entry_\num + IRQ_ENTRY \num + .endm + + // Define an entry point for an interrupt (can read/modify args). + .macro IRQ_ENTRY_ARG num + .global entry_\num + entry_\num : + pushl $ handle_\num + jmp irqentryarg + .endm + + .macro DECL_IRQ_ENTRY_ARG num + DECLFUNC entry_\num + IRQ_ENTRY_ARG \num + .endm + + // Various entry points (that don't require a fixed location). + DECL_IRQ_ENTRY_ARG 13 + DECL_IRQ_ENTRY 76 + DECL_IRQ_ENTRY 70 + DECL_IRQ_ENTRY 74 + DECL_IRQ_ENTRY 75 + DECL_IRQ_ENTRY hwpic1 + DECL_IRQ_ENTRY hwpic2 + + // int 18/19 are special - they reset stack and call into 32bit mode. + DECLFUNC entry_19 +entry_19: + ENTRY_INTO32 _cfunc32flat_handle_19 + + DECLFUNC entry_18 +entry_18: + ENTRY_INTO32 _cfunc32flat_handle_18 + + +/**************************************************************** + * Fixed position entry points + ****************************************************************/ + + // Specify a location in the fixed part of bios area. + .macro ORG addr + .section .fixedaddr.\addr + .endm + + ORG 0xe05b +entry_post: + cmpl $0, %cs:HaveRunPost // Check for resume/reboot + jnz entry_resume + ENTRY_INTO32 _cfunc32flat_handle_post // Normal entry point + + ORG 0xe2c3 + IRQ_ENTRY 02 + + ORG 0xe3fe + .global entry_13_official +entry_13_official: + jmp entry_13 + + // 0xe401 - OldFDPT in disk.c + + ORG 0xe6f2 + .global entry_19_official +entry_19_official: + jmp entry_19 + + // 0xe6f5 - BIOS_CONFIG_TABLE in misc.c + + // 0xe729 - BaudTable in serial.c + + ORG 0xe739 + IRQ_ENTRY_ARG 14 + + ORG 0xe82e + IRQ_ENTRY_ARG 16 + + ORG 0xe987 + IRQ_ENTRY 09 + + ORG 0xec59 + IRQ_ENTRY_ARG 40 + + ORG 0xef57 + IRQ_ENTRY 0e + + // 0xefc7 - diskette_param_table in floppy.c + + ORG 0xefd2 + IRQ_ENTRY_ARG 17 + + ORG 0xf045 +entry_10_0x0f: + // XXX - INT 10 Functions 0-Fh Entry Point + iretw + + ORG 0xf065 + IRQ_ENTRY_ARG 10 + + // 0xf0a4 - VideoParams in misc.c + + ORG 0xf841 + IRQ_ENTRY_ARG 12 + + ORG 0xf84d + IRQ_ENTRY_ARG 11 + + ORG 0xf859 + IRQ_ENTRY_ARG 15 + + // 0xfa6e - vgafont8 in font.c + + ORG 0xfe6e + IRQ_ENTRY_ARG 1a + + ORG 0xfea5 + IRQ_ENTRY 08 + + // 0xfef3 - InitVectors in misc.c + + // 0xff00 - BiosCopyright in misc.c + + ORG 0xff53 + .global entry_iret_official +entry_iret_official: + iretw + + ORG 0xff54 + IRQ_ENTRY_ARG 05 + + ORG 0xfff0 // Power-up Entry Point + .global reset_vector +reset_vector: + ljmpw $SEG_BIOS, $entry_post + + // 0xfff5 - BiosDate in misc.c + + // 0xfffe - BiosModelId in misc.c + + // 0xffff - BiosChecksum in misc.c + + .end diff --git a/bios/seabios/src/serial.c b/bios/seabios/src/serial.c new file mode 100644 index 0000000..21b4bd0 --- /dev/null +++ b/bios/seabios/src/serial.c @@ -0,0 +1,315 @@ +// 16bit code to handle serial and printer services. +// +// Copyright (C) 2008,2009 Kevin O'Connor +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "biosvar.h" // SET_BDA +#include "util.h" // debug_enter +#include "bregs.h" // struct bregs + + +/**************************************************************** + * COM ports + ****************************************************************/ + +static u16 +detect_serial(u16 port, u8 timeout, u8 count) +{ + outb(0x02, port+SEROFF_IER); + u8 ier = inb(port+SEROFF_IER); + if (ier != 0x02) + return 0; + u8 iir = inb(port+SEROFF_IIR); + if ((iir & 0x3f) != 0x02) + return 0; + + outb(0x00, port+SEROFF_IER); + SET_BDA(port_com[count], port); + SET_BDA(com_timeout[count], timeout); + return 1; +} + +void +serial_setup(void) +{ + if (! CONFIG_SERIAL) + return; + dprintf(3, "init serial\n"); + + u16 count = 0; + count += detect_serial(PORT_SERIAL1, 0x0a, count); + count += detect_serial(PORT_SERIAL2, 0x0a, count); + count += detect_serial(PORT_SERIAL3, 0x0a, count); + count += detect_serial(PORT_SERIAL4, 0x0a, count); + dprintf(1, "Found %d serial ports\n", count); + + // Equipment word bits 9..11 determing # serial ports + u16 eqb = GET_BDA(equipment_list_flags); + SET_BDA(equipment_list_flags, (eqb & 0xf1ff) | (count << 9)); +} + +static u16 +getComAddr(struct bregs *regs) +{ + if (regs->dx >= 4) { + set_invalid(regs); + return 0; + } + u16 addr = GET_BDA(port_com[regs->dx]); + if (! addr) + set_invalid(regs); + return addr; +} + +// SERIAL - INITIALIZE PORT +static void +handle_1400(struct bregs *regs) +{ + u16 addr = getComAddr(regs); + if (!addr) + return; + outb(inb(addr+SEROFF_LCR) | 0x80, addr+SEROFF_LCR); + if ((regs->al & 0xE0) == 0) { + outb(0x17, addr+SEROFF_DLL); + outb(0x04, addr+SEROFF_DLH); + } else { + u16 val16 = 0x600 >> ((regs->al & 0xE0) >> 5); + outb(val16 & 0xFF, addr+SEROFF_DLL); + outb(val16 >> 8, addr+SEROFF_DLH); + } + outb(regs->al & 0x1F, addr+SEROFF_LCR); + regs->ah = inb(addr+SEROFF_LSR); + regs->al = inb(addr+SEROFF_MSR); + set_success(regs); +} + +// SERIAL - WRITE CHARACTER TO PORT +static void +handle_1401(struct bregs *regs) +{ + u16 addr = getComAddr(regs); + if (!addr) + return; + u32 end = calc_future_timer_ticks(GET_BDA(com_timeout[regs->dx])); + for (;;) { + u8 lsr = inb(addr+SEROFF_LSR); + if ((lsr & 0x60) == 0x60) { + // Success - can write data + outb(regs->al, addr+SEROFF_DATA); + // XXX - reread lsr? + regs->ah = lsr; + break; + } + if (check_timer(end)) { + // Timed out - can't write data. + regs->ah = lsr | 0x80; + break; + } + yield(); + } + set_success(regs); +} + +// SERIAL - READ CHARACTER FROM PORT +static void +handle_1402(struct bregs *regs) +{ + u16 addr = getComAddr(regs); + if (!addr) + return; + u32 end = calc_future_timer_ticks(GET_BDA(com_timeout[regs->dx])); + for (;;) { + u8 lsr = inb(addr+SEROFF_LSR); + if (lsr & 0x01) { + // Success - can read data + regs->al = inb(addr+SEROFF_DATA); + regs->ah = lsr; + break; + } + if (check_timer(end)) { + // Timed out - can't read data. + regs->ah = lsr | 0x80; + break; + } + yield(); + } + set_success(regs); +} + +// SERIAL - GET PORT STATUS +static void +handle_1403(struct bregs *regs) +{ + u16 addr = getComAddr(regs); + if (!addr) + return; + regs->ah = inb(addr+SEROFF_LSR); + regs->al = inb(addr+SEROFF_MSR); + set_success(regs); +} + +static void +handle_14XX(struct bregs *regs) +{ + set_unimplemented(regs); +} + +// INT 14h Serial Communications Service Entry Point +void VISIBLE16 +handle_14(struct bregs *regs) +{ + debug_enter(regs, DEBUG_HDL_14); + if (! CONFIG_SERIAL) { + handle_14XX(regs); + return; + } + + switch (regs->ah) { + case 0x00: handle_1400(regs); break; + case 0x01: handle_1401(regs); break; + case 0x02: handle_1402(regs); break; + case 0x03: handle_1403(regs); break; + default: handle_14XX(regs); break; + } +} + +// XXX - Baud Rate Generator Table +u8 BaudTable[16] VAR16FIXED(0xe729); + + +/**************************************************************** + * LPT ports + ****************************************************************/ + +static u16 +detect_parport(u16 port, u8 timeout, u8 count) +{ + // clear input mode + outb(inb(port+2) & 0xdf, port+2); + + outb(0xaa, port); + if (inb(port) != 0xaa) + // Not present + return 0; + SET_BDA(port_lpt[count], port); + SET_BDA(lpt_timeout[count], timeout); + return 1; +} + +void +lpt_setup(void) +{ + if (! CONFIG_LPT) + return; + dprintf(3, "init lpt\n"); + + u16 count = 0; + count += detect_parport(PORT_LPT1, 0x14, count); + count += detect_parport(PORT_LPT2, 0x14, count); + dprintf(1, "Found %d lpt ports\n", count); + + // Equipment word bits 14..15 determing # parallel ports + u16 eqb = GET_BDA(equipment_list_flags); + SET_BDA(equipment_list_flags, (eqb & 0x3fff) | (count << 14)); +} + +static u16 +getLptAddr(struct bregs *regs) +{ + if (regs->dx >= 3) { + set_invalid(regs); + return 0; + } + u16 addr = GET_BDA(port_lpt[regs->dx]); + if (! addr) + set_invalid(regs); + return addr; +} + +// INT 17 - PRINTER - WRITE CHARACTER +static void +handle_1700(struct bregs *regs) +{ + u16 addr = getLptAddr(regs); + if (!addr) + return; + + u32 end = calc_future_timer_ticks(GET_BDA(lpt_timeout[regs->dx])); + + outb(regs->al, addr); + u8 val8 = inb(addr+2); + outb(val8 | 0x01, addr+2); // send strobe + udelay(5); + outb(val8 & ~0x01, addr+2); + + for (;;) { + u8 v = inb(addr+1); + if (!(v & 0x40)) { + // Success + regs->ah = v ^ 0x48; + break; + } + if (check_timer(end)) { + // Timeout + regs->ah = (v ^ 0x48) | 0x01; + break; + } + yield(); + } + + set_success(regs); +} + +// INT 17 - PRINTER - INITIALIZE PORT +static void +handle_1701(struct bregs *regs) +{ + u16 addr = getLptAddr(regs); + if (!addr) + return; + + u8 val8 = inb(addr+2); + outb(val8 & ~0x04, addr+2); // send init + udelay(5); + outb(val8 | 0x04, addr+2); + + regs->ah = inb(addr+1) ^ 0x48; + set_success(regs); +} + +// INT 17 - PRINTER - GET STATUS +static void +handle_1702(struct bregs *regs) +{ + u16 addr = getLptAddr(regs); + if (!addr) + return; + regs->ah = inb(addr+1) ^ 0x48; + set_success(regs); +} + +static void +handle_17XX(struct bregs *regs) +{ + set_unimplemented(regs); +} + +// INT17h : Printer Service Entry Point +void VISIBLE16 +handle_17(struct bregs *regs) +{ + debug_enter(regs, DEBUG_HDL_17); + if (! CONFIG_LPT) { + handle_17XX(regs); + return; + } + + switch (regs->ah) { + case 0x00: handle_1700(regs); break; + case 0x01: handle_1701(regs); break; + case 0x02: handle_1702(regs); break; + default: handle_17XX(regs); break; + } +} diff --git a/bios/seabios/src/shadow.c b/bios/seabios/src/shadow.c new file mode 100644 index 0000000..c0c8cc2 --- /dev/null +++ b/bios/seabios/src/shadow.c @@ -0,0 +1,158 @@ +// Support for enabling/disabling BIOS ram shadowing. +// +// Copyright (C) 2008-2010 Kevin O'Connor +// Copyright (C) 2006 Fabrice Bellard +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // memcpy +#include "pci.h" // pci_config_writeb +#include "config.h" // CONFIG_* +#include "pci_ids.h" // PCI_VENDOR_ID_INTEL +#include "pci_regs.h" // PCI_VENDOR_ID +#include "xen.h" // usingXen + +// On the emulators, the bios at 0xf0000 is also at 0xffff0000 +#define BIOS_SRC_OFFSET 0xfff00000 + +#define I440FX_PAM0 0x59 + +// Enable shadowing and copy bios. +static void +__make_bios_writable_intel(u16 bdf, u32 pam0) +{ + // Make ram from 0xc0000-0xf0000 writable + int clear = 0; + int i; + for (i=0; i<6; i++) { + u32 pam = pam0 + 1 + i; + int reg = pci_config_readb(bdf, pam); + if (CONFIG_OPTIONROMS_DEPLOYED && (reg & 0x11) != 0x11) { + // Need to copy optionroms to work around qemu implementation + void *mem = (void*)(BUILD_ROM_START + i * 32*1024); + memcpy((void*)BUILD_BIOS_TMP_ADDR, mem, 32*1024); + pci_config_writeb(bdf, pam, 0x33); + memcpy(mem, (void*)BUILD_BIOS_TMP_ADDR, 32*1024); + clear = 1; + } else { + pci_config_writeb(bdf, pam, 0x33); + } + } + if (clear) + memset((void*)BUILD_BIOS_TMP_ADDR, 0, 32*1024); + + // Make ram from 0xf0000-0x100000 writable + int reg = pci_config_readb(bdf, pam0); + pci_config_writeb(bdf, pam0, 0x30); + if (reg & 0x10) + // Ram already present. + return; + + // Copy bios. + extern u8 code32flat_start[], code32flat_end[]; + memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET + , code32flat_end - code32flat_start); +} + +static void +make_bios_writable_intel(u16 bdf, u32 pam0) +{ + int reg = pci_config_readb(bdf, pam0); + if (!(reg & 0x10)) { + // QEMU doesn't fully implement the piix shadow capabilities - + // if ram isn't backing the bios segment when shadowing is + // disabled, the code itself wont be in memory. So, run the + // code from the high-memory flash location. + u32 pos = (u32)__make_bios_writable_intel + BIOS_SRC_OFFSET; + void (*func)(u16 bdf, u32 pam0) = (void*)pos; + func(bdf, pam0); + return; + } + // Ram already present - just enable writes + __make_bios_writable_intel(bdf, pam0); +} + +static void +make_bios_readonly_intel(u16 bdf, u32 pam0) +{ + // Flush any pending writes before locking memory. + wbinvd(); + + // Write protect roms from 0xc0000-0xf0000 + int i; + for (i=0; i<6; i++) { + u32 mem = BUILD_ROM_START + i * 32*1024; + u32 pam = pam0 + 1 + i; + if (RomEnd <= mem + 16*1024) { + if (RomEnd > mem) + pci_config_writeb(bdf, pam, 0x31); + break; + } + pci_config_writeb(bdf, pam, 0x11); + } + + // Write protect 0xf0000-0x100000 + pci_config_writeb(bdf, pam0, 0x10); +} + +static void i440fx_bios_make_readonly(struct pci_device *pci, void *arg) +{ + make_bios_readonly_intel(pci->bdf, I440FX_PAM0); +} + +static const struct pci_device_id dram_controller_make_readonly_tbl[] = { + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, + i440fx_bios_make_readonly), + PCI_DEVICE_END +}; + +// Make the 0xc0000-0x100000 area read/writable. +void +make_bios_writable(void) +{ + if (CONFIG_COREBOOT || usingXen()) + return; + + dprintf(3, "enabling shadow ram\n"); + + // At this point, statically allocated variables can't be written, + // so do this search manually. + int bdf; + foreachbdf(bdf, 0) { + u32 vendev = pci_config_readl(bdf, PCI_VENDOR_ID); + u16 vendor = vendev & 0xffff, device = vendev >> 16; + if (vendor == PCI_VENDOR_ID_INTEL + && device == PCI_DEVICE_ID_INTEL_82441) { + make_bios_writable_intel(bdf, I440FX_PAM0); + return; + } + } + dprintf(1, "Unable to unlock ram - bridge not found\n"); +} + +// Make the BIOS code segment area (0xf0000) read-only. +void +make_bios_readonly(void) +{ + if (CONFIG_COREBOOT || usingXen()) + return; + + dprintf(3, "locking shadow ram\n"); + struct pci_device *pci = pci_find_init_device( + dram_controller_make_readonly_tbl, NULL); + if (!pci) + dprintf(1, "Unable to lock ram - bridge not found\n"); +} + +void +qemu_prep_reset(void) +{ + if (CONFIG_COREBOOT) + return; + // QEMU doesn't map 0xc0000-0xfffff back to the original rom on a + // reset, so do that manually before invoking a hard reset. + make_bios_writable(); + extern u8 code32flat_start[], code32flat_end[]; + memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET + , code32flat_end - code32flat_start); +} diff --git a/bios/seabios/src/smbios.c b/bios/seabios/src/smbios.c new file mode 100644 index 0000000..fe1e183 --- /dev/null +++ b/bios/seabios/src/smbios.c @@ -0,0 +1,524 @@ +// smbios table generation (on emulators) +// +// Copyright (C) 2008,2009 Kevin O'Connor +// Copyright (C) 2006 Fabrice Bellard +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // dprintf +#include "biosvar.h" // GET_EBDA +#include "paravirt.h" // qemu_cfg_smbios_load_field +#include "smbios.h" // struct smbios_entry_point + +struct smbios_entry_point *SMBiosAddr; + +static void +smbios_entry_point_init(u16 max_structure_size, + u16 structure_table_length, + void *structure_table_address, + u16 number_of_structures) +{ + struct smbios_entry_point *ep = malloc_fseg(sizeof(*ep)); + void *finaltable; + if (structure_table_length <= BUILD_MAX_SMBIOS_FSEG) + // Table is small enough for f-seg - allocate there. This + // works around a bug in JunOS (at least for small SMBIOS tables). + finaltable = malloc_fseg(structure_table_length); + else + finaltable = malloc_high(structure_table_length); + if (!ep || !finaltable) { + warn_noalloc(); + free(ep); + free(finaltable); + return; + } + memcpy(finaltable, structure_table_address, structure_table_length); + + memcpy(ep->anchor_string, "_SM_", 4); + ep->length = 0x1f; + ep->smbios_major_version = 2; + ep->smbios_minor_version = 4; + ep->max_structure_size = max_structure_size; + ep->entry_point_revision = 0; + memset(ep->formatted_area, 0, 5); + memcpy(ep->intermediate_anchor_string, "_DMI_", 5); + + ep->structure_table_length = structure_table_length; + ep->structure_table_address = (u32)finaltable; + ep->number_of_structures = number_of_structures; + ep->smbios_bcd_revision = 0x24; + + ep->checksum -= checksum(ep, 0x10); + + ep->intermediate_checksum -= checksum((void*)ep + 0x10, ep->length - 0x10); + + SMBiosAddr = ep; + dprintf(1, "SMBIOS ptr=%p table=%p size=%d\n" + , ep, finaltable, structure_table_length); +} + +#define load_str_field_with_default(type, field, def) \ + do { \ + size = qemu_cfg_smbios_load_field(type, \ + offsetof(struct smbios_type_##type, \ + field), end); \ + if (size > 0) { \ + end += size; \ + } else { \ + memcpy(end, def, sizeof(def)); \ + end += sizeof(def); \ + } \ + p->field = ++str_index; \ + } while (0) + +#define load_str_field_or_skip(type, field) \ + do { \ + size = qemu_cfg_smbios_load_field(type, \ + offsetof(struct smbios_type_##type, \ + field), end); \ + if (size > 0) { \ + end += size; \ + p->field = ++str_index; \ + } else { \ + p->field = 0; \ + } \ + } while (0) + +#define set_field_with_default(type, field, def) \ + do { \ + if (!qemu_cfg_smbios_load_field(type, \ + offsetof(struct smbios_type_##type, \ + field), &p->field)) { \ + p->field = def; \ + } \ + } while (0) + +/* Type 0 -- BIOS Information */ +#define RELEASE_DATE_STR "01/01/2007" +static void * +smbios_init_type_0(void *start) +{ + struct smbios_type_0 *p = (struct smbios_type_0 *)start; + char *end = (char *)start + sizeof(struct smbios_type_0); + size_t size; + int str_index = 0; + + p->header.type = 0; + p->header.length = sizeof(struct smbios_type_0); + p->header.handle = 0; + + load_str_field_with_default(0, vendor_str, CONFIG_APPNAME); + load_str_field_with_default(0, bios_version_str, CONFIG_APPNAME); + + p->bios_starting_address_segment = 0xe800; + + load_str_field_with_default(0, bios_release_date_str, RELEASE_DATE_STR); + + p->bios_rom_size = 0; /* FIXME */ + + if (!qemu_cfg_smbios_load_field(0, offsetof(struct smbios_type_0, + bios_characteristics), + &p->bios_characteristics)) { + memset(p->bios_characteristics, 0, 8); + /* BIOS characteristics not supported */ + p->bios_characteristics[0] = 0x08; + } + + if (!qemu_cfg_smbios_load_field(0, offsetof(struct smbios_type_0, + bios_characteristics_extension_bytes), + &p->bios_characteristics_extension_bytes)) { + p->bios_characteristics_extension_bytes[0] = 0; + /* Enable targeted content distribution. Needed for SVVP */ + p->bios_characteristics_extension_bytes[1] = 4; + } + + set_field_with_default(0, system_bios_major_release, 1); + set_field_with_default(0, system_bios_minor_release, 0); + set_field_with_default(0, embedded_controller_major_release, 0xff); + set_field_with_default(0, embedded_controller_minor_release, 0xff); + + *end = 0; + end++; + + return end; +} + +/* Type 1 -- System Information */ +static void * +smbios_init_type_1(void *start) +{ + struct smbios_type_1 *p = (struct smbios_type_1 *)start; + char *end = (char *)start + sizeof(struct smbios_type_1); + size_t size; + int str_index = 0; + + p->header.type = 1; + p->header.length = sizeof(struct smbios_type_1); + p->header.handle = 0x100; + + load_str_field_with_default(1, manufacturer_str, CONFIG_APPNAME); + load_str_field_with_default(1, product_name_str, CONFIG_APPNAME); + load_str_field_or_skip(1, version_str); + load_str_field_or_skip(1, serial_number_str); + + if (!qemu_cfg_smbios_load_field(1, offsetof(struct smbios_type_1, + uuid), &p->uuid)) { + memset(p->uuid, 0, 16); + } + + set_field_with_default(1, wake_up_type, 0x06); /* power switch */ + + load_str_field_or_skip(1, sku_number_str); + load_str_field_or_skip(1, family_str); + + *end = 0; + end++; + if (!str_index) { + *end = 0; + end++; + } + + return end; +} + +/* Type 3 -- System Enclosure */ +static void * +smbios_init_type_3(void *start) +{ + struct smbios_type_3 *p = (struct smbios_type_3 *)start; + char *end = (char *)start + sizeof(struct smbios_type_3); + size_t size; + int str_index = 0; + + p->header.type = 3; + p->header.length = sizeof(struct smbios_type_3); + p->header.handle = 0x300; + + load_str_field_with_default(3, manufacturer_str, CONFIG_APPNAME); + set_field_with_default(3, type, 0x01); /* other */ + + load_str_field_or_skip(3, version_str); + load_str_field_or_skip(3, serial_number_str); + load_str_field_or_skip(3, asset_tag_number_str); + + set_field_with_default(3, boot_up_state, 0x03); /* safe */ + set_field_with_default(3, power_supply_state, 0x03); /* safe */ + set_field_with_default(3, thermal_state, 0x03); /* safe */ + set_field_with_default(3, security_status, 0x02); /* unknown */ + + set_field_with_default(3, oem_defined, 0); + set_field_with_default(3, height, 0); + set_field_with_default(3, number_of_power_cords, 0); + set_field_with_default(3, contained_element_count, 0); + + *end = 0; + end++; + if (!str_index) { + *end = 0; + end++; + } + + return end; +} + +/* Type 4 -- Processor Information */ +static void * +smbios_init_type_4(void *start, unsigned int cpu_number) +{ + struct smbios_type_4 *p = (struct smbios_type_4 *)start; + char *end = (char *)start + sizeof(struct smbios_type_4); + size_t size; + int str_index = 0; + char name[1024]; + + p->header.type = 4; + p->header.length = sizeof(struct smbios_type_4); + p->header.handle = 0x400 + cpu_number; + + size = qemu_cfg_smbios_load_field(4, offsetof(struct smbios_type_4, + socket_designation_str), + name); + if (size) + snprintf(name + size - 1, sizeof(name) - size, "%2x", cpu_number); + else + snprintf(name, sizeof(name), "CPU%2x", cpu_number); + + memcpy(end, name, strlen(name) + 1); + end += strlen(name) + 1; + p->socket_designation_str = ++str_index; + + set_field_with_default(4, processor_type, 0x03); /* CPU */ + set_field_with_default(4, processor_family, 0x01); /* other */ + + load_str_field_with_default(4, processor_manufacturer_str, CONFIG_APPNAME); + + if (!qemu_cfg_smbios_load_field(4, offsetof(struct smbios_type_4, + processor_id), p->processor_id)) { + u32 cpuid_signature, ebx, ecx, cpuid_features; + cpuid(1, &cpuid_signature, &ebx, &ecx, &cpuid_features); + p->processor_id[0] = cpuid_signature; + p->processor_id[1] = cpuid_features; + } + + load_str_field_or_skip(4, processor_version_str); + set_field_with_default(4, voltage, 0); + set_field_with_default(4, external_clock, 0); + + set_field_with_default(4, max_speed, 2000); + set_field_with_default(4, current_speed, 2000); + + set_field_with_default(4, status, 0x41); /* socket populated, CPU enabled */ + set_field_with_default(4, processor_upgrade, 0x01); /* other */ + + /* cache information structure not provided */ + p->l1_cache_handle = 0xffff; + p->l2_cache_handle = 0xffff; + p->l3_cache_handle = 0xffff; + + *end = 0; + end++; + if (!str_index) { + *end = 0; + end++; + } + + return end; +} + +/* Type 16 -- Physical Memory Array */ +static void * +smbios_init_type_16(void *start, u32 memory_size_mb, int nr_mem_devs) +{ + struct smbios_type_16 *p = (struct smbios_type_16*)start; + + p->header.type = 16; + p->header.length = sizeof(struct smbios_type_16); + p->header.handle = 0x1000; + + set_field_with_default(16, location, 0x01); /* other */ + set_field_with_default(16, use, 0x03); /* system memory */ + /* Multi-bit ECC to make Microsoft happy */ + set_field_with_default(16, error_correction, 0x06); + /* 0x80000000 = unknown, accept sizes < 2TB - TODO multiple arrays */ + p->maximum_capacity = memory_size_mb < 2 << 20 ? + memory_size_mb << 10 : 0x80000000; + p->memory_error_information_handle = 0xfffe; /* none provided */ + p->number_of_memory_devices = nr_mem_devs; + + start += sizeof(struct smbios_type_16); + *((u16 *)start) = 0; + + return start + 2; +} + +/* Type 17 -- Memory Device */ +static void * +smbios_init_type_17(void *start, u32 size_mb, int instance) +{ + struct smbios_type_17 *p = (struct smbios_type_17 *)start; + char *end = (char *)start + sizeof(struct smbios_type_17); + size_t size; + int str_index = 0; + char name[1024]; + + p->header.type = 17; + p->header.length = sizeof(struct smbios_type_17); + p->header.handle = 0x1100 + instance; + + p->physical_memory_array_handle = 0x1000; + set_field_with_default(17, total_width, 64); + set_field_with_default(17, data_width, 64); +/* TODO: should assert in case something is wrong ASSERT((memory_size_mb & ~0x7fff) == 0); */ + p->size = size_mb; + set_field_with_default(17, form_factor, 0x09); /* DIMM */ + p->device_set = 0; + + size = qemu_cfg_smbios_load_field(17, offsetof(struct smbios_type_17, + device_locator_str), + name); + if (size) + snprintf(name + size - 1, sizeof(name) - size, "%d", instance); + else + snprintf(name, sizeof(name), "DIMM %d", instance); + + memcpy(end, name, strlen(name) + 1); + end += strlen(name) + 1; + p->device_locator_str = ++str_index; + + load_str_field_or_skip(17, bank_locator_str); + set_field_with_default(17, memory_type, 0x07); /* RAM */ + set_field_with_default(17, type_detail, 0); + + *end = 0; + end++; + if (!str_index) { + *end = 0; + end++; + } + + return end; +} + +/* Type 19 -- Memory Array Mapped Address */ +static void * +smbios_init_type_19(void *start, u32 start_mb, u32 size_mb, int instance) +{ + struct smbios_type_19 *p = (struct smbios_type_19 *)start; + + p->header.type = 19; + p->header.length = sizeof(struct smbios_type_19); + p->header.handle = 0x1300 + instance; + + p->starting_address = start_mb << 10; + p->ending_address = p->starting_address + (size_mb << 10) - 1; + p->memory_array_handle = 0x1000; + p->partition_width = 1; + + start += sizeof(struct smbios_type_19); + *((u16 *)start) = 0; + + return start + 2; +} + +/* Type 20 -- Memory Device Mapped Address */ +static void * +smbios_init_type_20(void *start, u32 start_mb, u32 size_mb, int instance, + int dev_handle, int array_handle) +{ + struct smbios_type_20 *p = (struct smbios_type_20 *)start; + + p->header.type = 20; + p->header.length = sizeof(struct smbios_type_20); + p->header.handle = 0x1400 + instance; + + p->starting_address = start_mb << 10; + p->ending_address = p->starting_address + (size_mb << 10) - 1; + p->memory_device_handle = 0x1100 + dev_handle; + p->memory_array_mapped_address_handle = 0x1300 + array_handle; + p->partition_row_position = 1; + p->interleave_position = 0; + p->interleaved_data_depth = 0; + + start += sizeof(struct smbios_type_20); + + *((u16 *)start) = 0; + return start+2; +} + +/* Type 32 -- System Boot Information */ +static void * +smbios_init_type_32(void *start) +{ + struct smbios_type_32 *p = (struct smbios_type_32 *)start; + + p->header.type = 32; + p->header.length = sizeof(struct smbios_type_32); + p->header.handle = 0x2000; + memset(p->reserved, 0, 6); + set_field_with_default(32, boot_status, 0); /* no errors detected */ + + start += sizeof(struct smbios_type_32); + *((u16 *)start) = 0; + + return start+2; +} + +/* Type 127 -- End of Table */ +static void * +smbios_init_type_127(void *start) +{ + struct smbios_type_127 *p = (struct smbios_type_127 *)start; + + p->header.type = 127; + p->header.length = sizeof(struct smbios_type_127); + p->header.handle = 0x7f00; + + start += sizeof(struct smbios_type_127); + *((u16 *)start) = 0; + + return start + 2; +} + +#define TEMPSMBIOSSIZE (32 * 1024) + +void +smbios_init(void) +{ + if (! CONFIG_SMBIOS) + return; + + dprintf(3, "init SMBIOS tables\n"); + + char *start = malloc_tmphigh(TEMPSMBIOSSIZE); + if (! start) { + warn_noalloc(); + return; + } + + u32 nr_structs = 0, max_struct_size = 0; + char *q, *p = start; + char *end = start + TEMPSMBIOSSIZE - sizeof(struct smbios_type_127); + +#define add_struct(type, args...) \ + do { \ + if (!qemu_cfg_smbios_load_external(type, &p, &nr_structs, \ + &max_struct_size, end)) { \ + q = smbios_init_type_##type(args); \ + nr_structs++; \ + if ((q - p) > max_struct_size) \ + max_struct_size = q - p; \ + p = q; \ + } \ + } while (0) + + add_struct(0, p); + add_struct(1, p); + add_struct(3, p); + + int cpu_num; + for (cpu_num = 1; cpu_num <= MaxCountCPUs; cpu_num++) + add_struct(4, p, cpu_num); + + int ram_mb = (RamSize + RamSizeOver4G) >> 20; + int nr_mem_devs = (ram_mb + 0x3fff) >> 14; + add_struct(16, p, ram_mb, nr_mem_devs); + + int i, j; + for (i = 0; i < nr_mem_devs; i++) { + u32 dev_mb = ((i == (nr_mem_devs - 1)) + ? (((ram_mb - 1) & 0x3fff) + 1) + : 16384); + add_struct(17, p, dev_mb, i); + } + + add_struct(19, p, 0, RamSize >> 20, 0); + if (RamSizeOver4G) + add_struct(19, p, 4096, RamSizeOver4G >> 20, 1); + + add_struct(20, p, 0, RamSize >> 20, 0, 0, 0); + if (RamSizeOver4G) { + u32 start_mb = 4096; + for (j = 1, i = 0; i < nr_mem_devs; i++, j++) { + u32 dev_mb = ((i == (nr_mem_devs - 1)) + ? (((ram_mb - 1) & 0x3fff) + 1) + : 16384); + if (i == 0) + dev_mb -= RamSize >> 20; + + add_struct(20, p, start_mb, dev_mb, j, i, 1); + start_mb += dev_mb; + } + } + + add_struct(32, p); + /* Add any remaining provided entries before the end marker */ + for (i = 0; i < 256; i++) + qemu_cfg_smbios_load_external(i, &p, &nr_structs, &max_struct_size, + end); + add_struct(127, p); + +#undef add_struct + + smbios_entry_point_init(max_struct_size, p - start, start, nr_structs); + free(start); +} diff --git a/bios/seabios/src/smbios.h b/bios/seabios/src/smbios.h new file mode 100644 index 0000000..9d54e80 --- /dev/null +++ b/bios/seabios/src/smbios.h @@ -0,0 +1,168 @@ +#ifndef __SMBIOS_H +#define __SMBIOS_H + +// smbios.c +void smbios_init(void); + +/* SMBIOS entry point -- must be written to a 16-bit aligned address + between 0xf0000 and 0xfffff. + */ +struct smbios_entry_point { + char anchor_string[4]; + u8 checksum; + u8 length; + u8 smbios_major_version; + u8 smbios_minor_version; + u16 max_structure_size; + u8 entry_point_revision; + u8 formatted_area[5]; + char intermediate_anchor_string[5]; + u8 intermediate_checksum; + u16 structure_table_length; + u32 structure_table_address; + u16 number_of_structures; + u8 smbios_bcd_revision; +} PACKED; + +extern struct smbios_entry_point *SMBiosAddr; + +/* This goes at the beginning of every SMBIOS structure. */ +struct smbios_structure_header { + u8 type; + u8 length; + u16 handle; +} PACKED; + +/* SMBIOS type 0 - BIOS Information */ +struct smbios_type_0 { + struct smbios_structure_header header; + u8 vendor_str; + u8 bios_version_str; + u16 bios_starting_address_segment; + u8 bios_release_date_str; + u8 bios_rom_size; + u8 bios_characteristics[8]; + u8 bios_characteristics_extension_bytes[2]; + u8 system_bios_major_release; + u8 system_bios_minor_release; + u8 embedded_controller_major_release; + u8 embedded_controller_minor_release; +} PACKED; + +/* SMBIOS type 1 - System Information */ +struct smbios_type_1 { + struct smbios_structure_header header; + u8 manufacturer_str; + u8 product_name_str; + u8 version_str; + u8 serial_number_str; + u8 uuid[16]; + u8 wake_up_type; + u8 sku_number_str; + u8 family_str; +} PACKED; + +/* SMBIOS type 3 - System Enclosure (v2.3) */ +struct smbios_type_3 { + struct smbios_structure_header header; + u8 manufacturer_str; + u8 type; + u8 version_str; + u8 serial_number_str; + u8 asset_tag_number_str; + u8 boot_up_state; + u8 power_supply_state; + u8 thermal_state; + u8 security_status; + u32 oem_defined; + u8 height; + u8 number_of_power_cords; + u8 contained_element_count; + // contained elements follow +} PACKED; + +/* SMBIOS type 4 - Processor Information (v2.0) */ +struct smbios_type_4 { + struct smbios_structure_header header; + u8 socket_designation_str; + u8 processor_type; + u8 processor_family; + u8 processor_manufacturer_str; + u32 processor_id[2]; + u8 processor_version_str; + u8 voltage; + u16 external_clock; + u16 max_speed; + u16 current_speed; + u8 status; + u8 processor_upgrade; + u16 l1_cache_handle; + u16 l2_cache_handle; + u16 l3_cache_handle; +} PACKED; + +/* SMBIOS type 16 - Physical Memory Array + * Associated with one type 17 (Memory Device). + */ +struct smbios_type_16 { + struct smbios_structure_header header; + u8 location; + u8 use; + u8 error_correction; + u32 maximum_capacity; + u16 memory_error_information_handle; + u16 number_of_memory_devices; +} PACKED; + +/* SMBIOS type 17 - Memory Device + * Associated with one type 19 + */ +struct smbios_type_17 { + struct smbios_structure_header header; + u16 physical_memory_array_handle; + u16 memory_error_information_handle; + u16 total_width; + u16 data_width; + u16 size; + u8 form_factor; + u8 device_set; + u8 device_locator_str; + u8 bank_locator_str; + u8 memory_type; + u16 type_detail; +} PACKED; + +/* SMBIOS type 19 - Memory Array Mapped Address */ +struct smbios_type_19 { + struct smbios_structure_header header; + u32 starting_address; + u32 ending_address; + u16 memory_array_handle; + u8 partition_width; +} PACKED; + +/* SMBIOS type 20 - Memory Device Mapped Address */ +struct smbios_type_20 { + struct smbios_structure_header header; + u32 starting_address; + u32 ending_address; + u16 memory_device_handle; + u16 memory_array_mapped_address_handle; + u8 partition_row_position; + u8 interleave_position; + u8 interleaved_data_depth; +} PACKED; + +/* SMBIOS type 32 - System Boot Information */ +struct smbios_type_32 { + struct smbios_structure_header header; + u8 reserved[6]; + u8 boot_status; +} PACKED; + +/* SMBIOS type 127 -- End-of-table */ +struct smbios_type_127 { + struct smbios_structure_header header; +} PACKED; + +#endif // smbios.h diff --git a/bios/seabios/src/smm.c b/bios/seabios/src/smm.c new file mode 100644 index 0000000..72e5e88 --- /dev/null +++ b/bios/seabios/src/smm.c @@ -0,0 +1,157 @@ +// System Management Mode support (on emulators) +// +// Copyright (C) 2008 Kevin O'Connor +// Copyright (C) 2006 Fabrice Bellard +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "pci.h" // pci_config_writel +#include "util.h" // wbinvd +#include "config.h" // CONFIG_* +#include "ioport.h" // outb +#include "pci_ids.h" // PCI_VENDOR_ID_INTEL + +ASM32FLAT( + ".global smm_relocation_start\n" + ".global smm_relocation_end\n" + ".global smm_code_start\n" + ".global smm_code_end\n" + " .code16\n" + + /* code to relocate SMBASE to 0xa0000 */ + "smm_relocation_start:\n" + " mov $" __stringify(BUILD_SMM_INIT_ADDR) " + 0x7efc, %ebx\n" + " addr32 mov (%ebx), %al\n" /* revision ID to see if x86_64 or x86 */ + " cmp $0x64, %al\n" + " je 1f\n" + " mov $" __stringify(BUILD_SMM_INIT_ADDR) " + 0x7ef8, %ebx\n" + " jmp 2f\n" + "1:\n" + " mov $" __stringify(BUILD_SMM_INIT_ADDR) " + 0x7f00, %ebx\n" + "2:\n" + " movl $" __stringify(BUILD_SMM_ADDR) " - 0x8000, %eax\n" + " addr32 movl %eax, (%ebx)\n" + /* indicate to the BIOS that the SMM code was executed */ + " mov $0x00, %al\n" + " movw $" __stringify(PORT_SMI_STATUS) ", %dx\n" + " outb %al, %dx\n" + " rsm\n" + "smm_relocation_end:\n" + + /* minimal SMM code to enable or disable ACPI */ + "smm_code_start:\n" + " movw $" __stringify(PORT_SMI_CMD) ", %dx\n" + " inb %dx, %al\n" + " cmp $0xf0, %al\n" + " jne 1f\n" + + /* ACPI disable */ + " mov $" __stringify(PORT_ACPI_PM_BASE) " + 0x04, %dx\n" /* PMCNTRL */ + " inw %dx, %ax\n" + " andw $~1, %ax\n" + " outw %ax, %dx\n" + + " jmp 2f\n" + + "1:\n" + " cmp $0xf1, %al\n" + " jne 2f\n" + + /* ACPI enable */ + " mov $" __stringify(PORT_ACPI_PM_BASE) " + 0x04, %dx\n" /* PMCNTRL */ + " inw %dx, %ax\n" + " orw $1, %ax\n" + " outw %ax, %dx\n" + + "2:\n" + " rsm\n" + "smm_code_end:\n" + " .code32\n" + ); + +extern u8 smm_relocation_start, smm_relocation_end; +extern u8 smm_code_start, smm_code_end; + +static void +smm_save_and_copy(void) +{ + /* save original memory content */ + memcpy((void *)BUILD_SMM_ADDR, (void *)BUILD_SMM_INIT_ADDR, BUILD_SMM_SIZE); + + /* copy the SMM relocation code */ + memcpy((void *)BUILD_SMM_INIT_ADDR, &smm_relocation_start, + &smm_relocation_end - &smm_relocation_start); +} + +static void +smm_relocate_and_restore(void) +{ + /* init APM status port */ + outb(0x01, PORT_SMI_STATUS); + + /* raise an SMI interrupt */ + outb(0x00, PORT_SMI_CMD); + + /* wait until SMM code executed */ + while (inb(PORT_SMI_STATUS) != 0x00) + ; + + /* restore original memory content */ + memcpy((void *)BUILD_SMM_INIT_ADDR, (void *)BUILD_SMM_ADDR, BUILD_SMM_SIZE); + + /* copy the SMM code */ + memcpy((void *)BUILD_SMM_ADDR, &smm_code_start + , &smm_code_end - &smm_code_start); + wbinvd(); +} + +#define I440FX_SMRAM 0x72 +#define PIIX_DEVACTB 0x58 +#define PIIX_APMC_EN (1 << 25) + +// This code is hardcoded for PIIX4 Power Management device. +static void piix4_apmc_smm_init(struct pci_device *pci, void *arg) +{ + struct pci_device *i440_pci = pci_find_device(PCI_VENDOR_ID_INTEL + , PCI_DEVICE_ID_INTEL_82441); + if (!i440_pci) + return; + + /* check if SMM init is already done */ + u32 value = pci_config_readl(pci->bdf, PIIX_DEVACTB); + if (value & PIIX_APMC_EN) + return; + + /* enable the SMM memory window */ + pci_config_writeb(i440_pci->bdf, I440FX_SMRAM, 0x02 | 0x48); + + smm_save_and_copy(); + + /* enable SMI generation when writing to the APMC register */ + pci_config_writel(pci->bdf, PIIX_DEVACTB, value | PIIX_APMC_EN); + + smm_relocate_and_restore(); + + /* close the SMM memory window and enable normal SMM */ + pci_config_writeb(i440_pci->bdf, I440FX_SMRAM, 0x02 | 0x08); +} + +static const struct pci_device_id smm_init_tbl[] = { + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, + piix4_apmc_smm_init), + + PCI_DEVICE_END, +}; + +void +smm_init(void) +{ + if (CONFIG_COREBOOT) + // SMM only supported on emulators. + return; + if (!CONFIG_USE_SMM) + return; + + dprintf(3, "init smm\n"); + pci_find_init_device(smm_init_tbl, NULL); +} diff --git a/bios/seabios/src/smp.c b/bios/seabios/src/smp.c new file mode 100644 index 0000000..8c077a1 --- /dev/null +++ b/bios/seabios/src/smp.c @@ -0,0 +1,131 @@ +// CPU count detection +// +// Copyright (C) 2008 Kevin O'Connor +// Copyright (C) 2006 Fabrice Bellard +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // dprintf +#include "config.h" // CONFIG_* +#include "cmos.h" // CMOS_BIOS_SMP_COUNT +#include "paravirt.h" + +#define APIC_ICR_LOW ((u8*)BUILD_APIC_ADDR + 0x300) +#define APIC_SVR ((u8*)BUILD_APIC_ADDR + 0x0F0) +#define APIC_LINT0 ((u8*)BUILD_APIC_ADDR + 0x350) +#define APIC_LINT1 ((u8*)BUILD_APIC_ADDR + 0x360) + +#define APIC_ENABLED 0x0100 + +struct { u32 ecx, eax, edx; } smp_mtrr[32] VAR16VISIBLE; +u32 smp_mtrr_count VAR16VISIBLE; + +void +wrmsr_smp(u32 index, u64 val) +{ + wrmsr(index, val); + if (smp_mtrr_count >= ARRAY_SIZE(smp_mtrr)) { + warn_noalloc(); + return; + } + smp_mtrr[smp_mtrr_count].ecx = index; + smp_mtrr[smp_mtrr_count].eax = val; + smp_mtrr[smp_mtrr_count].edx = val >> 32; + smp_mtrr_count++; +} + +u32 CountCPUs VAR16VISIBLE; +u32 MaxCountCPUs VAR16VISIBLE; +extern void smp_ap_boot_code(void); +ASM16( + " .global smp_ap_boot_code\n" + "smp_ap_boot_code:\n" + + // Setup data segment + " movw $" __stringify(SEG_BIOS) ", %ax\n" + " movw %ax, %ds\n" + + // MTRR setup + " movl $smp_mtrr, %esi\n" + " movl smp_mtrr_count, %ebx\n" + "1:testl %ebx, %ebx\n" + " jz 2f\n" + " movl 0(%esi), %ecx\n" + " movl 4(%esi), %eax\n" + " movl 8(%esi), %edx\n" + " wrmsr\n" + " addl $12, %esi\n" + " decl %ebx\n" + " jmp 1b\n" + "2:\n" + + // Increment the cpu counter + " lock incl CountCPUs\n" + + // Halt the processor. + "1:hlt\n" + " jmp 1b\n" + ); + +// find and initialize the CPUs by launching a SIPI to them +void +smp_probe(void) +{ + ASSERT32FLAT(); + u32 eax, ebx, ecx, cpuid_features; + cpuid(1, &eax, &ebx, &ecx, &cpuid_features); + if (eax < 1 || !(cpuid_features & CPUID_APIC)) { + // No apic - only the main cpu is present. + dprintf(1, "No apic - only the main cpu is present.\n"); + CountCPUs= 1; + MaxCountCPUs = 1; + return; + } + + // Init the counter. + writel(&CountCPUs, 1); + + // Setup jump trampoline to counter code. + u64 old = *(u64*)BUILD_AP_BOOT_ADDR; + // ljmpw $SEG_BIOS, $(smp_ap_boot_code - BUILD_BIOS_ADDR) + u64 new = (0xea | ((u64)SEG_BIOS<<24) + | (((u32)smp_ap_boot_code - BUILD_BIOS_ADDR) << 8)); + *(u64*)BUILD_AP_BOOT_ADDR = new; + + // enable local APIC + u32 val = readl(APIC_SVR); + writel(APIC_SVR, val | APIC_ENABLED); + + if (! CONFIG_COREBOOT) { + /* Set LINT0 as Ext_INT, level triggered */ + writel(APIC_LINT0, 0x8700); + + /* Set LINT1 as NMI, level triggered */ + writel(APIC_LINT1, 0x8400); + } + + // broadcast SIPI + barrier(); + writel(APIC_ICR_LOW, 0x000C4500); + u32 sipi_vector = BUILD_AP_BOOT_ADDR >> 12; + writel(APIC_ICR_LOW, 0x000C4600 | sipi_vector); + + // Wait for other CPUs to process the SIPI. + if (CONFIG_COREBOOT) { + msleep(10); + } else { + u8 cmos_smp_count = inb_cmos(CMOS_BIOS_SMP_COUNT); + while (cmos_smp_count + 1 != readl(&CountCPUs)) + yield(); + } + + // Restore memory. + *(u64*)BUILD_AP_BOOT_ADDR = old; + + MaxCountCPUs = qemu_cfg_get_max_cpus(); + if (!MaxCountCPUs || MaxCountCPUs < CountCPUs) + MaxCountCPUs = CountCPUs; + + dprintf(1, "Found %d cpu(s) max supported %d cpu(s)\n", readl(&CountCPUs), + MaxCountCPUs); +} diff --git a/bios/seabios/src/ssdt-proc.dsl b/bios/seabios/src/ssdt-proc.dsl new file mode 100644 index 0000000..358afa8 --- /dev/null +++ b/bios/seabios/src/ssdt-proc.dsl @@ -0,0 +1,50 @@ +/* This file is the basis for the ssdt_proc[] variable in src/acpi.c. + * It defines the contents of the per-cpu Processor() object. At + * runtime, a dynamically generated SSDT will contain one copy of this + * AML snippet for every possible cpu in the system. The objects will + * be placed in the \_SB_ namespace. + * + * To generate a new ssdt_proc[], run the commands: + * cpp -P src/ssdt-proc.dsl > out/ssdt-proc.dsl.i + * iasl -ta -p out/ssdt-proc out/ssdt-proc.dsl.i + * tail -c +37 < out/ssdt-proc.aml | hexdump -e '" " 8/1 "0x%02x," "\n"' + * and then cut-and-paste the output into the src/acpi.c ssdt_proc[] + * array. + * + * In addition to the aml code generated from this file, the + * src/acpi.c file creates a NTFY method with an entry for each cpu: + * Method(NTFY, 2) { + * If (LEqual(Arg0, 0x00)) { Notify(CP00, Arg1) } + * If (LEqual(Arg0, 0x01)) { Notify(CP01, Arg1) } + * ... + * } + * and a CPON array with the list of active and inactive cpus: + * Name(CPON, Package() { One, One, ..., Zero, Zero, ... }) + */ +DefinitionBlock ("ssdt-proc.aml", "SSDT", 0x01, "BXPC", "BXSSDT", 0x1) +/* v------------------ DO NOT EDIT ------------------v */ +{ + Processor (CPAA, 0xAA, 0x0000b010, 0x06) { + Name (ID, 0xAA) +/* ^------------------ DO NOT EDIT ------------------^ + * + * The src/acpi.c code requires the above layout so that it can update + * CPAA and 0xAA with the appropriate CPU id (see + * SD_OFFSET_CPUHEX/CPUID1/CPUID2). Don't change the above without + * also updating the C code. + */ + Name (_HID, "ACPI0007") + External(CPMA, MethodObj) + External(CPST, MethodObj) + External(CPEJ, MethodObj) + Method(_MAT, 0) { + Return(CPMA(ID)) + } + Method (_STA, 0) { + Return(CPST(ID)) + } + Method (_EJ0, 1, NotSerialized) { + CPEJ(ID, Arg0) + } + } +} diff --git a/bios/seabios/src/stacks.c b/bios/seabios/src/stacks.c new file mode 100644 index 0000000..17f1a4a --- /dev/null +++ b/bios/seabios/src/stacks.c @@ -0,0 +1,390 @@ +// Code for manipulating stack locations. +// +// Copyright (C) 2009-2010 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "biosvar.h" // get_ebda_seg +#include "util.h" // dprintf +#include "bregs.h" // CR0_PE + +// Thread info - stored at bottom of each thread stack - don't change +// without also updating the inline assembler below. +struct thread_info { + struct thread_info *next; + void *stackpos; + struct thread_info **pprev; +}; +struct thread_info VAR32FLATVISIBLE MainThread = { + &MainThread, NULL, &MainThread.next +}; + + +/**************************************************************** + * Low level helpers + ****************************************************************/ + +static inline void sgdt(struct descloc_s *desc) { + asm("sgdtl %0" : "=m"(*desc)); +} +static inline void lgdt(struct descloc_s *desc) { + asm("lgdtl %0" : : "m"(*desc) : "memory"); +} + +// Call a 32bit SeaBIOS function from a 16bit SeaBIOS function. +u32 VISIBLE16 +call32(void *func, u32 eax, u32 errret) +{ + ASSERT16(); + u32 cr0 = getcr0(); + if (cr0 & CR0_PE) + // Called in 16bit protected mode?! + return errret; + + // Backup cmos index register and disable nmi + u8 cmosindex = inb(PORT_CMOS_INDEX); + outb(cmosindex | NMI_DISABLE_BIT, PORT_CMOS_INDEX); + inb(PORT_CMOS_DATA); + + // Backup fs/gs and gdt + u16 fs = GET_SEG(FS), gs = GET_SEG(GS); + struct descloc_s gdt; + sgdt(&gdt); + + u32 bkup_ss, bkup_esp; + asm volatile( + // Backup ss/esp / set esp to flat stack location + " movl %%ss, %0\n" + " movl %%esp, %1\n" + " shll $4, %0\n" + " addl %0, %%esp\n" + " shrl $4, %0\n" + + // Transition to 32bit mode, call func, return to 16bit + " movl $(" __stringify(BUILD_BIOS_ADDR) " + 1f), %%edx\n" + " jmp transition32\n" + " .code32\n" + "1:calll *%3\n" + " movl $2f, %%edx\n" + " jmp transition16big\n" + + // Restore ds/ss/esp + " .code16gcc\n" + "2:movl %0, %%ds\n" + " movl %0, %%ss\n" + " movl %1, %%esp\n" + : "=&r" (bkup_ss), "=&r" (bkup_esp), "+a" (eax) + : "r" (func) + : "ecx", "edx", "cc", "memory"); + + // Restore gdt and fs/gs + lgdt(&gdt); + SET_SEG(FS, fs); + SET_SEG(GS, gs); + + // Restore cmos index register + outb(cmosindex, PORT_CMOS_INDEX); + inb(PORT_CMOS_DATA); + return eax; +} + +// 16bit trampoline for enabling irqs from 32bit mode. +ASM16( + " .global trampoline_checkirqs\n" + "trampoline_checkirqs:\n" + " rep ; nop\n" + " lretw" + ); + +static void +check_irqs(void) +{ + if (MODESEGMENT) { + asm volatile( + "sti\n" + "nop\n" + "rep ; nop\n" + "cli\n" + "cld\n" + : : :"memory"); + return; + } + extern void trampoline_checkirqs(); + struct bregs br; + br.flags = F_IF; + br.code.seg = SEG_BIOS; + br.code.offset = (u32)&trampoline_checkirqs; + call16big(&br); +} + +// 16bit trampoline for waiting for an irq from 32bit mode. +ASM16( + " .global trampoline_waitirq\n" + "trampoline_waitirq:\n" + " sti\n" + " hlt\n" + " lretw" + ); + +// Wait for next irq to occur. +void +wait_irq(void) +{ + if (MODESEGMENT) { + asm volatile("sti ; hlt ; cli ; cld": : :"memory"); + return; + } + if (CONFIG_THREADS && MainThread.next != &MainThread) { + // Threads still active - do a yield instead. + yield(); + return; + } + extern void trampoline_waitirq(); + struct bregs br; + br.flags = 0; + br.code.seg = SEG_BIOS; + br.code.offset = (u32)&trampoline_waitirq; + call16big(&br); +} + + +/**************************************************************** + * Stack in EBDA + ****************************************************************/ + +// Switch to the extra stack in ebda and call a function. +inline u32 +stack_hop(u32 eax, u32 edx, void *func) +{ + ASSERT16(); + u16 ebda_seg = get_ebda_seg(), bkup_ss; + u32 bkup_esp; + asm volatile( + // Backup current %ss/%esp values. + "movw %%ss, %w3\n" + "movl %%esp, %4\n" + // Copy ebda seg to %ds/%ss and set %esp + "movw %w6, %%ds\n" + "movw %w6, %%ss\n" + "movl %5, %%esp\n" + // Call func + "calll *%2\n" + // Restore segments and stack + "movw %w3, %%ds\n" + "movw %w3, %%ss\n" + "movl %4, %%esp" + : "+a" (eax), "+d" (edx), "+c" (func), "=&r" (bkup_ss), "=&r" (bkup_esp) + : "i" (EBDA_OFFSET_TOP_STACK), "r" (ebda_seg) + : "cc", "memory"); + return eax; +} + + +/**************************************************************** + * Threads + ****************************************************************/ + +#define THREADSTACKSIZE 4096 +int VAR16VISIBLE CanPreempt; + +// Return the 'struct thread_info' for the currently running thread. +struct thread_info * +getCurThread(void) +{ + u32 esp = getesp(); + if (esp <= BUILD_STACK_ADDR) + return &MainThread; + return (void*)ALIGN_DOWN(esp, THREADSTACKSIZE); +} + +// Switch to next thread stack. +static void +switch_next(struct thread_info *cur) +{ + struct thread_info *next = cur->next; + if (cur == next) + // Nothing to do. + return; + asm volatile( + " pushl $1f\n" // store return pc + " pushl %%ebp\n" // backup %ebp + " movl %%esp, 4(%%eax)\n" // cur->stackpos = %esp + " movl 4(%%ecx), %%esp\n" // %esp = next->stackpos + " popl %%ebp\n" // restore %ebp + " retl\n" // restore pc + "1:\n" + : "+a"(cur), "+c"(next) + : + : "ebx", "edx", "esi", "edi", "cc", "memory"); +} + +// Briefly permit irqs to occur. +void +yield(void) +{ + if (MODESEGMENT || !CONFIG_THREADS) { + // Just directly check irqs. + check_irqs(); + return; + } + struct thread_info *cur = getCurThread(); + if (cur == &MainThread) + // Permit irqs to fire + check_irqs(); + + // Switch to the next thread + switch_next(cur); +} + +// Last thing called from a thread (called on "next" stack). +static void +__end_thread(struct thread_info *old) +{ + old->next->pprev = old->pprev; + *old->pprev = old->next; + free(old); + dprintf(DEBUG_thread, "\\%08x/ End thread\n", (u32)old); + if (MainThread.next == &MainThread) + dprintf(1, "All threads complete.\n"); +} + +// Create a new thread and start executing 'func' in it. +void +run_thread(void (*func)(void*), void *data) +{ + ASSERT32FLAT(); + if (! CONFIG_THREADS) + goto fail; + struct thread_info *thread; + thread = memalign_tmphigh(THREADSTACKSIZE, THREADSTACKSIZE); + if (!thread) + goto fail; + + thread->stackpos = (void*)thread + THREADSTACKSIZE; + struct thread_info *cur = getCurThread(); + thread->next = cur; + thread->pprev = cur->pprev; + cur->pprev = &thread->next; + *thread->pprev = thread; + + dprintf(DEBUG_thread, "/%08x\\ Start thread\n", (u32)thread); + asm volatile( + // Start thread + " pushl $1f\n" // store return pc + " pushl %%ebp\n" // backup %ebp + " movl %%esp, 4(%%edx)\n" // cur->stackpos = %esp + " movl 4(%%ebx), %%esp\n" // %esp = thread->stackpos + " calll *%%ecx\n" // Call func + + // End thread + " movl (%%ebx), %%ecx\n" // %ecx = thread->next + " movl 4(%%ecx), %%esp\n" // %esp = next->stackpos + " movl %%ebx, %%eax\n" + " calll %4\n" // call __end_thread(thread) + " popl %%ebp\n" // restore %ebp + " retl\n" // restore pc + "1:\n" + : "+a"(data), "+c"(func), "+b"(thread), "+d"(cur) + : "m"(*(u8*)__end_thread) + : "esi", "edi", "cc", "memory"); + return; + +fail: + func(data); +} + +// Wait for all threads (other than the main thread) to complete. +void +wait_threads(void) +{ + ASSERT32FLAT(); + if (! CONFIG_THREADS) + return; + while (MainThread.next != &MainThread) + yield(); +} + +void +mutex_lock(struct mutex_s *mutex) +{ + ASSERT32FLAT(); + if (! CONFIG_THREADS) + return; + while (mutex->isLocked) + yield(); + mutex->isLocked = 1; +} + +void +mutex_unlock(struct mutex_s *mutex) +{ + ASSERT32FLAT(); + if (! CONFIG_THREADS) + return; + mutex->isLocked = 0; +} + + +/**************************************************************** + * Thread preemption + ****************************************************************/ + +static u32 PreemptCount; + +// Turn on RTC irqs and arrange for them to check the 32bit threads. +void +start_preempt(void) +{ + if (! CONFIG_THREADS || ! CONFIG_THREAD_OPTIONROMS) + return; + CanPreempt = 1; + PreemptCount = 0; + useRTC(); +} + +// Turn off RTC irqs / stop checking for thread execution. +void +finish_preempt(void) +{ + if (! CONFIG_THREADS || ! CONFIG_THREAD_OPTIONROMS) { + yield(); + return; + } + CanPreempt = 0; + releaseRTC(); + dprintf(9, "Done preempt - %d checks\n", PreemptCount); + yield(); +} + +// Check if preemption is on, and wait for it to complete if so. +int +wait_preempt(void) +{ + if (MODESEGMENT || !CONFIG_THREADS || !CONFIG_THREAD_OPTIONROMS + || !CanPreempt) + return 0; + while (CanPreempt) + yield(); + return 1; +} + +// Try to execute 32bit threads. +void VISIBLE32INIT +yield_preempt(void) +{ + PreemptCount++; + switch_next(&MainThread); +} + +// 16bit code that checks if threads are pending and executes them if so. +void +check_preempt(void) +{ + if (! CONFIG_THREADS || ! CONFIG_THREAD_OPTIONROMS + || !GET_GLOBAL(CanPreempt) + || GET_FLATPTR(MainThread.next) == &MainThread) + return; + + extern void _cfunc32flat_yield_preempt(void); + call32(_cfunc32flat_yield_preempt, 0, 0); +} diff --git a/bios/seabios/src/system.c b/bios/seabios/src/system.c new file mode 100644 index 0000000..898c3cc --- /dev/null +++ b/bios/seabios/src/system.c @@ -0,0 +1,365 @@ +// Handler for int 0x15 "system" calls +// +// Copyright (C) 2008 Kevin O'Connor +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // memcpy_far +#include "biosvar.h" // BIOS_CONFIG_TABLE +#include "ioport.h" // inb +#include "memmap.h" // E820_RAM +#include "pic.h" // eoi_pic2 +#include "bregs.h" // struct bregs + +// 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 | A20_ENABLE_BIT; + else + newval = oldval & ~A20_ENABLE_BIT; + outb(newval, PORT_A20); + + return (oldval & A20_ENABLE_BIT) != 0; +} + +static void +handle_152400(struct bregs *regs) +{ + set_a20(0); + set_code_success(regs); +} + +static void +handle_152401(struct bregs *regs) +{ + set_a20(1); + set_code_success(regs); +} + +static void +handle_152402(struct bregs *regs) +{ + regs->al = (inb(PORT_A20) & A20_ENABLE_BIT) != 0; + set_code_success(regs); +} + +static void +handle_152403(struct bregs *regs) +{ + regs->bx = 3; + set_code_success(regs); +} + +static void +handle_1524XX(struct bregs *regs) +{ + set_code_unimplemented(regs, RET_EUNSUPPORTED); +} + +static void +handle_1524(struct bregs *regs) +{ + 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; + } +} + +// removable media eject +static void +handle_1552(struct bregs *regs) +{ + set_code_success(regs); +} + +static void +handle_1587(struct bregs *regs) +{ + // +++ should probably have descriptor checks + // +++ should have exception handlers + + 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 + +// check for access rights of source & dest here + + // Initialize GDT descriptor + u32 si = regs->si; + u64 *gdt_far = (void*)si; + u16 gdt_seg = regs->es; + u32 loc = (u32)MAKE_FLATPTR(gdt_seg, gdt_far); + SET_FARVAR(gdt_seg, gdt_far[1], GDT_DATA | GDT_LIMIT((6*sizeof(u64))-1) + | GDT_BASE(loc)); + // Initialize CS descriptor + SET_FARVAR(gdt_seg, gdt_far[4], GDT_CODE | GDT_LIMIT(BUILD_BIOS_SIZE-1) + | GDT_BASE(BUILD_BIOS_ADDR)); + // Initialize SS descriptor + loc = (u32)MAKE_FLATPTR(GET_SEG(SS), 0); + SET_FARVAR(gdt_seg, gdt_far[5], GDT_DATA | GDT_LIMIT(0x0ffff) + | GDT_BASE(loc)); + + u16 count = regs->cx; + asm volatile( + // Load new descriptor tables + " lgdtw %%es:(1<<3)(%%si)\n" + " lidtw %%cs:pmode_IDT_info\n" + + // Enable protected mode + " movl %%cr0, %%eax\n" + " orl $" __stringify(CR0_PE) ", %%eax\n" + " movl %%eax, %%cr0\n" + + // far jump to flush CPU queue after transition to protected mode + " ljmpw $(4<<3), $1f\n" + + // GDT points to valid descriptor table, now load DS, ES + "1:movw $(2<<3), %%ax\n" // 2nd descriptor in table, TI=GDT, RPL=00 + " movw %%ax, %%ds\n" + " movw $(3<<3), %%ax\n" // 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" + " rep movsw\n" + + // Restore DS and ES segment limits to 0xffff + " movw $(5<<3), %%ax\n" // 5th descriptor in table (SS) + " movw %%ax, %%ds\n" + " movw %%ax, %%es\n" + + // Disable protected mode + " movl %%cr0, %%eax\n" + " andl $~" __stringify(CR0_PE) ", %%eax\n" + " movl %%eax, %%cr0\n" + + // far jump to flush CPU queue after transition to real mode + " ljmpw $" __stringify(SEG_BIOS) ", $2f\n" + + // restore IDT to normal real-mode defaults + "2:lidtw %%cs:rmode_IDT_info\n" + + // Restore %ds (from %ss) + " movw %%ss, %%ax\n" + " movw %%ax, %%ds\n" + : "+c"(count), "+S"(si) + : : "eax", "di", "cc"); // XXX - also clobbers %es + + set_a20(prev_a20_enable); + + set_code_success(regs); +} + +// Get the amount of extended memory (above 1M) +static void +handle_1588(struct bregs *regs) +{ + u32 rs = GET_GLOBAL(RamSize); + + // According to Ralf Brown's interrupt the limit should be 15M, + // but real machines mostly return max. 63M. + if (rs > 64*1024*1024) + regs->ax = 63 * 1024; + else + regs->ax = (rs - 1*1024*1024) / 1024; + set_success(regs); +} + +// Switch to protected mode +static void +handle_1589(struct bregs *regs) +{ + set_a20(1); + + set_pics(regs->bl, regs->bh); + + u64 *gdt_far = (void*)(regs->si + 0); + u16 gdt_seg = regs->es; + SET_FARVAR(gdt_seg, gdt_far[7], GDT_CODE | GDT_LIMIT(BUILD_BIOS_SIZE-1) + | GDT_BASE(BUILD_BIOS_ADDR)); + + regs->ds = 3<<3; // 3rd gdt descriptor is %ds + regs->es = 4<<3; // 4th gdt descriptor is %es + regs->code.seg = 6<<3; // 6th gdt descriptor is %cs + + set_code_success(regs); + + asm volatile( + // Load new descriptor tables + " lgdtw %%es:(1<<3)(%%si)\n" + " lidtw %%es:(2<<3)(%%si)\n" + + // Enable protected mode + " movl %%cr0, %%eax\n" + " orl $" __stringify(CR0_PE) ", %%eax\n" + " movl %%eax, %%cr0\n" + + // far jump to flush CPU queue after transition to protected mode + " ljmpw $(7<<3), $1f\n" + + // GDT points to valid descriptor table, now load SS + "1:movw $(5<<3), %%ax\n" + " movw %%ax, %%ds\n" + " movw %%ax, %%ss\n" + : + : "S"(gdt_far) + : "eax", "cc"); +} + +// 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) +{ +} + +// keyboard intercept +static void +handle_154f(struct bregs *regs) +{ + set_invalid_silent(regs); +} + +static void +handle_15c0(struct bregs *regs) +{ + regs->es = SEG_BIOS; + regs->bx = (u32)&BIOS_CONFIG_TABLE; + set_code_success(regs); +} + +static void +handle_15c1(struct bregs *regs) +{ + regs->es = get_ebda_seg(); + set_success(regs); +} + +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; + + u32 rs = GET_GLOBAL(RamSize); + + // Get the amount of extended memory (above 1M) + if (rs > 16*1024*1024) { + // limit to 15M + regs->cx = 15*1024; + // Get the amount of extended memory above 16M in 64k blocks + regs->dx = (rs - 16*1024*1024) / (64*1024); + } else { + regs->cx = (rs - 1*1024*1024) / 1024; + regs->dx = 0; + } + + // Set configured memory equal to extended memory + regs->ax = regs->cx; + regs->bx = regs->dx; + + set_success(regs); +} + +// Info on e820 map location and size. +struct e820entry e820_list[CONFIG_MAX_E820] VAR16VISIBLE; +int e820_count VAR16VISIBLE; + +static void +handle_15e820(struct bregs *regs) +{ + int count = GET_GLOBAL(e820_count); + if (regs->edx != 0x534D4150 || regs->bx >= count + || regs->ecx < sizeof(e820_list[0])) { + set_code_invalid(regs, RET_EUNSUPPORTED); + return; + } + + memcpy_far(regs->es, (void*)(regs->di+0) + , get_global_seg(), &e820_list[regs->bx] + , sizeof(e820_list[0])); + if (regs->bx == count-1) + regs->ebx = 0; + else + regs->ebx++; + regs->eax = 0x534D4150; + regs->ecx = sizeof(e820_list[0]); + set_success(regs); +} + +static void +handle_15e8XX(struct bregs *regs) +{ + set_code_unimplemented(regs, RET_EUNSUPPORTED); +} + +static void +handle_15e8(struct bregs *regs) +{ + switch (regs->al) { + case 0x01: handle_15e801(regs); break; + case 0x20: handle_15e820(regs); break; + default: handle_15e8XX(regs); break; + } +} + +static void +handle_15XX(struct bregs *regs) +{ + set_code_unimplemented(regs, RET_EUNSUPPORTED); +} + +// INT 15h System Services Entry Point +void VISIBLE16 +handle_15(struct bregs *regs) +{ + debug_enter(regs, DEBUG_HDL_15); + switch (regs->ah) { + case 0x24: handle_1524(regs); break; + case 0x4f: handle_154f(regs); break; + case 0x52: handle_1552(regs); break; + case 0x53: handle_1553(regs); break; + case 0x5f: handle_155f(regs); break; + case 0x83: handle_1583(regs); break; + case 0x86: handle_1586(regs); break; + case 0x87: handle_1587(regs); break; + case 0x88: handle_1588(regs); break; + case 0x89: handle_1589(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: handle_15e8(regs); break; + default: handle_15XX(regs); break; + } +} diff --git a/bios/seabios/src/types.h b/bios/seabios/src/types.h new file mode 100644 index 0000000..c0c6d26 --- /dev/null +++ b/bios/seabios/src/types.h @@ -0,0 +1,142 @@ +// Basic type definitions for X86 cpus. +// +// Copyright (C) 2008-2010 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 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 unsigned long long u64; +typedef signed long long s64; +typedef u32 size_t; + +union u64_u32_u { + struct { u32 hi, lo; }; + u64 val; +}; + +#ifdef MANUAL_NO_JUMP_TABLE +# define default case 775324556: asm(""); default +#endif + +#ifdef WHOLE_PROGRAM +# define __VISIBLE __attribute__((externally_visible)) +#else +# define __VISIBLE +#endif + +#define UNIQSEC __FILE__ "." __stringify(__LINE__) + +#define __noreturn __attribute__((noreturn)) +extern void __force_link_error__only_in_32bit_flat(void) __noreturn; +extern void __force_link_error__only_in_32bit_segmented(void) __noreturn; +extern void __force_link_error__only_in_16bit(void) __noreturn; + +#define __ASM(code) asm(".section .text.asm." UNIQSEC "\n\t" code) + +#if MODE16 == 1 +// Notes a function as externally visible in the 16bit code chunk. +# define VISIBLE16 __VISIBLE +// Notes a function as externally visible in the 32bit flat code chunk. +# define VISIBLE32FLAT __section(".discard.func32flat." UNIQSEC) noinline +// Notes a 32bit flat function that will only be called during init. +# define VISIBLE32INIT VISIBLE32FLAT +// Notes a function as externally visible in the 32bit segmented code chunk. +# define VISIBLE32SEG __section(".discard.func32seg." UNIQSEC) noinline +// Designate a variable as (only) visible to 16bit code. +# define VAR16 __section(".data16." UNIQSEC) +// Designate a variable as visible to 16bit, 32bit, and assembler code. +# define VAR16VISIBLE VAR16 __VISIBLE +// Designate a variable as externally visible (in addition to all internal code). +# define VAR16EXPORT __section(".data16.export." UNIQSEC) __VISIBLE +// Designate a variable at a specific 16bit address +# define VAR16FIXED(addr) __aligned(1) __VISIBLE __section(".fixedaddr." __stringify(addr)) +// Designate a variable as (only) visible to 32bit segmented code. +# define VAR32SEG __section(".discard.var32seg." UNIQSEC) +// Designate a 32bit variable also available in 16bit "big real" mode. +# define VAR32FLATVISIBLE __section(".discard.var32flat." UNIQSEC) __VISIBLE __weak +// Designate top-level assembler as 16bit only. +# define ASM16(code) __ASM(code) +// Designate top-level assembler as 32bit flat only. +# define ASM32FLAT(code) +// Compile time check for a given mode. +# define ASSERT16() do { } while (0) +# define ASSERT32SEG() __force_link_error__only_in_32bit_segmented() +# define ASSERT32FLAT() __force_link_error__only_in_32bit_flat() +#elif MODESEGMENT == 1 +# define VISIBLE16 __section(".discard.func16." UNIQSEC) noinline +# define VISIBLE32FLAT __section(".discard.func32flat." UNIQSEC) noinline +# define VISIBLE32INIT VISIBLE32FLAT +# define VISIBLE32SEG __VISIBLE +# define VAR16 __section(".discard.var16." UNIQSEC) +# define VAR16VISIBLE VAR16 __VISIBLE __weak +# define VAR16EXPORT VAR16VISIBLE +# define VAR16FIXED(addr) VAR16VISIBLE +# define VAR32SEG __section(".data32seg." UNIQSEC) +# define VAR32FLATVISIBLE __section(".discard.var32flat." UNIQSEC) __VISIBLE __weak +# define ASM16(code) +# define ASM32FLAT(code) +# define ASSERT16() __force_link_error__only_in_16bit() +# define ASSERT32SEG() do { } while (0) +# define ASSERT32FLAT() __force_link_error__only_in_32bit_flat() +#else +# define VISIBLE16 __section(".discard.func16." UNIQSEC) noinline +# define VISIBLE32FLAT __section(".text.runtime." UNIQSEC) __VISIBLE +# define VISIBLE32INIT __section(".text.init." UNIQSEC) __VISIBLE +# define VISIBLE32SEG __section(".discard.func32seg." UNIQSEC) noinline +# define VAR16 __section(".discard.var16." UNIQSEC) +# define VAR16VISIBLE VAR16 __VISIBLE __weak +# define VAR16EXPORT VAR16VISIBLE +# define VAR16FIXED(addr) VAR16VISIBLE +# define VAR32SEG __section(".discard.var32seg." UNIQSEC) +# define VAR32FLATVISIBLE __section(".data.runtime." UNIQSEC) __VISIBLE +# define ASM16(code) +# define ASM32FLAT(code) __ASM(code) +# define ASSERT16() __force_link_error__only_in_16bit() +# define ASSERT32SEG() __force_link_error__only_in_32bit_segmented() +# define ASSERT32FLAT() do { } while (0) +#endif + +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) +#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) +#define DIV_ROUND_CLOSEST(x, divisor)({ \ + typeof(divisor) __divisor = divisor; \ + (((x) + ((__divisor) / 2)) / (__divisor)); \ + }) +#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1) +#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) +#define ALIGN_DOWN(x,a) ((x) & ~((typeof(x))(a)-1)) +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + +#define NULL ((void*)0) + +#define __weak __attribute__((weak)) +#define __section(S) __attribute__((section(S))) + +#define PACKED __attribute__((packed)) +#define __aligned(x) __attribute__((aligned(x))) + +#define barrier() __asm__ __volatile__("": : :"memory") + +#define noinline __attribute__((noinline)) +#define __always_inline inline __attribute__((always_inline)) +#define __malloc __attribute__((__malloc__)) +#define __attribute_const __attribute__((__const__)) + +#define __stringify_1(x) #x +#define __stringify(x) __stringify_1(x) + +#endif // types.h diff --git a/bios/seabios/src/usb-ehci.c b/bios/seabios/src/usb-ehci.c new file mode 100644 index 0000000..a60c607 --- /dev/null +++ b/bios/seabios/src/usb-ehci.c @@ -0,0 +1,758 @@ +// Code for handling EHCI USB controllers. +// +// Copyright (C) 2010 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // dprintf +#include "pci.h" // pci_bdf_to_bus +#include "config.h" // CONFIG_* +#include "ioport.h" // outw +#include "usb-ehci.h" // struct ehci_qh +#include "pci_ids.h" // PCI_CLASS_SERIAL_USB_UHCI +#include "pci_regs.h" // PCI_BASE_ADDRESS_0 +#include "usb.h" // struct usb_s +#include "farptr.h" // GET_FLATPTR +#include "usb-uhci.h" // init_uhci +#include "usb-ohci.h" // init_ohci + +struct usb_ehci_s { + struct usb_s usb; + struct ehci_caps *caps; + struct ehci_regs *regs; + struct ehci_qh *async_qh; + struct pci_device *companion[8]; + int checkports; + int legacycount; +}; + + +/**************************************************************** + * Root hub + ****************************************************************/ + +#define EHCI_TIME_POSTPOWER 20 +#define EHCI_TIME_POSTRESET 2 + +// Check if need companion controllers for full/low speed devices +static void +ehci_note_port(struct usb_ehci_s *cntl) +{ + if (--cntl->checkports) + // Ports still being detected. + return; + if (! cntl->legacycount) + // No full/low speed devices found. + return; + // Start companion controllers. + int i; + for (i=0; icompanion); i++) { + struct pci_device *pci = cntl->companion[i]; + if (!pci) + break; + + // ohci/uhci_init call pci_config_XXX - don't run from irq handler. + wait_preempt(); + + if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_UHCI) + uhci_init(pci, cntl->usb.busid + i); + else if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_OHCI) + ohci_init(pci, cntl->usb.busid + i); + } +} + +// Check if device attached to port +static int +ehci_hub_detect(struct usbhub_s *hub, u32 port) +{ + struct usb_ehci_s *cntl = container_of(hub->cntl, struct usb_ehci_s, usb); + u32 *portreg = &cntl->regs->portsc[port]; + u32 portsc = readl(portreg); + + // Power up port. + if (!(portsc & PORT_POWER)) { + portsc |= PORT_POWER; + writel(portreg, portsc); + msleep(EHCI_TIME_POSTPOWER); + } else { + msleep(1); // XXX - time for connect to be detected. + } + portsc = readl(portreg); + + if (!(portsc & PORT_CONNECT)) + // No device present + goto doneearly; + + if ((portsc & PORT_LINESTATUS_MASK) == PORT_LINESTATUS_KSTATE) { + // low speed device + cntl->legacycount++; + writel(portreg, portsc | PORT_OWNER); + goto doneearly; + } + + // XXX - if just powered up, need to wait for USB_TIME_ATTDB? + + // Begin reset on port + portsc = (portsc & ~PORT_PE) | PORT_RESET; + writel(portreg, portsc); + msleep(USB_TIME_DRSTR); + return 0; + +doneearly: + ehci_note_port(cntl); + return -1; +} + +// Reset device on port +static int +ehci_hub_reset(struct usbhub_s *hub, u32 port) +{ + struct usb_ehci_s *cntl = container_of(hub->cntl, struct usb_ehci_s, usb); + u32 *portreg = &cntl->regs->portsc[port]; + u32 portsc = readl(portreg); + + // Finish reset on port + portsc &= ~PORT_RESET; + writel(portreg, portsc); + msleep(EHCI_TIME_POSTRESET); + + int rv = -1; + portsc = readl(portreg); + if (!(portsc & PORT_CONNECT)) + // No longer connected + goto resetfail; + if (!(portsc & PORT_PE)) { + // full speed device + cntl->legacycount++; + writel(portreg, portsc | PORT_OWNER); + goto resetfail; + } + + rv = USB_HIGHSPEED; +resetfail: + ehci_note_port(cntl); + return rv; +} + +// Disable port +static void +ehci_hub_disconnect(struct usbhub_s *hub, u32 port) +{ + struct usb_ehci_s *cntl = container_of(hub->cntl, struct usb_ehci_s, usb); + u32 *portreg = &cntl->regs->portsc[port]; + u32 portsc = readl(portreg); + writel(portreg, portsc & ~PORT_PE); +} + +static struct usbhub_op_s ehci_HubOp = { + .detect = ehci_hub_detect, + .reset = ehci_hub_reset, + .disconnect = ehci_hub_disconnect, +}; + +// Find any devices connected to the root hub. +static int +check_ehci_ports(struct usb_ehci_s *cntl) +{ + ASSERT32FLAT(); + struct usbhub_s hub; + memset(&hub, 0, sizeof(hub)); + hub.cntl = &cntl->usb; + hub.portcount = cntl->checkports; + hub.op = &ehci_HubOp; + usb_enumerate(&hub); + return hub.devcount; +} + + +/**************************************************************** + * Setup + ****************************************************************/ + +static void +configure_ehci(void *data) +{ + struct usb_ehci_s *cntl = data; + + // Allocate ram for schedule storage + struct ehci_framelist *fl = memalign_high(sizeof(*fl), sizeof(*fl)); + struct ehci_qh *intr_qh = memalign_high(EHCI_QH_ALIGN, sizeof(*intr_qh)); + struct ehci_qh *async_qh = memalign_high(EHCI_QH_ALIGN, sizeof(*async_qh)); + if (!fl || !intr_qh || !async_qh) { + warn_noalloc(); + goto fail; + } + + // XXX - check for halted? + + // Reset the HC + u32 cmd = readl(&cntl->regs->usbcmd); + writel(&cntl->regs->usbcmd, (cmd & ~(CMD_ASE | CMD_PSE)) | CMD_HCRESET); + u64 end = calc_future_tsc(250); + for (;;) { + cmd = readl(&cntl->regs->usbcmd); + if (!(cmd & CMD_HCRESET)) + break; + if (check_tsc(end)) { + warn_timeout(); + goto fail; + } + yield(); + } + + // Disable interrupts (just to be safe). + writel(&cntl->regs->usbintr, 0); + + // Set schedule to point to primary intr queue head + memset(intr_qh, 0, sizeof(*intr_qh)); + intr_qh->next = EHCI_PTR_TERM; + intr_qh->info2 = (0x01 << QH_SMASK_SHIFT); + intr_qh->token = QTD_STS_HALT; + intr_qh->qtd_next = intr_qh->alt_next = EHCI_PTR_TERM; + int i; + for (i=0; ilinks); i++) + fl->links[i] = (u32)intr_qh | EHCI_PTR_QH; + writel(&cntl->regs->periodiclistbase, (u32)fl); + + // Set async list to point to primary async queue head + memset(async_qh, 0, sizeof(*async_qh)); + async_qh->next = (u32)async_qh | EHCI_PTR_QH; + async_qh->info1 = QH_HEAD; + async_qh->token = QTD_STS_HALT; + async_qh->qtd_next = async_qh->alt_next = EHCI_PTR_TERM; + cntl->async_qh = async_qh; + writel(&cntl->regs->asynclistbase, (u32)async_qh); + + // Enable queues + writel(&cntl->regs->usbcmd, cmd | CMD_ASE | CMD_PSE | CMD_RUN); + + // Set default of high speed for root hub. + writel(&cntl->regs->configflag, 1); + cntl->checkports = readl(&cntl->caps->hcsparams) & HCS_N_PORTS_MASK; + + // Find devices + int count = check_ehci_ports(cntl); + free_pipe(cntl->usb.defaultpipe); + if (count) + // Success + return; + + // No devices found - shutdown and free controller. + writel(&cntl->regs->usbcmd, cmd & ~CMD_RUN); + msleep(4); // 2ms to stop reading memory - XXX +fail: + free(fl); + free(intr_qh); + free(async_qh); + free(cntl); +} + +int +ehci_init(struct pci_device *pci, int busid, struct pci_device *comppci) +{ + if (! CONFIG_USB_EHCI) + return -1; + + u16 bdf = pci->bdf; + u32 baseaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0); + struct ehci_caps *caps = (void*)(baseaddr & PCI_BASE_ADDRESS_MEM_MASK); + u32 hcc_params = readl(&caps->hccparams); + if (hcc_params & HCC_64BIT_ADDR) { + dprintf(1, "No support for 64bit EHCI\n"); + return -1; + } + + struct usb_ehci_s *cntl = malloc_tmphigh(sizeof(*cntl)); + if (!cntl) { + warn_noalloc(); + return -1; + } + memset(cntl, 0, sizeof(*cntl)); + cntl->usb.busid = busid; + cntl->usb.pci = pci; + cntl->usb.type = USB_TYPE_EHCI; + cntl->caps = caps; + cntl->regs = (void*)caps + readb(&caps->caplength); + + dprintf(1, "EHCI init on dev %02x:%02x.%x (regs=%p)\n" + , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf) + , pci_bdf_to_fn(bdf), cntl->regs); + + pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER); + + // XXX - check for and disable SMM control? + + // Find companion controllers. + int count = 0; + for (;;) { + if (!comppci || comppci == pci) + break; + if (pci_classprog(comppci) == PCI_CLASS_SERIAL_USB_UHCI) + cntl->companion[count++] = comppci; + else if (pci_classprog(comppci) == PCI_CLASS_SERIAL_USB_OHCI) + cntl->companion[count++] = comppci; + comppci = comppci->next; + } + + run_thread(configure_ehci, cntl); + return 0; +} + + +/**************************************************************** + * End point communication + ****************************************************************/ + +static int +ehci_wait_qh(struct usb_ehci_s *cntl, struct ehci_qh *qh) +{ + // XXX - 500ms just a guess + u64 end = calc_future_tsc(500); + for (;;) { + if (qh->qtd_next & EHCI_PTR_TERM) + // XXX - confirm + return 0; + if (check_tsc(end)) { + warn_timeout(); + return -1; + } + yield(); + } +} + +// Wait for next USB async frame to start - for ensuring safe memory release. +static void +ehci_waittick(struct usb_ehci_s *cntl) +{ + if (MODE16) { + msleep(10); + return; + } + // Wait for access to "doorbell" + barrier(); + u32 cmd, sts; + u64 end = calc_future_tsc(100); + for (;;) { + sts = readl(&cntl->regs->usbsts); + if (!(sts & STS_IAA)) { + cmd = readl(&cntl->regs->usbcmd); + if (!(cmd & CMD_IAAD)) + break; + } + if (check_tsc(end)) { + warn_timeout(); + return; + } + yield(); + } + // Ring "doorbell" + writel(&cntl->regs->usbcmd, cmd | CMD_IAAD); + // Wait for completion + for (;;) { + sts = readl(&cntl->regs->usbsts); + if (sts & STS_IAA) + break; + if (check_tsc(end)) { + warn_timeout(); + return; + } + yield(); + } + // Ack completion + writel(&cntl->regs->usbsts, STS_IAA); +} + +struct ehci_pipe { + struct ehci_qh qh; + struct ehci_qtd *next_td, *tds; + void *data; + struct usb_pipe pipe; +}; + +void +ehci_free_pipe(struct usb_pipe *p) +{ + if (! CONFIG_USB_EHCI) + return; + dprintf(7, "ehci_free_pipe %p\n", p); + struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe); + struct usb_ehci_s *cntl = container_of( + pipe->pipe.cntl, struct usb_ehci_s, usb); + + struct ehci_qh *start = cntl->async_qh; + struct ehci_qh *pos = start; + for (;;) { + struct ehci_qh *next = (void*)(pos->next & ~EHCI_PTR_BITS); + if (next == start) { + // Not found?! Exit without freeing. + warn_internalerror(); + return; + } + if (next == &pipe->qh) { + pos->next = next->next; + ehci_waittick(cntl); + free(pipe); + return; + } + pos = next; + } +} + +struct usb_pipe * +ehci_alloc_control_pipe(struct usb_pipe *dummy) +{ + if (! CONFIG_USB_EHCI) + return NULL; + struct usb_ehci_s *cntl = container_of( + dummy->cntl, struct usb_ehci_s, usb); + dprintf(7, "ehci_alloc_control_pipe %p\n", &cntl->usb); + + // Allocate a queue head. + struct ehci_pipe *pipe = memalign_tmphigh(EHCI_QH_ALIGN, sizeof(*pipe)); + if (!pipe) { + warn_noalloc(); + return NULL; + } + memset(pipe, 0, sizeof(*pipe)); + memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe)); + pipe->qh.qtd_next = pipe->qh.alt_next = EHCI_PTR_TERM; + pipe->qh.token = QTD_STS_HALT; + + // Add queue head to controller list. + struct ehci_qh *async_qh = cntl->async_qh; + pipe->qh.next = async_qh->next; + barrier(); + async_qh->next = (u32)&pipe->qh | EHCI_PTR_QH; + return &pipe->pipe; +} + +static int +fillTDbuffer(struct ehci_qtd *td, u16 maxpacket, const void *buf, int bytes) +{ + u32 dest = (u32)buf; + u32 *pos = td->buf; + while (bytes) { + if (pos >= &td->buf[ARRAY_SIZE(td->buf)]) + // More data than can transfer in a single qtd - only use + // full packets to prevent a babble error. + return ALIGN_DOWN(dest - (u32)buf, maxpacket); + u32 count = bytes; + u32 max = 0x1000 - (dest & 0xfff); + if (count > max) + count = max; + *pos = dest; + bytes -= count; + dest += count; + pos++; + } + return dest - (u32)buf; +} + +int +ehci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize + , void *data, int datasize) +{ + ASSERT32FLAT(); + if (! CONFIG_USB_EHCI) + return -1; + dprintf(5, "ehci_control %p\n", p); + if (datasize > 4*4096 || cmdsize > 4*4096) { + // XXX - should support larger sizes. + warn_noalloc(); + return -1; + } + struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe); + struct usb_ehci_s *cntl = container_of( + pipe->pipe.cntl, struct usb_ehci_s, usb); + + u16 maxpacket = pipe->pipe.maxpacket; + int speed = pipe->pipe.speed; + + // Setup fields in qh + pipe->qh.info1 = ( + (1 << QH_MULT_SHIFT) | (speed != USB_HIGHSPEED ? QH_CONTROL : 0) + | (maxpacket << QH_MAXPACKET_SHIFT) + | QH_TOGGLECONTROL + | (speed << QH_SPEED_SHIFT) + | (pipe->pipe.ep << QH_EP_SHIFT) + | (pipe->pipe.devaddr << QH_DEVADDR_SHIFT)); + pipe->qh.info2 = ((1 << QH_MULT_SHIFT) + | (pipe->pipe.tt_port << QH_HUBPORT_SHIFT) + | (pipe->pipe.tt_devaddr << QH_HUBADDR_SHIFT)); + + // Setup transfer descriptors + struct ehci_qtd *tds = memalign_tmphigh(EHCI_QTD_ALIGN, sizeof(*tds) * 3); + if (!tds) { + warn_noalloc(); + return -1; + } + memset(tds, 0, sizeof(*tds) * 3); + struct ehci_qtd *td = tds; + + td->qtd_next = (u32)&td[1]; + td->alt_next = EHCI_PTR_TERM; + td->token = (ehci_explen(cmdsize) | QTD_STS_ACTIVE + | QTD_PID_SETUP | ehci_maxerr(3)); + fillTDbuffer(td, maxpacket, cmd, cmdsize); + td++; + + if (datasize) { + td->qtd_next = (u32)&td[1]; + td->alt_next = EHCI_PTR_TERM; + td->token = (QTD_TOGGLE | ehci_explen(datasize) | QTD_STS_ACTIVE + | (dir ? QTD_PID_IN : QTD_PID_OUT) | ehci_maxerr(3)); + fillTDbuffer(td, maxpacket, data, datasize); + td++; + } + + td->qtd_next = EHCI_PTR_TERM; + td->alt_next = EHCI_PTR_TERM; + td->token = (QTD_TOGGLE | QTD_STS_ACTIVE + | (dir ? QTD_PID_OUT : QTD_PID_IN) | ehci_maxerr(3)); + + // Transfer data + barrier(); + pipe->qh.qtd_next = (u32)tds; + barrier(); + pipe->qh.token = 0; + int ret = ehci_wait_qh(cntl, &pipe->qh); + pipe->qh.token = QTD_STS_HALT; + if (ret) { + pipe->qh.qtd_next = pipe->qh.alt_next = EHCI_PTR_TERM; + // XXX - halt qh? + ehci_waittick(cntl); + } + free(tds); + return ret; +} + +struct usb_pipe * +ehci_alloc_bulk_pipe(struct usb_pipe *dummy) +{ + // XXX - this func is same as alloc_control except for malloc_low + if (! CONFIG_USB_EHCI) + return NULL; + struct usb_ehci_s *cntl = container_of( + dummy->cntl, struct usb_ehci_s, usb); + dprintf(7, "ehci_alloc_bulk_pipe %p\n", &cntl->usb); + + // Allocate a queue head. + struct ehci_pipe *pipe = memalign_low(EHCI_QH_ALIGN, sizeof(*pipe)); + if (!pipe) { + warn_noalloc(); + return NULL; + } + memset(pipe, 0, sizeof(*pipe)); + memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe)); + pipe->qh.qtd_next = pipe->qh.alt_next = EHCI_PTR_TERM; + pipe->qh.token = QTD_STS_HALT; + + // Add queue head to controller list. + struct ehci_qh *async_qh = cntl->async_qh; + pipe->qh.next = async_qh->next; + barrier(); + async_qh->next = (u32)&pipe->qh | EHCI_PTR_QH; + return &pipe->pipe; +} + +static int +ehci_wait_td(struct ehci_qtd *td) +{ + u64 end = calc_future_tsc(5000); // XXX - lookup real time. + u32 status; + for (;;) { + status = td->token; + if (!(status & QTD_STS_ACTIVE)) + break; + if (check_tsc(end)) { + warn_timeout(); + return -1; + } + yield(); + } + if (status & QTD_STS_HALT) { + dprintf(1, "ehci_wait_td error - status=%x\n", status); + return -2; + } + return 0; +} + +#define STACKQTDS 4 + +int +ehci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize) +{ + if (! CONFIG_USB_EHCI) + return -1; + struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe); + dprintf(7, "ehci_send_bulk qh=%p dir=%d data=%p size=%d\n" + , &pipe->qh, dir, data, datasize); + + // Allocate 4 tds on stack (16byte aligned) + u8 tdsbuf[sizeof(struct ehci_qtd) * STACKQTDS + EHCI_QTD_ALIGN - 1]; + struct ehci_qtd *tds = (void*)ALIGN((u32)tdsbuf, EHCI_QTD_ALIGN); + memset(tds, 0, sizeof(*tds) * STACKQTDS); + + // Setup fields in qh + u16 maxpacket = GET_FLATPTR(pipe->pipe.maxpacket); + SET_FLATPTR(pipe->qh.info1 + , ((1 << QH_MULT_SHIFT) + | (maxpacket << QH_MAXPACKET_SHIFT) + | (GET_FLATPTR(pipe->pipe.speed) << QH_SPEED_SHIFT) + | (GET_FLATPTR(pipe->pipe.ep) << QH_EP_SHIFT) + | (GET_FLATPTR(pipe->pipe.devaddr) << QH_DEVADDR_SHIFT))); + SET_FLATPTR(pipe->qh.info2 + , ((1 << QH_MULT_SHIFT) + | (GET_FLATPTR(pipe->pipe.tt_port) << QH_HUBPORT_SHIFT) + | (GET_FLATPTR(pipe->pipe.tt_devaddr) << QH_HUBADDR_SHIFT))); + barrier(); + SET_FLATPTR(pipe->qh.qtd_next, (u32)MAKE_FLATPTR(GET_SEG(SS), tds)); + barrier(); + SET_FLATPTR(pipe->qh.token, GET_FLATPTR(pipe->qh.token) & QTD_TOGGLE); + + int tdpos = 0; + while (datasize) { + struct ehci_qtd *td = &tds[tdpos++ % STACKQTDS]; + int ret = ehci_wait_td(td); + if (ret) + goto fail; + + struct ehci_qtd *nexttd_fl = MAKE_FLATPTR(GET_SEG(SS) + , &tds[tdpos % STACKQTDS]); + + int transfer = fillTDbuffer(td, maxpacket, data, datasize); + td->qtd_next = (transfer==datasize ? EHCI_PTR_TERM : (u32)nexttd_fl); + td->alt_next = EHCI_PTR_TERM; + barrier(); + td->token = (ehci_explen(transfer) | QTD_STS_ACTIVE + | (dir ? QTD_PID_IN : QTD_PID_OUT) | ehci_maxerr(3)); + + data += transfer; + datasize -= transfer; + } + int i; + for (i=0; iqh.qtd_next, EHCI_PTR_TERM); + SET_FLATPTR(pipe->qh.alt_next, EHCI_PTR_TERM); + // XXX - halt qh? + struct usb_ehci_s *cntl = container_of( + GET_FLATPTR(pipe->pipe.cntl), struct usb_ehci_s, usb); + ehci_waittick(cntl); + return -1; +} + +struct usb_pipe * +ehci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp) +{ + if (! CONFIG_USB_EHCI) + return NULL; + struct usb_ehci_s *cntl = container_of( + dummy->cntl, struct usb_ehci_s, usb); + dprintf(7, "ehci_alloc_intr_pipe %p %d\n", &cntl->usb, frameexp); + + if (frameexp > 10) + frameexp = 10; + int maxpacket = dummy->maxpacket; + // Determine number of entries needed for 2 timer ticks. + int ms = 1<pipe, dummy, sizeof(pipe->pipe)); + pipe->next_td = pipe->tds = tds; + pipe->data = data; + + pipe->qh.info1 = ( + (1 << QH_MULT_SHIFT) + | (maxpacket << QH_MAXPACKET_SHIFT) + | (pipe->pipe.speed << QH_SPEED_SHIFT) + | (pipe->pipe.ep << QH_EP_SHIFT) + | (pipe->pipe.devaddr << QH_DEVADDR_SHIFT)); + pipe->qh.info2 = ((1 << QH_MULT_SHIFT) + | (pipe->pipe.tt_port << QH_HUBPORT_SHIFT) + | (pipe->pipe.tt_devaddr << QH_HUBADDR_SHIFT) + | (0x01 << QH_SMASK_SHIFT) + | (0x1c << QH_CMASK_SHIFT)); + pipe->qh.qtd_next = (u32)tds; + + int i; + for (i=0; iqtd_next = (i==count-1 ? (u32)tds : (u32)&td[1]); + td->alt_next = EHCI_PTR_TERM; + td->token = (ehci_explen(maxpacket) | QTD_STS_ACTIVE + | QTD_PID_IN | ehci_maxerr(3)); + td->buf[0] = (u32)data + maxpacket * i; + } + + // Add to interrupt schedule. + struct ehci_framelist *fl = (void*)readl(&cntl->regs->periodiclistbase); + if (frameexp == 0) { + // Add to existing interrupt entry. + struct ehci_qh *intr_qh = (void*)(fl->links[0] & ~EHCI_PTR_BITS); + pipe->qh.next = intr_qh->next; + barrier(); + intr_qh->next = (u32)&pipe->qh | EHCI_PTR_QH; + } else { + int startpos = 1<<(frameexp-1); + pipe->qh.next = fl->links[startpos]; + barrier(); + for (i=startpos; ilinks); i+=ms) + fl->links[i] = (u32)&pipe->qh | EHCI_PTR_QH; + } + + return &pipe->pipe; +fail: + free(pipe); + free(tds); + free(data); + return NULL; +} + +int +ehci_poll_intr(struct usb_pipe *p, void *data) +{ + ASSERT16(); + if (! CONFIG_USB_EHCI) + return -1; + struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe); + struct ehci_qtd *td = GET_FLATPTR(pipe->next_td); + u32 token = GET_FLATPTR(td->token); + if (token & QTD_STS_ACTIVE) + // No intrs found. + return -1; + // XXX - check for errors. + + // Copy data. + int maxpacket = GET_FLATPTR(pipe->pipe.maxpacket); + int pos = td - GET_FLATPTR(pipe->tds); + void *tddata = GET_FLATPTR(pipe->data) + maxpacket * pos; + memcpy_far(GET_SEG(SS), data + , FLATPTR_TO_SEG(tddata), (void*)FLATPTR_TO_OFFSET(tddata) + , maxpacket); + + // Reenable this td. + struct ehci_qtd *next = (void*)(GET_FLATPTR(td->qtd_next) & ~EHCI_PTR_BITS); + SET_FLATPTR(pipe->next_td, next); + SET_FLATPTR(td->buf[0], (u32)tddata); + barrier(); + SET_FLATPTR(td->token, (ehci_explen(maxpacket) | QTD_STS_ACTIVE + | QTD_PID_IN | ehci_maxerr(3))); + + return 0; +} diff --git a/bios/seabios/src/usb-ehci.h b/bios/seabios/src/usb-ehci.h new file mode 100644 index 0000000..1a2c6c7 --- /dev/null +++ b/bios/seabios/src/usb-ehci.h @@ -0,0 +1,173 @@ +#ifndef __USB_EHCI_H +#define __USB_EHCI_H + +// usb-ehci.c +int ehci_init(struct pci_device *pci, int busid, struct pci_device *comppci); +struct usb_pipe; +void ehci_free_pipe(struct usb_pipe *p); +struct usb_pipe *ehci_alloc_control_pipe(struct usb_pipe *dummy); +int ehci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize + , void *data, int datasize); +struct usb_pipe *ehci_alloc_bulk_pipe(struct usb_pipe *dummy); +int ehci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize); +struct usb_pipe *ehci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp); +int ehci_poll_intr(struct usb_pipe *p, void *data); + + +/**************************************************************** + * ehci structs and flags + ****************************************************************/ + +struct ehci_caps { + u8 caplength; + u8 reserved_01; + u16 hciversion; + u32 hcsparams; + u32 hccparams; + u64 portroute; +} PACKED; + +#define HCC_64BIT_ADDR 1 + +#define HCS_N_PORTS_MASK 0xf + +struct ehci_regs { + u32 usbcmd; + u32 usbsts; + u32 usbintr; + u32 frindex; + u32 ctrldssegment; + u32 periodiclistbase; + u32 asynclistbase; + u32 reserved[9]; + u32 configflag; + u32 portsc[0]; +} PACKED; + +#define CMD_PARK (1<<11) +#define CMD_PARK_CNT(c) (((c)>>8)&3) +#define CMD_LRESET (1<<7) +#define CMD_IAAD (1<<6) +#define CMD_ASE (1<<5) +#define CMD_PSE (1<<4) +#define CMD_HCRESET (1<<1) +#define CMD_RUN (1<<0) + +#define STS_ASS (1<<15) +#define STS_PSS (1<<14) +#define STS_RECL (1<<13) +#define STS_HALT (1<<12) +#define STS_IAA (1<<5) +#define STS_FATAL (1<<4) +#define STS_FLR (1<<3) +#define STS_PCD (1<<2) +#define STS_ERR (1<<1) +#define STS_INT (1<<0) + +#define FLAG_CF (1<<0) + +#define PORT_WKOC_E (1<<22) +#define PORT_WKDISC_E (1<<21) +#define PORT_WKCONN_E (1<<20) +#define PORT_TEST_PKT (0x4<<16) +#define PORT_LED_OFF (0<<14) +#define PORT_LED_AMBER (1<<14) +#define PORT_LED_GREEN (2<<14) +#define PORT_LED_MASK (3<<14) +#define PORT_OWNER (1<<13) +#define PORT_POWER (1<<12) +#define PORT_LINESTATUS_MASK (3<<10) +#define PORT_LINESTATUS_KSTATE (1<<10) +#define PORT_RESET (1<<8) +#define PORT_SUSPEND (1<<7) +#define PORT_RESUME (1<<6) +#define PORT_OCC (1<<5) +#define PORT_OC (1<<4) +#define PORT_PEC (1<<3) +#define PORT_PE (1<<2) +#define PORT_CSC (1<<1) +#define PORT_CONNECT (1<<0) +#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC) + + +#define EHCI_QH_ALIGN 64 // Can't span a 4K boundary, so increase to 64 + +struct ehci_qh { + u32 next; + u32 info1; + u32 info2; + u32 current; + + u32 qtd_next; + u32 alt_next; + u32 token; + u32 buf[5]; + // u32 buf_hi[5]; +} PACKED; + +#define QH_CONTROL (1 << 27) +#define QH_MAXPACKET_SHIFT 16 +#define QH_MAXPACKET_MASK (0x7ff << QH_MAXPACKET_SHIFT) +#define QH_HEAD (1 << 15) +#define QH_TOGGLECONTROL (1 << 14) +#define QH_SPEED_SHIFT 12 +#define QH_SPEED_MASK (0x3 << QH_SPEED_SHIFT) +#define QH_EP_SHIFT 8 +#define QH_EP_MASK (0xf << QH_EP_SHIFT) +#define QH_DEVADDR_SHIFT 0 +#define QH_DEVADDR_MASK (0x7f << QH_DEVADDR_SHIFT) + +#define QH_SMASK_SHIFT 0 +#define QH_SMASK_MASK (0xff << QH_SMASK_SHIFT) +#define QH_CMASK_SHIFT 8 +#define QH_CMASK_MASK (0xff << QH_CMASK_SHIFT) +#define QH_HUBADDR_SHIFT 16 +#define QH_HUBADDR_MASK (0x7f << QH_HUBADDR_SHIFT) +#define QH_HUBPORT_SHIFT 23 +#define QH_HUBPORT_MASK (0x7f << QH_HUBPORT_SHIFT) +#define QH_MULT_SHIFT 30 +#define QH_MULT_MASK (0x3 << QH_MULT_SHIFT) + +#define EHCI_PTR_BITS 0x001F +#define EHCI_PTR_TERM 0x0001 +#define EHCI_PTR_QH 0x0002 + + +#define EHCI_QTD_ALIGN 32 + +struct ehci_qtd { + u32 qtd_next; + u32 alt_next; + u32 token; + u32 buf[5]; + //u32 buf_hi[5]; +} PACKED; + +#define QTD_TOGGLE (1 << 31) +#define QTD_LENGTH_SHIFT 16 +#define QTD_LENGTH_MASK (0x7fff << QTD_LENGTH_SHIFT) +#define QTD_CERR_SHIFT 10 +#define QTD_CERR_MASK (0x3 << QTD_CERR_SHIFT) +#define QTD_IOC (1 << 15) +#define QTD_PID_OUT (0x0 << 8) +#define QTD_PID_IN (0x1 << 8) +#define QTD_PID_SETUP (0x2 << 8) +#define QTD_STS_ACTIVE (1 << 7) +#define QTD_STS_HALT (1 << 6) +#define QTD_STS_DBE (1 << 5) +#define QTD_STS_BABBLE (1 << 4) +#define QTD_STS_XACT (1 << 3) +#define QTD_STS_MMF (1 << 2) +#define QTD_STS_STS (1 << 1) +#define QTD_STS_PING (1 << 0) + +#define ehci_explen(len) (((len) << QTD_LENGTH_SHIFT) & QTD_LENGTH_MASK) + +#define ehci_maxerr(err) (((err) << QTD_CERR_SHIFT) & QTD_CERR_MASK) + + +struct ehci_framelist { + u32 links[1024]; +} PACKED; + +#endif // usb-ehci.h diff --git a/bios/seabios/src/usb-hid.c b/bios/seabios/src/usb-hid.c new file mode 100644 index 0000000..168b7fa --- /dev/null +++ b/bios/seabios/src/usb-hid.c @@ -0,0 +1,418 @@ +// Code for handling USB Human Interface Devices (HID). +// +// Copyright (C) 2009 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // dprintf +#include "usb-hid.h" // usb_keyboard_setup +#include "config.h" // CONFIG_* +#include "usb.h" // usb_ctrlrequest +#include "biosvar.h" // GET_GLOBAL +#include "ps2port.h" // ATKBD_CMD_GETID + +struct usb_pipe *keyboard_pipe VAR16VISIBLE; +struct usb_pipe *mouse_pipe VAR16VISIBLE; + + +/**************************************************************** + * Setup + ****************************************************************/ + +// Send USB HID protocol message. +static int +set_protocol(struct usb_pipe *pipe, u16 val) +{ + struct usb_ctrlrequest req; + req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + req.bRequest = HID_REQ_SET_PROTOCOL; + req.wValue = val; + req.wIndex = 0; + req.wLength = 0; + return send_default_control(pipe, &req, NULL); +} + +// Send USB HID SetIdle request. +static int +set_idle(struct usb_pipe *pipe, int ms) +{ + struct usb_ctrlrequest req; + req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + req.bRequest = HID_REQ_SET_IDLE; + req.wValue = (ms/4)<<8; + req.wIndex = 0; + req.wLength = 0; + return send_default_control(pipe, &req, NULL); +} + +#define KEYREPEATWAITMS 500 +#define KEYREPEATMS 33 + +static int +usb_kbd_init(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc) +{ + if (! CONFIG_USB_KEYBOARD) + return -1; + if (keyboard_pipe) + // XXX - this enables the first found keyboard (could be random) + return -1; + + if (epdesc->wMaxPacketSize != 8) + return -1; + + // Enable "boot" protocol. + int ret = set_protocol(pipe, 0); + if (ret) + return -1; + // Periodically send reports to enable key repeat. + ret = set_idle(pipe, KEYREPEATMS); + if (ret) + return -1; + + keyboard_pipe = alloc_intr_pipe(pipe, epdesc); + if (!keyboard_pipe) + return -1; + + dprintf(1, "USB keyboard initialized\n"); + return 0; +} + +static int +usb_mouse_init(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc) +{ + if (! CONFIG_USB_MOUSE) + return -1; + if (mouse_pipe) + // XXX - this enables the first found mouse (could be random) + return -1; + + if (epdesc->wMaxPacketSize < 3 || epdesc->wMaxPacketSize > 8) + return -1; + + // Enable "boot" protocol. + int ret = set_protocol(pipe, 0); + if (ret) + return -1; + + mouse_pipe = alloc_intr_pipe(pipe, epdesc); + if (!mouse_pipe) + return -1; + + dprintf(1, "USB mouse initialized\n"); + return 0; +} + +// Initialize a found USB HID device (if applicable). +int +usb_hid_init(struct usb_pipe *pipe + , struct usb_interface_descriptor *iface, int imax) +{ + if (! CONFIG_USB_KEYBOARD || ! CONFIG_USB_MOUSE) + return -1; + dprintf(2, "usb_hid_init %p\n", pipe); + + if (iface->bInterfaceSubClass != USB_INTERFACE_SUBCLASS_BOOT) + // Doesn't support boot protocol. + return -1; + + // Find intr in endpoint. + struct usb_endpoint_descriptor *epdesc = findEndPointDesc( + iface, imax, USB_ENDPOINT_XFER_INT, USB_DIR_IN); + if (!epdesc) { + dprintf(1, "No usb hid intr in?\n"); + return -1; + } + + if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD) + return usb_kbd_init(pipe, epdesc); + if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE) + return usb_mouse_init(pipe, epdesc); + return -1; +} + + +/**************************************************************** + * Keyboard events + ****************************************************************/ + +// Mapping from USB key id to ps2 key sequence. +static u16 KeyToScanCode[] VAR16 = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x001e, 0x0030, 0x002e, 0x0020, + 0x0012, 0x0021, 0x0022, 0x0023, 0x0017, 0x0024, 0x0025, 0x0026, + 0x0032, 0x0031, 0x0018, 0x0019, 0x0010, 0x0013, 0x001f, 0x0014, + 0x0016, 0x002f, 0x0011, 0x002d, 0x0015, 0x002c, 0x0002, 0x0003, + 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, + 0x001c, 0x0001, 0x000e, 0x000f, 0x0039, 0x000c, 0x000d, 0x001a, + 0x001b, 0x002b, 0x0000, 0x0027, 0x0028, 0x0029, 0x0033, 0x0034, + 0x0035, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, + 0x0041, 0x0042, 0x0043, 0x0044, 0x0057, 0x0058, 0xe037, 0x0046, + 0xe11d, 0xe052, 0xe047, 0xe049, 0xe053, 0xe04f, 0xe051, 0xe04d, + 0xe04b, 0xe050, 0xe048, 0x0045, 0xe035, 0x0037, 0x004a, 0x004e, + 0xe01c, 0x004f, 0x0050, 0x0051, 0x004b, 0x004c, 0x004d, 0x0047, + 0x0048, 0x0049, 0x0052, 0x0053 +}; + +// Mapping from USB modifier id to ps2 key sequence. +static u16 ModifierToScanCode[] VAR16 = { + //lcntl, lshift, lalt, lgui, rcntl, rshift, ralt, rgui + 0x001d, 0x002a, 0x0038, 0xe05b, 0xe01d, 0x0036, 0xe038, 0xe05c +}; + +#define RELEASEBIT 0x80 + +// Format of USB keyboard event data +struct keyevent { + u8 modifiers; + u8 reserved; + u8 keys[6]; +}; + +// Translate data from KeyToScanCode[] to calls to process_key(). +static void +prockeys(u16 keys) +{ + if (keys > 0xff) { + u8 key = keys>>8; + if (key == 0xe1) { + // Pause key + process_key(0xe1); + process_key(0x1d | (keys & RELEASEBIT)); + process_key(0x45 | (keys & RELEASEBIT)); + return; + } + process_key(key); + } + process_key(keys); +} + +// Handle a USB key press/release event. +static void +procscankey(u8 key, u8 flags) +{ + if (key >= ARRAY_SIZE(KeyToScanCode)) + return; + u16 keys = GET_GLOBAL(KeyToScanCode[key]); + if (keys) + prockeys(keys | flags); +} + +// Handle a USB modifier press/release event. +static void +procmodkey(u8 mods, u8 flags) +{ + int i; + for (i=0; mods; i++) + if (mods & (1<modifiers, data->keys[0]); + + // Load old keys. + u16 ebda_seg = get_ebda_seg(); + struct usbkeyinfo old; + old.data = GET_EBDA2(ebda_seg, usbkey_last.data); + + // Check for keys no longer pressed. + int addpos = 0; + int i; + for (i=0; i=ARRAY_SIZE(data->keys)) { + // Key released. + procscankey(key, RELEASEBIT); + if (i+1 >= ARRAY_SIZE(old.keys) || !old.keys[i+1]) + // Last pressed key released - disable repeat. + old.repeatcount = 0xff; + break; + } + if (data->keys[j] == key) { + // Key still pressed. + data->keys[j] = 0; + old.keys[addpos++] = key; + break; + } + } + } + procmodkey(old.modifiers & ~data->modifiers, RELEASEBIT); + + // Process new keys + procmodkey(data->modifiers & ~old.modifiers, 0); + old.modifiers = data->modifiers; + for (i=0; ikeys); i++) { + u8 key = data->keys[i]; + if (!key) + continue; + // New key pressed. + procscankey(key, 0); + old.keys[addpos++] = key; + old.repeatcount = KEYREPEATWAITMS / KEYREPEATMS + 1; + } + if (addpos < ARRAY_SIZE(old.keys)) + old.keys[addpos] = 0; + + // Check for key repeat event. + if (addpos) { + if (!old.repeatcount) + procscankey(old.keys[addpos-1], 0); + else if (old.repeatcount != 0xff) + old.repeatcount--; + } + + // Update old keys + SET_EBDA2(ebda_seg, usbkey_last.data, old.data); +} + +// Check if a USB keyboard event is pending and process it if so. +static void +usb_check_key(void) +{ + if (! CONFIG_USB_KEYBOARD) + return; + struct usb_pipe *pipe = GET_GLOBAL(keyboard_pipe); + if (!pipe) + return; + + for (;;) { + struct keyevent data; + int ret = usb_poll_intr(pipe, &data); + if (ret) + break; + handle_key(&data); + } +} + +// Test if USB keyboard is active. +inline int +usb_kbd_active(void) +{ + if (! CONFIG_USB_KEYBOARD) + return 0; + return GET_GLOBAL(keyboard_pipe) != NULL; +} + +// Handle a ps2 style keyboard command. +inline int +usb_kbd_command(int command, u8 *param) +{ + if (! CONFIG_USB_KEYBOARD) + return -1; + dprintf(9, "usb keyboard cmd=%x\n", command); + switch (command) { + case ATKBD_CMD_GETID: + // Return the id of a standard AT keyboard. + param[0] = 0xab; + param[1] = 0x83; + return 0; + default: + return -1; + } +} + + +/**************************************************************** + * Mouse events + ****************************************************************/ + +// Format of USB mouse event data +struct mouseevent { + u8 buttons; + u8 x, y; + u8 reserved[5]; +}; + +// Process USB mouse data. +static void +handle_mouse(struct mouseevent *data) +{ + dprintf(9, "Got mouse b=%x x=%x y=%x\n", data->buttons, data->x, data->y); + + s8 x = data->x, y = -data->y; + u8 flag = ((data->buttons & 0x7) | (1<<3) + | (x & 0x80 ? (1<<4) : 0) | (y & 0x80 ? (1<<5) : 0)); + process_mouse(flag); + process_mouse(x); + process_mouse(y); +} + +// Check if a USB mouse event is pending and process it if so. +static void +usb_check_mouse(void) +{ + if (! CONFIG_USB_MOUSE) + return; + struct usb_pipe *pipe = GET_GLOBAL(mouse_pipe); + if (!pipe) + return; + + for (;;) { + struct mouseevent data; + int ret = usb_poll_intr(pipe, &data); + if (ret) + break; + handle_mouse(&data); + } +} + +// Test if USB mouse is active. +inline int +usb_mouse_active(void) +{ + if (! CONFIG_USB_MOUSE) + return 0; + return GET_GLOBAL(mouse_pipe) != NULL; +} + +// Handle a ps2 style mouse command. +inline int +usb_mouse_command(int command, u8 *param) +{ + if (! CONFIG_USB_MOUSE) + return -1; + dprintf(9, "usb mouse cmd=%x\n", command); + switch (command) { + case PSMOUSE_CMD_ENABLE: + case PSMOUSE_CMD_DISABLE: + case PSMOUSE_CMD_SETSCALE11: + return 0; + case PSMOUSE_CMD_SETSCALE21: + case PSMOUSE_CMD_SETRATE: + case PSMOUSE_CMD_SETRES: + // XXX + return 0; + case PSMOUSE_CMD_RESET_BAT: + case PSMOUSE_CMD_GETID: + // Return the id of a standard AT mouse. + param[0] = 0xaa; + param[1] = 0x00; + return 0; + + case PSMOUSE_CMD_GETINFO: + param[0] = 0x00; + param[1] = 4; + param[2] = 100; + return 0; + + default: + return -1; + } +} + +// Check for USB events pending - called periodically from timer interrupt. +void +usb_check_event(void) +{ + usb_check_key(); + usb_check_mouse(); +} diff --git a/bios/seabios/src/usb-hid.h b/bios/seabios/src/usb-hid.h new file mode 100644 index 0000000..7fbcf4b --- /dev/null +++ b/bios/seabios/src/usb-hid.h @@ -0,0 +1,31 @@ +#ifndef __USB_HID_H +#define __USB_HID_H + +// usb-hid.c +struct usb_interface_descriptor; +struct usb_pipe; +int usb_hid_init(struct usb_pipe *pipe + , struct usb_interface_descriptor *iface, int imax); +inline int usb_kbd_active(void); +inline int usb_kbd_command(int command, u8 *param); +inline int usb_mouse_active(void); +inline int usb_mouse_command(int command, u8 *param); +void usb_check_event(void); + + +/**************************************************************** + * hid flags + ****************************************************************/ + +#define USB_INTERFACE_SUBCLASS_BOOT 1 +#define USB_INTERFACE_PROTOCOL_KEYBOARD 1 +#define USB_INTERFACE_PROTOCOL_MOUSE 2 + +#define HID_REQ_GET_REPORT 0x01 +#define HID_REQ_GET_IDLE 0x02 +#define HID_REQ_GET_PROTOCOL 0x03 +#define HID_REQ_SET_REPORT 0x09 +#define HID_REQ_SET_IDLE 0x0A +#define HID_REQ_SET_PROTOCOL 0x0B + +#endif // ush-hid.h diff --git a/bios/seabios/src/usb-hub.c b/bios/seabios/src/usb-hub.c new file mode 100644 index 0000000..b2d9ff2 --- /dev/null +++ b/bios/seabios/src/usb-hub.c @@ -0,0 +1,185 @@ +// Code for handling standard USB hubs. +// +// Copyright (C) 2010 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // dprintf +#include "config.h" // CONFIG_USB_HUB +#include "usb-hub.h" // struct usb_hub_descriptor +#include "usb.h" // struct usb_s + +static int +get_hub_desc(struct usb_pipe *pipe, struct usb_hub_descriptor *desc) +{ + struct usb_ctrlrequest req; + req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE; + req.bRequest = USB_REQ_GET_DESCRIPTOR; + req.wValue = USB_DT_HUB<<8; + req.wIndex = 0; + req.wLength = sizeof(*desc); + return send_default_control(pipe, &req, desc); +} + +static int +set_port_feature(struct usbhub_s *hub, int port, int feature) +{ + struct usb_ctrlrequest req; + req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER; + req.bRequest = USB_REQ_SET_FEATURE; + req.wValue = feature; + req.wIndex = port + 1; + req.wLength = 0; + mutex_lock(&hub->lock); + int ret = send_default_control(hub->pipe, &req, NULL); + mutex_unlock(&hub->lock); + return ret; +} + +static int +clear_port_feature(struct usbhub_s *hub, int port, int feature) +{ + struct usb_ctrlrequest req; + req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER; + req.bRequest = USB_REQ_CLEAR_FEATURE; + req.wValue = feature; + req.wIndex = port + 1; + req.wLength = 0; + mutex_lock(&hub->lock); + int ret = send_default_control(hub->pipe, &req, NULL); + mutex_unlock(&hub->lock); + return ret; +} + +static int +get_port_status(struct usbhub_s *hub, int port, struct usb_port_status *sts) +{ + struct usb_ctrlrequest req; + req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_OTHER; + req.bRequest = USB_REQ_GET_STATUS; + req.wValue = 0; + req.wIndex = port + 1; + req.wLength = sizeof(*sts); + mutex_lock(&hub->lock); + int ret = send_default_control(hub->pipe, &req, sts); + mutex_unlock(&hub->lock); + return ret; +} + +// Check if device attached to port +static int +usb_hub_detect(struct usbhub_s *hub, u32 port) +{ + // Turn on power to port. + int ret = set_port_feature(hub, port, USB_PORT_FEAT_POWER); + if (ret) + goto fail; + + // Wait for port power to stabilize. + msleep(hub->powerwait); + + // Check periodically for a device connect. + struct usb_port_status sts; + u64 end = calc_future_tsc(USB_TIME_SIGATT); + for (;;) { + ret = get_port_status(hub, port, &sts); + if (ret) + goto fail; + if (sts.wPortStatus & USB_PORT_STAT_CONNECTION) + // Device connected. + break; + if (check_tsc(end)) + // No device found. + return -1; + msleep(5); + } + + // XXX - wait USB_TIME_ATTDB time? + + return 0; + +fail: + dprintf(1, "Failure on hub port %d detect\n", port); + return -1; +} + +// Disable port +static void +usb_hub_disconnect(struct usbhub_s *hub, u32 port) +{ + int ret = clear_port_feature(hub, port, USB_PORT_FEAT_ENABLE); + if (ret) + dprintf(1, "Failure on hub port %d disconnect\n", port); +} + +// Reset device on port +static int +usb_hub_reset(struct usbhub_s *hub, u32 port) +{ + int ret = set_port_feature(hub, port, USB_PORT_FEAT_RESET); + if (ret) + goto fail; + + // Wait for reset to complete. + struct usb_port_status sts; + u64 end = calc_future_tsc(USB_TIME_DRST * 2); + for (;;) { + ret = get_port_status(hub, port, &sts); + if (ret) + goto fail; + if (!(sts.wPortStatus & USB_PORT_STAT_RESET)) + break; + if (check_tsc(end)) { + warn_timeout(); + goto fail; + } + msleep(5); + } + + // Reset complete. + if (!(sts.wPortStatus & USB_PORT_STAT_CONNECTION)) + // Device no longer present + return -1; + + return ((sts.wPortStatus & USB_PORT_STAT_SPEED_MASK) + >> USB_PORT_STAT_SPEED_SHIFT); + +fail: + dprintf(1, "Failure on hub port %d reset\n", port); + usb_hub_disconnect(hub, port); + return -1; +} + +static struct usbhub_op_s HubOp = { + .detect = usb_hub_detect, + .reset = usb_hub_reset, + .disconnect = usb_hub_disconnect, +}; + +// Configure a usb hub and then find devices connected to it. +int +usb_hub_init(struct usb_pipe *pipe) +{ + ASSERT32FLAT(); + if (!CONFIG_USB_HUB) + return -1; + + struct usb_hub_descriptor desc; + int ret = get_hub_desc(pipe, &desc); + if (ret) + return ret; + + struct usbhub_s hub; + memset(&hub, 0, sizeof(hub)); + hub.pipe = pipe; + hub.cntl = pipe->cntl; + hub.powerwait = desc.bPwrOn2PwrGood * 2; + hub.portcount = desc.bNbrPorts; + hub.op = &HubOp; + usb_enumerate(&hub); + + dprintf(1, "Initialized USB HUB (%d ports used)\n", hub.devcount); + if (hub.devcount) + return 0; + return -1; +} diff --git a/bios/seabios/src/usb-hub.h b/bios/seabios/src/usb-hub.h new file mode 100644 index 0000000..7672028 --- /dev/null +++ b/bios/seabios/src/usb-hub.h @@ -0,0 +1,60 @@ +#ifndef __USB_HUB_H +#define __USB_HUB_H + +// usb-hub.c +struct usb_pipe; +int usb_hub_init(struct usb_pipe *pipe); + + +/**************************************************************** + * hub flags + ****************************************************************/ + +#define USB_DT_HUB (USB_TYPE_CLASS | 0x09) + +struct usb_hub_descriptor { + u8 bDescLength; + u8 bDescriptorType; + u8 bNbrPorts; + u16 wHubCharacteristics; + u8 bPwrOn2PwrGood; + u8 bHubContrCurrent; + // Variable length fields for DeviceRemovable[], PortPwrCtrlMask[] follow. +} PACKED; + +#define USB_PORT_FEAT_CONNECTION 0 +#define USB_PORT_FEAT_ENABLE 1 +#define USB_PORT_FEAT_SUSPEND 2 +#define USB_PORT_FEAT_OVER_CURRENT 3 +#define USB_PORT_FEAT_RESET 4 +#define USB_PORT_FEAT_POWER 8 +#define USB_PORT_FEAT_LOWSPEED 9 +#define USB_PORT_FEAT_C_CONNECTION 16 +#define USB_PORT_FEAT_C_ENABLE 17 +#define USB_PORT_FEAT_C_SUSPEND 18 +#define USB_PORT_FEAT_C_OVER_CURRENT 19 +#define USB_PORT_FEAT_C_RESET 20 +#define USB_PORT_FEAT_TEST 21 +#define USB_PORT_FEAT_INDICATOR 22 +#define USB_PORT_FEAT_C_PORT_L1 23 + +struct usb_port_status { + u16 wPortStatus; + u16 wPortChange; +} PACKED; + +#define USB_PORT_STAT_CONNECTION 0x0001 +#define USB_PORT_STAT_ENABLE 0x0002 +#define USB_PORT_STAT_SUSPEND 0x0004 +#define USB_PORT_STAT_OVERCURRENT 0x0008 +#define USB_PORT_STAT_RESET 0x0010 +#define USB_PORT_STAT_L1 0x0020 +#define USB_PORT_STAT_POWER 0x0100 +#define USB_PORT_STAT_SPEED_SHIFT 9 +#define USB_PORT_STAT_SPEED_MASK (0x3 << USB_PORT_STAT_SPEED_SHIFT) +#define USB_PORT_STAT_LOW_SPEED 0x0200 +#define USB_PORT_STAT_HIGH_SPEED 0x0400 +#define USB_PORT_STAT_TEST 0x0800 +#define USB_PORT_STAT_INDICATOR 0x1000 + +#endif // ush-hid.h diff --git a/bios/seabios/src/usb-msc.c b/bios/seabios/src/usb-msc.c new file mode 100644 index 0000000..13ef93e --- /dev/null +++ b/bios/seabios/src/usb-msc.c @@ -0,0 +1,260 @@ +// Code for handling USB Mass Storage Controller devices. +// +// Copyright (C) 2010 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // dprintf +#include "config.h" // CONFIG_USB_MSC +#include "usb-msc.h" // usb_msc_init +#include "usb.h" // struct usb_s +#include "biosvar.h" // GET_GLOBAL +#include "blockcmd.h" // cdb_read +#include "disk.h" // DTYPE_USB +#include "boot.h" // boot_add_hd + +struct usbdrive_s { + struct drive_s drive; + struct usb_pipe *bulkin, *bulkout; +}; + + +/**************************************************************** + * Bulk-only drive command processing + ****************************************************************/ + +#define USB_CDB_SIZE 12 + +#define CBW_SIGNATURE 0x43425355 // USBC + +struct cbw_s { + u32 dCBWSignature; + u32 dCBWTag; + u32 dCBWDataTransferLength; + u8 bmCBWFlags; + u8 bCBWLUN; + u8 bCBWCBLength; + u8 CBWCB[16]; +} PACKED; + +#define CSW_SIGNATURE 0x53425355 // USBS + +struct csw_s { + u32 dCSWSignature; + u32 dCSWTag; + u32 dCSWDataResidue; + u8 bCSWStatus; +} PACKED; + +// Low-level usb command transmit function. +int +usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) +{ + if (!CONFIG_USB_MSC) + return 0; + + dprintf(16, "usb_cmd_data id=%p write=%d count=%d bs=%d buf=%p\n" + , op->drive_g, 0, op->count, blocksize, op->buf_fl); + struct usbdrive_s *udrive_g = container_of( + op->drive_g, struct usbdrive_s, drive); + struct usb_pipe *bulkin = GET_GLOBAL(udrive_g->bulkin); + struct usb_pipe *bulkout = GET_GLOBAL(udrive_g->bulkout); + + // Setup command block wrapper. + u32 bytes = blocksize * op->count; + struct cbw_s cbw; + memset(&cbw, 0, sizeof(cbw)); + cbw.dCBWSignature = CBW_SIGNATURE; + cbw.dCBWTag = 999; // XXX + cbw.dCBWDataTransferLength = bytes; + cbw.bmCBWFlags = USB_DIR_IN; // XXX + cbw.bCBWLUN = 0; // XXX + cbw.bCBWCBLength = USB_CDB_SIZE; + memcpy(cbw.CBWCB, cdbcmd, USB_CDB_SIZE); + + // Transfer cbw to device. + int ret = usb_send_bulk(bulkout, USB_DIR_OUT + , MAKE_FLATPTR(GET_SEG(SS), &cbw), sizeof(cbw)); + if (ret) + goto fail; + + // Transfer data from device. + ret = usb_send_bulk(bulkin, USB_DIR_IN, op->buf_fl, bytes); + if (ret) + goto fail; + + // Transfer csw info. + struct csw_s csw; + ret = usb_send_bulk(bulkin, USB_DIR_IN + , MAKE_FLATPTR(GET_SEG(SS), &csw), sizeof(csw)); + if (ret) + goto fail; + + if (!csw.bCSWStatus) + return DISK_RET_SUCCESS; + if (csw.bCSWStatus == 2) + goto fail; + + op->count -= csw.dCSWDataResidue / blocksize; + return DISK_RET_EBADTRACK; + +fail: + // XXX - reset connection + dprintf(1, "USB transmission failed\n"); + op->count = 0; + return DISK_RET_EBADTRACK; +} + + +/**************************************************************** + * Drive ops + ****************************************************************/ + +// 16bit command demuxer for ATAPI cdroms. +int +process_usb_op(struct disk_op_s *op) +{ + if (!CONFIG_USB_MSC) + return 0; + switch (op->command) { + case CMD_READ: + return cdb_read(op); + case CMD_FORMAT: + case CMD_WRITE: + return DISK_RET_EWRITEPROTECT; + case CMD_RESET: + case CMD_ISREADY: + case CMD_VERIFY: + case CMD_SEEK: + return DISK_RET_SUCCESS; + default: + op->count = 0; + return DISK_RET_EPARAM; + } +} + + +/**************************************************************** + * Setup + ****************************************************************/ + +static int +setup_drive_cdrom(struct disk_op_s *op, char *desc) +{ + op->drive_g->blksize = CDROM_SECTOR_SIZE; + op->drive_g->sectors = (u64)-1; + struct usb_pipe *pipe = container_of( + op->drive_g, struct usbdrive_s, drive)->bulkout; + int prio = bootprio_find_usb(pipe->cntl->pci, pipe->path); + boot_add_cd(op->drive_g, desc, prio); + return 0; +} + +static int +setup_drive_hd(struct disk_op_s *op, char *desc) +{ + struct cdbres_read_capacity info; + int ret = cdb_read_capacity(op, &info); + if (ret) + return ret; + // XXX - retry for some timeout? + + u32 blksize = ntohl(info.blksize), sectors = ntohl(info.sectors); + if (blksize != DISK_SECTOR_SIZE) { + if (blksize == CDROM_SECTOR_SIZE) + return setup_drive_cdrom(op, desc); + dprintf(1, "Unsupported USB MSC block size %d\n", blksize); + return -1; + } + op->drive_g->blksize = blksize; + op->drive_g->sectors = sectors; + dprintf(1, "USB MSC blksize=%d sectors=%d\n", blksize, sectors); + + // Register with bcv system. + struct usb_pipe *pipe = container_of( + op->drive_g, struct usbdrive_s, drive)->bulkout; + int prio = bootprio_find_usb(pipe->cntl->pci, pipe->path); + boot_add_hd(op->drive_g, desc, prio); + + return 0; +} + +// Configure a usb msc device. +int +usb_msc_init(struct usb_pipe *pipe + , struct usb_interface_descriptor *iface, int imax) +{ + if (!CONFIG_USB_MSC) + return -1; + + // Verify right kind of device + if ((iface->bInterfaceSubClass != US_SC_SCSI && + iface->bInterfaceSubClass != US_SC_ATAPI_8070 && + iface->bInterfaceSubClass != US_SC_ATAPI_8020) + || iface->bInterfaceProtocol != US_PR_BULK) { + dprintf(1, "Unsupported MSC USB device (subclass=%02x proto=%02x)\n" + , iface->bInterfaceSubClass, iface->bInterfaceProtocol); + return -1; + } + + // Allocate drive structure. + struct usbdrive_s *udrive_g = malloc_fseg(sizeof(*udrive_g)); + if (!udrive_g) { + warn_noalloc(); + goto fail; + } + memset(udrive_g, 0, sizeof(*udrive_g)); + udrive_g->drive.type = DTYPE_USB; + + // Find bulk in and bulk out endpoints. + struct usb_endpoint_descriptor *indesc = findEndPointDesc( + iface, imax, USB_ENDPOINT_XFER_BULK, USB_DIR_IN); + struct usb_endpoint_descriptor *outdesc = findEndPointDesc( + iface, imax, USB_ENDPOINT_XFER_BULK, USB_DIR_OUT); + if (!indesc || !outdesc) + goto fail; + udrive_g->bulkin = alloc_bulk_pipe(pipe, indesc); + udrive_g->bulkout = alloc_bulk_pipe(pipe, outdesc); + if (!udrive_g->bulkin || !udrive_g->bulkout) + goto fail; + + // Validate drive and find block size and sector count. + struct disk_op_s dop; + memset(&dop, 0, sizeof(dop)); + dop.drive_g = &udrive_g->drive; + struct cdbres_inquiry data; + int ret = cdb_get_inquiry(&dop, &data); + if (ret) + goto fail; + char vendor[sizeof(data.vendor)+1], product[sizeof(data.product)+1]; + char rev[sizeof(data.rev)+1]; + strtcpy(vendor, data.vendor, sizeof(vendor)); + nullTrailingSpace(vendor); + strtcpy(product, data.product, sizeof(product)); + nullTrailingSpace(product); + strtcpy(rev, data.rev, sizeof(rev)); + nullTrailingSpace(rev); + int pdt = data.pdt & 0x1f; + int removable = !!(data.removable & 0x80); + dprintf(1, "USB MSC vendor='%s' product='%s' rev='%s' type=%d removable=%d\n" + , vendor, product, rev, pdt, removable); + udrive_g->drive.removable = removable; + + if (pdt == USB_MSC_TYPE_CDROM) { + char *desc = znprintf(MAXDESCSIZE, "DVD/CD [USB Drive %s %s %s]" + , vendor, product, rev); + ret = setup_drive_cdrom(&dop, desc); + } else { + char *desc = znprintf(MAXDESCSIZE, "USB Drive %s %s %s" + , vendor, product, rev); + ret = setup_drive_hd(&dop, desc); + } + if (ret) + goto fail; + + return 0; +fail: + dprintf(1, "Unable to configure USB MSC device.\n"); + free(udrive_g); + return -1; +} diff --git a/bios/seabios/src/usb-msc.h b/bios/seabios/src/usb-msc.h new file mode 100644 index 0000000..71adb20 --- /dev/null +++ b/bios/seabios/src/usb-msc.h @@ -0,0 +1,27 @@ +#ifndef __USB_MSC_H +#define __USB_MSC_H + +// usb-msc.c +struct disk_op_s; +int usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize); +struct usb_interface_descriptor; +struct usb_pipe; +int usb_msc_init(struct usb_pipe *pipe + , struct usb_interface_descriptor *iface, int imax); +int process_usb_op(struct disk_op_s *op); + + +/**************************************************************** + * MSC flags + ****************************************************************/ + +#define US_SC_ATAPI_8020 0x02 +#define US_SC_ATAPI_8070 0x05 +#define US_SC_SCSI 0x06 + +#define US_PR_BULK 0x50 + +#define USB_MSC_TYPE_DISK 0x00 +#define USB_MSC_TYPE_CDROM 0x05 + +#endif // ush-msc.h diff --git a/bios/seabios/src/usb-ohci.c b/bios/seabios/src/usb-ohci.c new file mode 100644 index 0000000..9107db2 --- /dev/null +++ b/bios/seabios/src/usb-ohci.c @@ -0,0 +1,537 @@ +// Code for handling OHCI USB controllers. +// +// Copyright (C) 2009 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // dprintf +#include "pci.h" // pci_bdf_to_bus +#include "config.h" // CONFIG_* +#include "usb-ohci.h" // struct ohci_hcca +#include "pci_regs.h" // PCI_BASE_ADDRESS_0 +#include "usb.h" // struct usb_s +#include "farptr.h" // GET_FLATPTR + +#define FIT (1 << 31) + +struct usb_ohci_s { + struct usb_s usb; + struct ohci_regs *regs; +}; + + +/**************************************************************** + * Root hub + ****************************************************************/ + +// Check if device attached to port +static int +ohci_hub_detect(struct usbhub_s *hub, u32 port) +{ + struct usb_ohci_s *cntl = container_of(hub->cntl, struct usb_ohci_s, usb); + u32 sts = readl(&cntl->regs->roothub_portstatus[port]); + if (!(sts & RH_PS_CCS)) + // No device. + return -1; + + // XXX - need to wait for USB_TIME_ATTDB if just powered up? + + return 0; +} + +// Disable port +static void +ohci_hub_disconnect(struct usbhub_s *hub, u32 port) +{ + struct usb_ohci_s *cntl = container_of(hub->cntl, struct usb_ohci_s, usb); + writel(&cntl->regs->roothub_portstatus[port], RH_PS_CCS|RH_PS_LSDA); +} + +// Reset device on port +static int +ohci_hub_reset(struct usbhub_s *hub, u32 port) +{ + struct usb_ohci_s *cntl = container_of(hub->cntl, struct usb_ohci_s, usb); + writel(&cntl->regs->roothub_portstatus[port], RH_PS_PRS); + u32 sts; + u64 end = calc_future_tsc(USB_TIME_DRSTR * 2); + for (;;) { + sts = readl(&cntl->regs->roothub_portstatus[port]); + if (!(sts & RH_PS_PRS)) + // XXX - need to ensure USB_TIME_DRSTR time in reset? + break; + if (check_tsc(end)) { + // Timeout. + warn_timeout(); + ohci_hub_disconnect(hub, port); + return -1; + } + yield(); + } + + if ((sts & (RH_PS_CCS|RH_PS_PES)) != (RH_PS_CCS|RH_PS_PES)) + // Device no longer present + return -1; + + return !!(sts & RH_PS_LSDA); +} + +static struct usbhub_op_s ohci_HubOp = { + .detect = ohci_hub_detect, + .reset = ohci_hub_reset, + .disconnect = ohci_hub_disconnect, +}; + +// Find any devices connected to the root hub. +static int +check_ohci_ports(struct usb_ohci_s *cntl) +{ + ASSERT32FLAT(); + // Turn on power for all devices on roothub. + u32 rha = readl(&cntl->regs->roothub_a); + rha &= ~(RH_A_PSM | RH_A_OCPM); + writel(&cntl->regs->roothub_status, RH_HS_LPSC); + writel(&cntl->regs->roothub_b, RH_B_PPCM); + msleep((rha >> 24) * 2); + // XXX - need to sleep for USB_TIME_SIGATT if just powered up? + + struct usbhub_s hub; + memset(&hub, 0, sizeof(hub)); + hub.cntl = &cntl->usb; + hub.portcount = rha & RH_A_NDP; + hub.op = &ohci_HubOp; + usb_enumerate(&hub); + return hub.devcount; +} + + +/**************************************************************** + * Setup + ****************************************************************/ + +static int +start_ohci(struct usb_ohci_s *cntl, struct ohci_hcca *hcca) +{ + u32 oldfminterval = readl(&cntl->regs->fminterval); + u32 oldrwc = readl(&cntl->regs->control) & OHCI_CTRL_RWC; + + // XXX - check if already running? + + // Do reset + writel(&cntl->regs->control, OHCI_USB_RESET | oldrwc); + readl(&cntl->regs->control); // flush writes + msleep(USB_TIME_DRSTR); + + // Do software init (min 10us, max 2ms) + u64 end = calc_future_tsc_usec(10); + writel(&cntl->regs->cmdstatus, OHCI_HCR); + for (;;) { + u32 status = readl(&cntl->regs->cmdstatus); + if (! status & OHCI_HCR) + break; + if (check_tsc(end)) { + warn_timeout(); + return -1; + } + } + + // Init memory + writel(&cntl->regs->ed_controlhead, 0); + writel(&cntl->regs->ed_bulkhead, 0); + writel(&cntl->regs->hcca, (u32)hcca); + + // Init fminterval + u32 fi = oldfminterval & 0x3fff; + writel(&cntl->regs->fminterval + , (((oldfminterval & FIT) ^ FIT) + | fi | (((6 * (fi - 210)) / 7) << 16))); + writel(&cntl->regs->periodicstart, ((9 * fi) / 10) & 0x3fff); + readl(&cntl->regs->control); // flush writes + + // XXX - verify that fminterval was setup correctly. + + // Go into operational state + writel(&cntl->regs->control + , (OHCI_CTRL_CBSR | OHCI_CTRL_CLE | OHCI_CTRL_PLE + | OHCI_USB_OPER | oldrwc)); + readl(&cntl->regs->control); // flush writes + + return 0; +} + +static void +stop_ohci(struct usb_ohci_s *cntl) +{ + u32 oldrwc = readl(&cntl->regs->control) & OHCI_CTRL_RWC; + writel(&cntl->regs->control, oldrwc); + readl(&cntl->regs->control); // flush writes +} + +static void +configure_ohci(void *data) +{ + struct usb_ohci_s *cntl = data; + + // Allocate memory + struct ohci_hcca *hcca = memalign_high(256, sizeof(*hcca)); + struct ohci_ed *intr_ed = malloc_high(sizeof(*intr_ed)); + if (!hcca || !intr_ed) { + warn_noalloc(); + goto free; + } + memset(hcca, 0, sizeof(*hcca)); + memset(intr_ed, 0, sizeof(*intr_ed)); + intr_ed->hwINFO = ED_SKIP; + int i; + for (i=0; iint_table); i++) + hcca->int_table[i] = (u32)intr_ed; + + int ret = start_ohci(cntl, hcca); + if (ret) + goto err; + + int count = check_ohci_ports(cntl); + free_pipe(cntl->usb.defaultpipe); + if (! count) + goto err; + return; + +err: + stop_ohci(cntl); +free: + free(hcca); + free(intr_ed); +} + +void +ohci_init(struct pci_device *pci, int busid) +{ + if (! CONFIG_USB_OHCI) + return; + struct usb_ohci_s *cntl = malloc_tmphigh(sizeof(*cntl)); + if (!cntl) { + warn_noalloc(); + return; + } + memset(cntl, 0, sizeof(*cntl)); + cntl->usb.busid = busid; + cntl->usb.pci = pci; + cntl->usb.type = USB_TYPE_OHCI; + + u16 bdf = pci->bdf; + u32 baseaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0); + cntl->regs = (void*)(baseaddr & PCI_BASE_ADDRESS_MEM_MASK); + + dprintf(1, "OHCI init on dev %02x:%02x.%x (regs=%p)\n" + , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf) + , pci_bdf_to_fn(bdf), cntl->regs); + + // Enable bus mastering and memory access. + pci_config_maskw(bdf, PCI_COMMAND + , 0, PCI_COMMAND_MASTER|PCI_COMMAND_MEMORY); + + // XXX - check for and disable SMM control? + + // Disable interrupts + writel(&cntl->regs->intrdisable, ~0); + writel(&cntl->regs->intrstatus, ~0); + + run_thread(configure_ohci, cntl); +} + + +/**************************************************************** + * End point communication + ****************************************************************/ + +static int +wait_ed(struct ohci_ed *ed) +{ + // XXX - 500ms just a guess + u64 end = calc_future_tsc(500); + for (;;) { + if (ed->hwHeadP == ed->hwTailP) + return 0; + if (check_tsc(end)) { + warn_timeout(); + return -1; + } + yield(); + } +} + +// Wait for next USB frame to start - for ensuring safe memory release. +static void +ohci_waittick(struct usb_ohci_s *cntl) +{ + barrier(); + struct ohci_hcca *hcca = (void*)cntl->regs->hcca; + u32 startframe = hcca->frame_no; + u64 end = calc_future_tsc(1000 * 5); + for (;;) { + if (hcca->frame_no != startframe) + break; + if (check_tsc(end)) { + warn_timeout(); + return; + } + yield(); + } +} + +static void +signal_freelist(struct usb_ohci_s *cntl) +{ + u32 v = readl(&cntl->regs->control); + if (v & OHCI_CTRL_CLE) { + writel(&cntl->regs->control, v & ~(OHCI_CTRL_CLE|OHCI_CTRL_BLE)); + ohci_waittick(cntl); + writel(&cntl->regs->ed_controlcurrent, 0); + writel(&cntl->regs->ed_bulkcurrent, 0); + writel(&cntl->regs->control, v); + } else { + ohci_waittick(cntl); + } +} + +struct ohci_pipe { + struct ohci_ed ed; + struct usb_pipe pipe; + void *data; + int count; + struct ohci_td *tds; +}; + +void +ohci_free_pipe(struct usb_pipe *p) +{ + if (! CONFIG_USB_OHCI) + return; + dprintf(7, "ohci_free_pipe %p\n", p); + struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe); + struct usb_ohci_s *cntl = container_of( + pipe->pipe.cntl, struct usb_ohci_s, usb); + + u32 *pos = &cntl->regs->ed_controlhead; + for (;;) { + struct ohci_ed *next = (void*)*pos; + if (!next) { + // Not found?! Exit without freeing. + warn_internalerror(); + return; + } + if (next == &pipe->ed) { + *pos = next->hwNextED; + signal_freelist(cntl); + free(pipe); + return; + } + pos = &next->hwNextED; + } +} + +struct usb_pipe * +ohci_alloc_control_pipe(struct usb_pipe *dummy) +{ + if (! CONFIG_USB_OHCI) + return NULL; + struct usb_ohci_s *cntl = container_of( + dummy->cntl, struct usb_ohci_s, usb); + dprintf(7, "ohci_alloc_control_pipe %p\n", &cntl->usb); + + // Allocate a queue head. + struct ohci_pipe *pipe = malloc_tmphigh(sizeof(*pipe)); + if (!pipe) { + warn_noalloc(); + return NULL; + } + memset(pipe, 0, sizeof(*pipe)); + memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe)); + pipe->ed.hwINFO = ED_SKIP; + + // Add queue head to controller list. + pipe->ed.hwNextED = cntl->regs->ed_controlhead; + barrier(); + cntl->regs->ed_controlhead = (u32)&pipe->ed; + return &pipe->pipe; +} + +int +ohci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize + , void *data, int datasize) +{ + if (! CONFIG_USB_OHCI) + return -1; + dprintf(5, "ohci_control %p\n", p); + if (datasize > 4096) { + // XXX - should support larger sizes. + warn_noalloc(); + return -1; + } + struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe); + struct usb_ohci_s *cntl = container_of( + pipe->pipe.cntl, struct usb_ohci_s, usb); + int maxpacket = pipe->pipe.maxpacket; + int lowspeed = pipe->pipe.speed; + int devaddr = pipe->pipe.devaddr | (pipe->pipe.ep << 7); + + // Setup transfer descriptors + struct ohci_td *tds = malloc_tmphigh(sizeof(*tds) * 3); + if (!tds) { + warn_noalloc(); + return -1; + } + struct ohci_td *td = tds; + td->hwINFO = TD_DP_SETUP | TD_T_DATA0 | TD_CC; + td->hwCBP = (u32)cmd; + td->hwNextTD = (u32)&td[1]; + td->hwBE = (u32)cmd + cmdsize - 1; + td++; + if (datasize) { + td->hwINFO = (dir ? TD_DP_IN : TD_DP_OUT) | TD_T_DATA1 | TD_CC; + td->hwCBP = (u32)data; + td->hwNextTD = (u32)&td[1]; + td->hwBE = (u32)data + datasize - 1; + td++; + } + td->hwINFO = (dir ? TD_DP_OUT : TD_DP_IN) | TD_T_DATA1 | TD_CC; + td->hwCBP = 0; + td->hwNextTD = (u32)&td[1]; + td->hwBE = 0; + td++; + + // Transfer data + pipe->ed.hwINFO = ED_SKIP; + barrier(); + pipe->ed.hwHeadP = (u32)tds; + pipe->ed.hwTailP = (u32)td; + barrier(); + pipe->ed.hwINFO = devaddr | (maxpacket << 16) | (lowspeed ? ED_LOWSPEED : 0); + writel(&cntl->regs->cmdstatus, OHCI_CLF); + + int ret = wait_ed(&pipe->ed); + pipe->ed.hwINFO = ED_SKIP; + if (ret) + ohci_waittick(cntl); + free(tds); + return ret; +} + +struct usb_pipe * +ohci_alloc_bulk_pipe(struct usb_pipe *dummy) +{ + if (! CONFIG_USB_OHCI) + return NULL; + dprintf(1, "OHCI Bulk transfers not supported.\n"); + return NULL; +} + +int +ohci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize) +{ + return -1; +} + +struct usb_pipe * +ohci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp) +{ + if (! CONFIG_USB_OHCI) + return NULL; + struct usb_ohci_s *cntl = container_of( + dummy->cntl, struct usb_ohci_s, usb); + dprintf(7, "ohci_alloc_intr_pipe %p %d\n", &cntl->usb, frameexp); + + if (frameexp > 5) + frameexp = 5; + int maxpacket = dummy->maxpacket; + int lowspeed = dummy->speed; + int devaddr = dummy->devaddr | (dummy->ep << 7); + // Determine number of entries needed for 2 timer ticks. + int ms = 1<pipe, dummy, sizeof(pipe->pipe)); + pipe->data = data; + pipe->count = count; + pipe->tds = tds; + + struct ohci_ed *ed = &pipe->ed; + ed->hwHeadP = (u32)&tds[0]; + ed->hwTailP = (u32)&tds[count-1]; + ed->hwINFO = devaddr | (maxpacket << 16) | (lowspeed ? ED_LOWSPEED : 0); + + int i; + for (i=0; iregs->hcca; + if (frameexp == 0) { + // Add to existing interrupt entry. + struct ohci_ed *intr_ed = (void*)hcca->int_table[0]; + ed->hwNextED = intr_ed->hwNextED; + intr_ed->hwNextED = (u32)ed; + } else { + int startpos = 1<<(frameexp-1); + ed->hwNextED = hcca->int_table[startpos]; + for (i=startpos; iint_table); i+=ms) + hcca->int_table[i] = (u32)ed; + } + + return &pipe->pipe; + +err: + free(pipe); + free(tds); + free(data); + return NULL; +} + +int +ohci_poll_intr(struct usb_pipe *p, void *data) +{ + ASSERT16(); + if (! CONFIG_USB_OHCI) + return -1; + + struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe); + struct ohci_td *tds = GET_FLATPTR(pipe->tds); + struct ohci_td *head = (void*)(GET_FLATPTR(pipe->ed.hwHeadP) & ~(ED_C|ED_H)); + struct ohci_td *tail = (void*)GET_FLATPTR(pipe->ed.hwTailP); + int count = GET_FLATPTR(pipe->count); + int pos = (tail - tds + 1) % count; + struct ohci_td *next = &tds[pos]; + if (head == next) + // No intrs found. + return -1; + // XXX - check for errors. + + // Copy data. + int maxpacket = GET_FLATPTR(pipe->pipe.maxpacket); + void *pipedata = GET_FLATPTR(pipe->data); + void *intrdata = pipedata + maxpacket * pos; + memcpy_far(GET_SEG(SS), data + , FLATPTR_TO_SEG(intrdata), (void*)FLATPTR_TO_OFFSET(intrdata) + , maxpacket); + + // Reenable this td. + SET_FLATPTR(tail->hwINFO, TD_DP_IN | TD_T_TOGGLE | TD_CC); + intrdata = pipedata + maxpacket * (tail-tds); + SET_FLATPTR(tail->hwCBP, (u32)intrdata); + SET_FLATPTR(tail->hwNextTD, (u32)next); + SET_FLATPTR(tail->hwBE, (u32)intrdata + maxpacket - 1); + barrier(); + SET_FLATPTR(pipe->ed.hwTailP, (u32)next); + + return 0; +} diff --git a/bios/seabios/src/usb-ohci.h b/bios/seabios/src/usb-ohci.h new file mode 100644 index 0000000..c7670ff --- /dev/null +++ b/bios/seabios/src/usb-ohci.h @@ -0,0 +1,143 @@ +#ifndef __USB_OHCI_H +#define __USB_OHCI_H + +// usb-ohci.c +void ohci_init(struct pci_device *pci, int busid); +struct usb_pipe; +void ohci_free_pipe(struct usb_pipe *p); +struct usb_pipe *ohci_alloc_control_pipe(struct usb_pipe *dummy); +int ohci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize + , void *data, int datasize); +struct usb_pipe *ohci_alloc_bulk_pipe(struct usb_pipe *dummy); +int ohci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize); +struct usb_pipe *ohci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp); +int ohci_poll_intr(struct usb_pipe *p, void *data); + + +/**************************************************************** + * ohci structs and flags + ****************************************************************/ + +struct ohci_ed { + u32 hwINFO; + u32 hwTailP; + u32 hwHeadP; + u32 hwNextED; +} PACKED; + +#define ED_ISO (1 << 15) +#define ED_SKIP (1 << 14) +#define ED_LOWSPEED (1 << 13) +#define ED_OUT (0x01 << 11) +#define ED_IN (0x02 << 11) + +#define ED_C (0x02) +#define ED_H (0x01) + +struct ohci_td { + u32 hwINFO; + u32 hwCBP; + u32 hwNextTD; + u32 hwBE; +} PACKED; + +#define TD_CC 0xf0000000 +#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f) +#define TD_DI 0x00E00000 + +#define TD_DONE 0x00020000 +#define TD_ISO 0x00010000 + +#define TD_EC 0x0C000000 +#define TD_T 0x03000000 +#define TD_T_DATA0 0x02000000 +#define TD_T_DATA1 0x03000000 +#define TD_T_TOGGLE 0x00000000 +#define TD_DP 0x00180000 +#define TD_DP_SETUP 0x00000000 +#define TD_DP_IN 0x00100000 +#define TD_DP_OUT 0x00080000 + +#define TD_R 0x00040000 + +struct ohci_hcca { + u32 int_table[32]; + u32 frame_no; + u32 done_head; + u8 reserved[120]; +} PACKED; + +struct ohci_regs { + u32 revision; + u32 control; + u32 cmdstatus; + u32 intrstatus; + u32 intrenable; + u32 intrdisable; + + u32 hcca; + u32 ed_periodcurrent; + u32 ed_controlhead; + u32 ed_controlcurrent; + u32 ed_bulkhead; + u32 ed_bulkcurrent; + u32 donehead; + + u32 fminterval; + u32 fmremaining; + u32 fmnumber; + u32 periodicstart; + u32 lsthresh; + + u32 roothub_a; + u32 roothub_b; + u32 roothub_status; + u32 roothub_portstatus[15]; +} PACKED; + +#define OHCI_CTRL_CBSR (3 << 0) +#define OHCI_CTRL_PLE (1 << 2) +#define OHCI_CTRL_CLE (1 << 4) +#define OHCI_CTRL_BLE (1 << 5) +#define OHCI_CTRL_HCFS (3 << 6) +# define OHCI_USB_RESET (0 << 6) +# define OHCI_USB_OPER (2 << 6) +#define OHCI_CTRL_RWC (1 << 9) + +#define OHCI_HCR (1 << 0) +#define OHCI_CLF (1 << 1) + +#define OHCI_INTR_MIE (1 << 31) + +#define RH_PS_CCS 0x00000001 +#define RH_PS_PES 0x00000002 +#define RH_PS_PSS 0x00000004 +#define RH_PS_POCI 0x00000008 +#define RH_PS_PRS 0x00000010 +#define RH_PS_PPS 0x00000100 +#define RH_PS_LSDA 0x00000200 +#define RH_PS_CSC 0x00010000 +#define RH_PS_PESC 0x00020000 +#define RH_PS_PSSC 0x00040000 +#define RH_PS_OCIC 0x00080000 +#define RH_PS_PRSC 0x00100000 + +#define RH_HS_LPS 0x00000001 +#define RH_HS_OCI 0x00000002 +#define RH_HS_DRWE 0x00008000 +#define RH_HS_LPSC 0x00010000 +#define RH_HS_OCIC 0x00020000 +#define RH_HS_CRWE 0x80000000 + +#define RH_B_DR 0x0000ffff +#define RH_B_PPCM 0xffff0000 + +#define RH_A_NDP (0xff << 0) +#define RH_A_PSM (1 << 8) +#define RH_A_NPS (1 << 9) +#define RH_A_DT (1 << 10) +#define RH_A_OCPM (1 << 11) +#define RH_A_NOCP (1 << 12) +#define RH_A_POTPGT (0xff << 24) + +#endif // usb-ohci.h diff --git a/bios/seabios/src/usb-uhci.c b/bios/seabios/src/usb-uhci.c new file mode 100644 index 0000000..f3680d3 --- /dev/null +++ b/bios/seabios/src/usb-uhci.c @@ -0,0 +1,609 @@ +// Code for handling UHCI USB controllers. +// +// Copyright (C) 2009 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // dprintf +#include "pci.h" // pci_bdf_to_bus +#include "config.h" // CONFIG_* +#include "ioport.h" // outw +#include "usb-uhci.h" // USBLEGSUP +#include "pci_regs.h" // PCI_BASE_ADDRESS_4 +#include "usb.h" // struct usb_s +#include "farptr.h" // GET_FLATPTR + +struct usb_uhci_s { + struct usb_s usb; + u16 iobase; + struct uhci_qh *control_qh, *bulk_qh; + struct uhci_framelist *framelist; +}; + + +/**************************************************************** + * Root hub + ****************************************************************/ + +// Check if device attached to a given port +static int +uhci_hub_detect(struct usbhub_s *hub, u32 port) +{ + struct usb_uhci_s *cntl = container_of(hub->cntl, struct usb_uhci_s, usb); + u16 ioport = cntl->iobase + USBPORTSC1 + port * 2; + + u16 status = inw(ioport); + if (!(status & USBPORTSC_CCS)) + // No device + return -1; + + // XXX - if just powered up, need to wait for USB_TIME_ATTDB? + + // Begin reset on port + outw(USBPORTSC_PR, ioport); + msleep(USB_TIME_DRSTR); + return 0; +} + +// Reset device on port +static int +uhci_hub_reset(struct usbhub_s *hub, u32 port) +{ + struct usb_uhci_s *cntl = container_of(hub->cntl, struct usb_uhci_s, usb); + u16 ioport = cntl->iobase + USBPORTSC1 + port * 2; + + // Finish reset on port + outw(0, ioport); + udelay(6); // 64 high-speed bit times + u16 status = inw(ioport); + if (!(status & USBPORTSC_CCS)) + // No longer connected + return -1; + outw(USBPORTSC_PE, ioport); + return !!(status & USBPORTSC_LSDA); +} + +// Disable port +static void +uhci_hub_disconnect(struct usbhub_s *hub, u32 port) +{ + struct usb_uhci_s *cntl = container_of(hub->cntl, struct usb_uhci_s, usb); + u16 ioport = cntl->iobase + USBPORTSC1 + port * 2; + outw(0, ioport); +} + +static struct usbhub_op_s uhci_HubOp = { + .detect = uhci_hub_detect, + .reset = uhci_hub_reset, + .disconnect = uhci_hub_disconnect, +}; + +// Find any devices connected to the root hub. +static int +check_uhci_ports(struct usb_uhci_s *cntl) +{ + ASSERT32FLAT(); + struct usbhub_s hub; + memset(&hub, 0, sizeof(hub)); + hub.cntl = &cntl->usb; + hub.portcount = 2; + hub.op = &uhci_HubOp; + usb_enumerate(&hub); + return hub.devcount; +} + + +/**************************************************************** + * Setup + ****************************************************************/ + +static void +reset_uhci(struct usb_uhci_s *cntl, u16 bdf) +{ + // XXX - don't reset if not needed. + + // Reset PIRQ and SMI + pci_config_writew(bdf, USBLEGSUP, USBLEGSUP_RWC); + + // Reset the HC + outw(USBCMD_HCRESET, cntl->iobase + USBCMD); + udelay(5); + + // Disable interrupts and commands (just to be safe). + outw(0, cntl->iobase + USBINTR); + outw(0, cntl->iobase + USBCMD); +} + +static void +configure_uhci(void *data) +{ + struct usb_uhci_s *cntl = data; + + // Allocate ram for schedule storage + struct uhci_td *term_td = malloc_high(sizeof(*term_td)); + struct uhci_framelist *fl = memalign_high(sizeof(*fl), sizeof(*fl)); + struct uhci_qh *intr_qh = malloc_high(sizeof(*intr_qh)); + struct uhci_qh *term_qh = malloc_high(sizeof(*term_qh)); + if (!term_td || !fl || !intr_qh || !term_qh) { + warn_noalloc(); + goto fail; + } + + // Work around for PIIX errata + memset(term_td, 0, sizeof(*term_td)); + term_td->link = UHCI_PTR_TERM; + term_td->token = (uhci_explen(0) | (0x7f << TD_TOKEN_DEVADDR_SHIFT) + | USB_PID_IN); + memset(term_qh, 0, sizeof(*term_qh)); + term_qh->element = (u32)term_td; + term_qh->link = UHCI_PTR_TERM; + + // Set schedule to point to primary intr queue head + memset(intr_qh, 0, sizeof(*intr_qh)); + intr_qh->element = UHCI_PTR_TERM; + intr_qh->link = (u32)term_qh | UHCI_PTR_QH; + int i; + for (i=0; ilinks); i++) + fl->links[i] = (u32)intr_qh | UHCI_PTR_QH; + cntl->framelist = fl; + cntl->control_qh = cntl->bulk_qh = intr_qh; + barrier(); + + // Set the frame length to the default: 1 ms exactly + outb(USBSOF_DEFAULT, cntl->iobase + USBSOF); + + // Store the frame list base address + outl((u32)fl->links, cntl->iobase + USBFLBASEADD); + + // Set the current frame number + outw(0, cntl->iobase + USBFRNUM); + + // Mark as configured and running with a 64-byte max packet. + outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, cntl->iobase + USBCMD); + + // Find devices + int count = check_uhci_ports(cntl); + free_pipe(cntl->usb.defaultpipe); + if (count) + // Success + return; + + // No devices found - shutdown and free controller. + outw(0, cntl->iobase + USBCMD); +fail: + free(term_td); + free(fl); + free(intr_qh); + free(term_qh); + free(cntl); +} + +void +uhci_init(struct pci_device *pci, int busid) +{ + if (! CONFIG_USB_UHCI) + return; + u16 bdf = pci->bdf; + struct usb_uhci_s *cntl = malloc_tmphigh(sizeof(*cntl)); + if (!cntl) { + warn_noalloc(); + return; + } + memset(cntl, 0, sizeof(*cntl)); + cntl->usb.busid = busid; + cntl->usb.pci = pci; + cntl->usb.type = USB_TYPE_UHCI; + cntl->iobase = (pci_config_readl(bdf, PCI_BASE_ADDRESS_4) + & PCI_BASE_ADDRESS_IO_MASK); + + dprintf(1, "UHCI init on dev %02x:%02x.%x (io=%x)\n" + , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf) + , pci_bdf_to_fn(bdf), cntl->iobase); + + pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER); + + reset_uhci(cntl, bdf); + + run_thread(configure_uhci, cntl); +} + + +/**************************************************************** + * End point communication + ****************************************************************/ + +static int +wait_qh(struct usb_uhci_s *cntl, struct uhci_qh *qh) +{ + // XXX - 500ms just a guess + u64 end = calc_future_tsc(500); + for (;;) { + if (qh->element & UHCI_PTR_TERM) + return 0; + if (check_tsc(end)) { + warn_timeout(); + struct uhci_td *td = (void*)(qh->element & ~UHCI_PTR_BITS); + dprintf(1, "Timeout on wait_qh %p (td=%p s=%x c=%x/%x)\n" + , qh, td, td->status + , inw(cntl->iobase + USBCMD) + , inw(cntl->iobase + USBSTS)); + return -1; + } + yield(); + } +} + +// Wait for next USB frame to start - for ensuring safe memory release. +static void +uhci_waittick(u16 iobase) +{ + barrier(); + u16 startframe = inw(iobase + USBFRNUM); + u64 end = calc_future_tsc(1000 * 5); + for (;;) { + if (inw(iobase + USBFRNUM) != startframe) + break; + if (check_tsc(end)) { + warn_timeout(); + return; + } + yield(); + } +} + +struct uhci_pipe { + struct uhci_qh qh; + struct uhci_td *next_td; + struct usb_pipe pipe; + u16 iobase; + u8 toggle; +}; + +void +uhci_free_pipe(struct usb_pipe *p) +{ + if (! CONFIG_USB_UHCI) + return; + dprintf(7, "uhci_free_pipe %p\n", p); + struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe); + struct usb_uhci_s *cntl = container_of( + pipe->pipe.cntl, struct usb_uhci_s, usb); + + struct uhci_qh *pos = (void*)(cntl->framelist->links[0] & ~UHCI_PTR_BITS); + for (;;) { + u32 link = pos->link; + if (link == UHCI_PTR_TERM) { + // Not found?! Exit without freeing. + warn_internalerror(); + return; + } + struct uhci_qh *next = (void*)(link & ~UHCI_PTR_BITS); + if (next == &pipe->qh) { + pos->link = next->link; + if (cntl->control_qh == next) + cntl->control_qh = pos; + if (cntl->bulk_qh == next) + cntl->bulk_qh = pos; + uhci_waittick(cntl->iobase); + free(pipe); + return; + } + pos = next; + } +} + +struct usb_pipe * +uhci_alloc_control_pipe(struct usb_pipe *dummy) +{ + if (! CONFIG_USB_UHCI) + return NULL; + struct usb_uhci_s *cntl = container_of( + dummy->cntl, struct usb_uhci_s, usb); + dprintf(7, "uhci_alloc_control_pipe %p\n", &cntl->usb); + + // Allocate a queue head. + struct uhci_pipe *pipe = malloc_tmphigh(sizeof(*pipe)); + if (!pipe) { + warn_noalloc(); + return NULL; + } + memset(pipe, 0, sizeof(*pipe)); + memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe)); + pipe->qh.element = UHCI_PTR_TERM; + pipe->iobase = cntl->iobase; + + // Add queue head to controller list. + struct uhci_qh *control_qh = cntl->control_qh; + pipe->qh.link = control_qh->link; + barrier(); + control_qh->link = (u32)&pipe->qh | UHCI_PTR_QH; + if (cntl->bulk_qh == control_qh) + cntl->bulk_qh = &pipe->qh; + return &pipe->pipe; +} + +int +uhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize + , void *data, int datasize) +{ + ASSERT32FLAT(); + if (! CONFIG_USB_UHCI) + return -1; + dprintf(5, "uhci_control %p\n", p); + struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe); + struct usb_uhci_s *cntl = container_of( + pipe->pipe.cntl, struct usb_uhci_s, usb); + + int maxpacket = pipe->pipe.maxpacket; + int lowspeed = pipe->pipe.speed; + int devaddr = pipe->pipe.devaddr | (pipe->pipe.ep << 7); + + // Setup transfer descriptors + int count = 2 + DIV_ROUND_UP(datasize, maxpacket); + struct uhci_td *tds = malloc_tmphigh(sizeof(*tds) * count); + if (!tds) { + warn_noalloc(); + return -1; + } + + tds[0].link = (u32)&tds[1] | UHCI_PTR_DEPTH; + tds[0].status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0) + | TD_CTRL_ACTIVE); + tds[0].token = (uhci_explen(cmdsize) | (devaddr << TD_TOKEN_DEVADDR_SHIFT) + | USB_PID_SETUP); + tds[0].buffer = (void*)cmd; + int toggle = TD_TOKEN_TOGGLE; + int i; + for (i=1; iqh.element = (u32)&tds[0]; + int ret = wait_qh(cntl, &pipe->qh); + if (ret) { + pipe->qh.element = UHCI_PTR_TERM; + uhci_waittick(pipe->iobase); + } + free(tds); + return ret; +} + +struct usb_pipe * +uhci_alloc_bulk_pipe(struct usb_pipe *dummy) +{ + if (! CONFIG_USB_UHCI) + return NULL; + struct usb_uhci_s *cntl = container_of( + dummy->cntl, struct usb_uhci_s, usb); + dprintf(7, "uhci_alloc_bulk_pipe %p\n", &cntl->usb); + + // Allocate a queue head. + struct uhci_pipe *pipe = malloc_low(sizeof(*pipe)); + if (!pipe) { + warn_noalloc(); + return NULL; + } + memset(pipe, 0, sizeof(*pipe)); + memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe)); + pipe->qh.element = UHCI_PTR_TERM; + pipe->iobase = cntl->iobase; + + // Add queue head to controller list. + struct uhci_qh *bulk_qh = cntl->bulk_qh; + pipe->qh.link = bulk_qh->link; + barrier(); + bulk_qh->link = (u32)&pipe->qh | UHCI_PTR_QH; + + return &pipe->pipe; +} + +static int +wait_td(struct uhci_td *td) +{ + u64 end = calc_future_tsc(5000); // XXX - lookup real time. + u32 status; + for (;;) { + status = td->status; + if (!(status & TD_CTRL_ACTIVE)) + break; + if (check_tsc(end)) { + warn_timeout(); + return -1; + } + yield(); + } + if (status & TD_CTRL_ANY_ERROR) { + dprintf(1, "wait_td error - status=%x\n", status); + return -2; + } + return 0; +} + +#define STACKTDS 4 +#define TDALIGN 16 + +int +uhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize) +{ + if (! CONFIG_USB_UHCI) + return -1; + struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe); + dprintf(7, "uhci_send_bulk qh=%p dir=%d data=%p size=%d\n" + , &pipe->qh, dir, data, datasize); + int maxpacket = GET_FLATPTR(pipe->pipe.maxpacket); + int lowspeed = GET_FLATPTR(pipe->pipe.speed); + int devaddr = (GET_FLATPTR(pipe->pipe.devaddr) + | (GET_FLATPTR(pipe->pipe.ep) << 7)); + int toggle = GET_FLATPTR(pipe->toggle) ? TD_TOKEN_TOGGLE : 0; + + // Allocate 4 tds on stack (16byte aligned) + u8 tdsbuf[sizeof(struct uhci_td) * STACKTDS + TDALIGN - 1]; + struct uhci_td *tds = (void*)ALIGN((u32)tdsbuf, TDALIGN); + memset(tds, 0, sizeof(*tds) * STACKTDS); + + // Enable tds + barrier(); + SET_FLATPTR(pipe->qh.element, (u32)MAKE_FLATPTR(GET_SEG(SS), tds)); + + int tdpos = 0; + while (datasize) { + struct uhci_td *td = &tds[tdpos++ % STACKTDS]; + int ret = wait_td(td); + if (ret) + goto fail; + + int transfer = datasize; + if (transfer > maxpacket) + transfer = maxpacket; + struct uhci_td *nexttd_fl = MAKE_FLATPTR(GET_SEG(SS) + , &tds[tdpos % STACKTDS]); + td->link = (transfer==datasize ? UHCI_PTR_TERM : (u32)nexttd_fl); + td->token = (uhci_explen(transfer) | toggle + | (devaddr << TD_TOKEN_DEVADDR_SHIFT) + | (dir ? USB_PID_IN : USB_PID_OUT)); + td->buffer = data; + barrier(); + td->status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0) + | TD_CTRL_ACTIVE); + toggle ^= TD_TOKEN_TOGGLE; + + data += transfer; + datasize -= transfer; + } + int i; + for (i=0; itoggle, !!toggle); + return 0; +fail: + dprintf(1, "uhci_send_bulk failed\n"); + SET_FLATPTR(pipe->qh.element, UHCI_PTR_TERM); + uhci_waittick(GET_FLATPTR(pipe->iobase)); + return -1; +} + +struct usb_pipe * +uhci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp) +{ + if (! CONFIG_USB_UHCI) + return NULL; + struct usb_uhci_s *cntl = container_of( + dummy->cntl, struct usb_uhci_s, usb); + dprintf(7, "uhci_alloc_intr_pipe %p %d\n", &cntl->usb, frameexp); + + if (frameexp > 10) + frameexp = 10; + int maxpacket = dummy->maxpacket; + int lowspeed = dummy->speed; + int devaddr = dummy->devaddr | (dummy->ep << 7); + // Determine number of entries needed for 2 timer ticks. + int ms = 1<pipe, dummy, sizeof(pipe->pipe)); + pipe->qh.element = (u32)tds; + pipe->next_td = &tds[0]; + pipe->iobase = cntl->iobase; + + int toggle = 0; + int i; + for (i=0; iframelist; + if (frameexp == 0) { + // Add to existing interrupt entry. + struct uhci_qh *intr_qh = (void*)(fl->links[0] & ~UHCI_PTR_BITS); + pipe->qh.link = intr_qh->link; + barrier(); + intr_qh->link = (u32)&pipe->qh | UHCI_PTR_QH; + if (cntl->control_qh == intr_qh) + cntl->control_qh = &pipe->qh; + if (cntl->bulk_qh == intr_qh) + cntl->bulk_qh = &pipe->qh; + } else { + int startpos = 1<<(frameexp-1); + pipe->qh.link = fl->links[startpos]; + barrier(); + for (i=startpos; ilinks); i+=ms) + fl->links[i] = (u32)&pipe->qh | UHCI_PTR_QH; + } + + return &pipe->pipe; +fail: + free(pipe); + free(tds); + free(data); + return NULL; +} + +int +uhci_poll_intr(struct usb_pipe *p, void *data) +{ + ASSERT16(); + if (! CONFIG_USB_UHCI) + return -1; + + struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe); + struct uhci_td *td = GET_FLATPTR(pipe->next_td); + u32 status = GET_FLATPTR(td->status); + u32 token = GET_FLATPTR(td->token); + if (status & TD_CTRL_ACTIVE) + // No intrs found. + return -1; + // XXX - check for errors. + + // Copy data. + void *tddata = GET_FLATPTR(td->buffer); + memcpy_far(GET_SEG(SS), data + , FLATPTR_TO_SEG(tddata), (void*)FLATPTR_TO_OFFSET(tddata) + , uhci_expected_length(token)); + + // Reenable this td. + struct uhci_td *next = (void*)(GET_FLATPTR(td->link) & ~UHCI_PTR_BITS); + SET_FLATPTR(pipe->next_td, next); + barrier(); + SET_FLATPTR(td->status, (uhci_maxerr(0) | (status & TD_CTRL_LS) + | TD_CTRL_ACTIVE)); + + return 0; +} diff --git a/bios/seabios/src/usb-uhci.h b/bios/seabios/src/usb-uhci.h new file mode 100644 index 0000000..b5f70f7 --- /dev/null +++ b/bios/seabios/src/usb-uhci.h @@ -0,0 +1,128 @@ +#ifndef __USB_UHCI_H +#define __USB_UHCI_H + +// usb-uhci.c +void uhci_init(struct pci_device *pci, int busid); +struct usb_pipe; +void uhci_free_pipe(struct usb_pipe *p); +struct usb_pipe *uhci_alloc_control_pipe(struct usb_pipe *dummy); +int uhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize + , void *data, int datasize); +struct usb_pipe *uhci_alloc_bulk_pipe(struct usb_pipe *dummy); +int uhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize); +struct usb_pipe *uhci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp); +int uhci_poll_intr(struct usb_pipe *p, void *data); + + +/**************************************************************** + * uhci structs and flags + ****************************************************************/ + +/* USB port status and control registers */ +#define USBPORTSC1 16 +#define USBPORTSC2 18 +#define USBPORTSC_CCS 0x0001 /* Current Connect Status + * ("device present") */ +#define USBPORTSC_CSC 0x0002 /* Connect Status Change */ +#define USBPORTSC_PE 0x0004 /* Port Enable */ +#define USBPORTSC_PEC 0x0008 /* Port Enable Change */ +#define USBPORTSC_DPLUS 0x0010 /* D+ high (line status) */ +#define USBPORTSC_DMINUS 0x0020 /* D- high (line status) */ +#define USBPORTSC_RD 0x0040 /* Resume Detect */ +#define USBPORTSC_RES1 0x0080 /* reserved, always 1 */ +#define USBPORTSC_LSDA 0x0100 /* Low Speed Device Attached */ +#define USBPORTSC_PR 0x0200 /* Port Reset */ + +/* Legacy support register */ +#define USBLEGSUP 0xc0 +#define USBLEGSUP_RWC 0x8f00 /* the R/WC bits */ + +/* Command register */ +#define USBCMD 0 +#define USBCMD_RS 0x0001 /* Run/Stop */ +#define USBCMD_HCRESET 0x0002 /* Host reset */ +#define USBCMD_GRESET 0x0004 /* Global reset */ +#define USBCMD_EGSM 0x0008 /* Global Suspend Mode */ +#define USBCMD_FGR 0x0010 /* Force Global Resume */ +#define USBCMD_SWDBG 0x0020 /* SW Debug mode */ +#define USBCMD_CF 0x0040 /* Config Flag (sw only) */ +#define USBCMD_MAXP 0x0080 /* Max Packet (0 = 32, 1 = 64) */ + +/* Status register */ +#define USBSTS 2 +#define USBSTS_USBINT 0x0001 /* Interrupt due to IOC */ +#define USBSTS_ERROR 0x0002 /* Interrupt due to error */ +#define USBSTS_RD 0x0004 /* Resume Detect */ +#define USBSTS_HSE 0x0008 /* Host System Error: PCI problems */ +#define USBSTS_HCPE 0x0010 /* Host Controller Process Error: + * the schedule is buggy */ +#define USBSTS_HCH 0x0020 /* HC Halted */ + +/* Interrupt enable register */ +#define USBINTR 4 +#define USBINTR_TIMEOUT 0x0001 /* Timeout/CRC error enable */ +#define USBINTR_RESUME 0x0002 /* Resume interrupt enable */ +#define USBINTR_IOC 0x0004 /* Interrupt On Complete enable */ +#define USBINTR_SP 0x0008 /* Short packet interrupt enable */ + +#define USBFRNUM 6 +#define USBFLBASEADD 8 +#define USBSOF 12 +#define USBSOF_DEFAULT 64 /* Frame length is exactly 1 ms */ + +struct uhci_framelist { + u32 links[1024]; +} PACKED; + +#define TD_CTRL_SPD (1 << 29) /* Short Packet Detect */ +#define TD_CTRL_C_ERR_MASK (3 << 27) /* Error Counter bits */ +#define TD_CTRL_C_ERR_SHIFT 27 +#define TD_CTRL_LS (1 << 26) /* Low Speed Device */ +#define TD_CTRL_IOS (1 << 25) /* Isochronous Select */ +#define TD_CTRL_IOC (1 << 24) /* Interrupt on Complete */ +#define TD_CTRL_ACTIVE (1 << 23) /* TD Active */ +#define TD_CTRL_STALLED (1 << 22) /* TD Stalled */ +#define TD_CTRL_DBUFERR (1 << 21) /* Data Buffer Error */ +#define TD_CTRL_BABBLE (1 << 20) /* Babble Detected */ +#define TD_CTRL_NAK (1 << 19) /* NAK Received */ +#define TD_CTRL_CRCTIMEO (1 << 18) /* CRC/Time Out Error */ +#define TD_CTRL_BITSTUFF (1 << 17) /* Bit Stuff Error */ +#define TD_CTRL_ACTLEN_MASK 0x7FF /* actual length, encoded as n - 1 */ + +#define TD_CTRL_ANY_ERROR (TD_CTRL_STALLED | TD_CTRL_DBUFERR | \ + TD_CTRL_BABBLE | TD_CTRL_CRCTIMEO | \ + TD_CTRL_BITSTUFF) +#define uhci_maxerr(err) ((err) << TD_CTRL_C_ERR_SHIFT) + +#define TD_TOKEN_DEVADDR_SHIFT 8 +#define TD_TOKEN_TOGGLE_SHIFT 19 +#define TD_TOKEN_TOGGLE (1 << 19) +#define TD_TOKEN_EXPLEN_SHIFT 21 +#define TD_TOKEN_EXPLEN_MASK 0x7FF /* expected length, encoded as n-1 */ +#define TD_TOKEN_PID_MASK 0xFF + +#define uhci_explen(len) ((((len) - 1) & TD_TOKEN_EXPLEN_MASK) << \ + TD_TOKEN_EXPLEN_SHIFT) + +#define uhci_expected_length(token) ((((token) >> TD_TOKEN_EXPLEN_SHIFT) + \ + 1) & TD_TOKEN_EXPLEN_MASK) + +struct uhci_td { + u32 link; + u32 status; + u32 token; + void *buffer; +} PACKED; + +struct uhci_qh { + u32 link; + u32 element; +} PACKED; + +#define UHCI_PTR_BITS 0x000F +#define UHCI_PTR_TERM 0x0001 +#define UHCI_PTR_QH 0x0002 +#define UHCI_PTR_DEPTH 0x0004 +#define UHCI_PTR_BREADTH 0x0000 + +#endif // usb-uhci.h diff --git a/bios/seabios/src/usb.c b/bios/seabios/src/usb.c new file mode 100644 index 0000000..1f69d16 --- /dev/null +++ b/bios/seabios/src/usb.c @@ -0,0 +1,468 @@ +// Main code for handling USB controllers and devices. +// +// Copyright (C) 2009 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // dprintf +#include "pci.h" // foreachpci +#include "config.h" // CONFIG_* +#include "pci_regs.h" // PCI_CLASS_REVISION +#include "pci_ids.h" // PCI_CLASS_SERIAL_USB_UHCI +#include "usb-uhci.h" // uhci_init +#include "usb-ohci.h" // ohci_init +#include "usb-ehci.h" // ehci_init +#include "usb-hid.h" // usb_keyboard_setup +#include "usb-hub.h" // usb_hub_init +#include "usb-msc.h" // usb_msc_init +#include "usb.h" // struct usb_s +#include "biosvar.h" // GET_GLOBAL + + +/**************************************************************** + * Controller function wrappers + ****************************************************************/ + +// Free an allocated control or bulk pipe. +void +free_pipe(struct usb_pipe *pipe) +{ + ASSERT32FLAT(); + if (!pipe) + return; + switch (pipe->type) { + default: + case USB_TYPE_UHCI: + return uhci_free_pipe(pipe); + case USB_TYPE_OHCI: + return ohci_free_pipe(pipe); + case USB_TYPE_EHCI: + return ehci_free_pipe(pipe); + } +} + +// Allocate a control pipe to a default endpoint (which can only be +// used by 32bit code) +static struct usb_pipe * +alloc_default_control_pipe(struct usb_pipe *dummy) +{ + switch (dummy->type) { + default: + case USB_TYPE_UHCI: + return uhci_alloc_control_pipe(dummy); + case USB_TYPE_OHCI: + return ohci_alloc_control_pipe(dummy); + case USB_TYPE_EHCI: + return ehci_alloc_control_pipe(dummy); + } +} + +// Send a message on a control pipe using the default control descriptor. +static int +send_control(struct usb_pipe *pipe, int dir, const void *cmd, int cmdsize + , void *data, int datasize) +{ + ASSERT32FLAT(); + switch (pipe->type) { + default: + case USB_TYPE_UHCI: + return uhci_control(pipe, dir, cmd, cmdsize, data, datasize); + case USB_TYPE_OHCI: + return ohci_control(pipe, dir, cmd, cmdsize, data, datasize); + case USB_TYPE_EHCI: + return ehci_control(pipe, dir, cmd, cmdsize, data, datasize); + } +} + +// Fill "pipe" endpoint info from an endpoint descriptor. +static void +desc2pipe(struct usb_pipe *newpipe, struct usb_pipe *origpipe + , struct usb_endpoint_descriptor *epdesc) +{ + memcpy(newpipe, origpipe, sizeof(*newpipe)); + newpipe->ep = epdesc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + newpipe->maxpacket = epdesc->wMaxPacketSize; +} + +struct usb_pipe * +alloc_bulk_pipe(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc) +{ + struct usb_pipe dummy; + desc2pipe(&dummy, pipe, epdesc); + switch (pipe->type) { + default: + case USB_TYPE_UHCI: + return uhci_alloc_bulk_pipe(&dummy); + case USB_TYPE_OHCI: + return ohci_alloc_bulk_pipe(&dummy); + case USB_TYPE_EHCI: + return ehci_alloc_bulk_pipe(&dummy); + } +} + +int +usb_send_bulk(struct usb_pipe *pipe_fl, int dir, void *data, int datasize) +{ + switch (GET_FLATPTR(pipe_fl->type)) { + default: + case USB_TYPE_UHCI: + return uhci_send_bulk(pipe_fl, dir, data, datasize); + case USB_TYPE_OHCI: + return ohci_send_bulk(pipe_fl, dir, data, datasize); + case USB_TYPE_EHCI: + return ehci_send_bulk(pipe_fl, dir, data, datasize); + } +} + +struct usb_pipe * +alloc_intr_pipe(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc) +{ + struct usb_pipe dummy; + desc2pipe(&dummy, pipe, epdesc); + // Find the exponential period of the requested time. + int period = epdesc->bInterval; + int frameexp; + if (pipe->speed != USB_HIGHSPEED) + frameexp = (period <= 0) ? 0 : __fls(period); + else + frameexp = (period <= 4) ? 0 : period - 4; + switch (pipe->type) { + default: + case USB_TYPE_UHCI: + return uhci_alloc_intr_pipe(&dummy, frameexp); + case USB_TYPE_OHCI: + return ohci_alloc_intr_pipe(&dummy, frameexp); + case USB_TYPE_EHCI: + return ehci_alloc_intr_pipe(&dummy, frameexp); + } +} + +int noinline +usb_poll_intr(struct usb_pipe *pipe_fl, void *data) +{ + switch (GET_FLATPTR(pipe_fl->type)) { + default: + case USB_TYPE_UHCI: + return uhci_poll_intr(pipe_fl, data); + case USB_TYPE_OHCI: + return ohci_poll_intr(pipe_fl, data); + case USB_TYPE_EHCI: + return ehci_poll_intr(pipe_fl, data); + } +} + + +/**************************************************************** + * Helper functions + ****************************************************************/ + +// Find the first endpoing of a given type in an interface description. +struct usb_endpoint_descriptor * +findEndPointDesc(struct usb_interface_descriptor *iface, int imax + , int type, int dir) +{ + struct usb_endpoint_descriptor *epdesc = (void*)&iface[1]; + for (;;) { + if ((void*)epdesc >= (void*)iface + imax + || epdesc->bDescriptorType == USB_DT_INTERFACE) { + return NULL; + } + if (epdesc->bDescriptorType == USB_DT_ENDPOINT + && (epdesc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == dir + && (epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == type) + return epdesc; + epdesc = (void*)epdesc + epdesc->bLength; + } +} + +// Send a message to the default control pipe of a device. +int +send_default_control(struct usb_pipe *pipe, const struct usb_ctrlrequest *req + , void *data) +{ + return send_control(pipe, req->bRequestType & USB_DIR_IN + , req, sizeof(*req), data, req->wLength); +} + +// Get the first 8 bytes of the device descriptor. +static int +get_device_info8(struct usb_pipe *pipe, struct usb_device_descriptor *dinfo) +{ + struct usb_ctrlrequest req; + req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; + req.bRequest = USB_REQ_GET_DESCRIPTOR; + req.wValue = USB_DT_DEVICE<<8; + req.wIndex = 0; + req.wLength = 8; + return send_default_control(pipe, &req, dinfo); +} + +static struct usb_config_descriptor * +get_device_config(struct usb_pipe *pipe) +{ + struct usb_config_descriptor cfg; + + struct usb_ctrlrequest req; + req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; + req.bRequest = USB_REQ_GET_DESCRIPTOR; + req.wValue = USB_DT_CONFIG<<8; + req.wIndex = 0; + req.wLength = sizeof(cfg); + int ret = send_default_control(pipe, &req, &cfg); + if (ret) + return NULL; + + void *config = malloc_tmphigh(cfg.wTotalLength); + if (!config) + return NULL; + req.wLength = cfg.wTotalLength; + ret = send_default_control(pipe, &req, config); + if (ret) + return NULL; + //hexdump(config, cfg.wTotalLength); + return config; +} + +static int +set_configuration(struct usb_pipe *pipe, u16 val) +{ + struct usb_ctrlrequest req; + req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE; + req.bRequest = USB_REQ_SET_CONFIGURATION; + req.wValue = val; + req.wIndex = 0; + req.wLength = 0; + return send_default_control(pipe, &req, NULL); +} + + +/**************************************************************** + * Initialization and enumeration + ****************************************************************/ + +// Assign an address to a device in the default state on the given +// controller. +static struct usb_pipe * +usb_set_address(struct usbhub_s *hub, int port, int speed) +{ + ASSERT32FLAT(); + struct usb_s *cntl = hub->cntl; + dprintf(3, "set_address %p\n", cntl); + if (cntl->maxaddr >= USB_MAXADDR) + return NULL; + + struct usb_pipe *defpipe = cntl->defaultpipe; + if (!defpipe) { + // Create a pipe for the default address. + struct usb_pipe dummy; + memset(&dummy, 0, sizeof(dummy)); + dummy.cntl = cntl; + dummy.type = cntl->type; + dummy.maxpacket = 8; + dummy.path = (u64)-1; + cntl->defaultpipe = defpipe = alloc_default_control_pipe(&dummy); + if (!defpipe) + return NULL; + } + defpipe->speed = speed; + if (hub->pipe) { + if (hub->pipe->speed == USB_HIGHSPEED) { + defpipe->tt_devaddr = hub->pipe->devaddr; + defpipe->tt_port = port; + } else { + defpipe->tt_devaddr = hub->pipe->tt_devaddr; + defpipe->tt_port = hub->pipe->tt_port; + } + } else { + defpipe->tt_devaddr = defpipe->tt_port = 0; + } + + msleep(USB_TIME_RSTRCY); + + struct usb_ctrlrequest req; + req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE; + req.bRequest = USB_REQ_SET_ADDRESS; + req.wValue = cntl->maxaddr + 1; + req.wIndex = 0; + req.wLength = 0; + int ret = send_default_control(defpipe, &req, NULL); + if (ret) + return NULL; + + msleep(USB_TIME_SETADDR_RECOVERY); + + cntl->maxaddr++; + defpipe->devaddr = cntl->maxaddr; + struct usb_pipe *pipe = alloc_default_control_pipe(defpipe); + defpipe->devaddr = 0; + if (hub->pipe) + pipe->path = hub->pipe->path; + pipe->path = (pipe->path << 8) | port; + return pipe; +} + +// Called for every found device - see if a driver is available for +// this device and do setup if so. +static int +configure_usb_device(struct usb_pipe *pipe) +{ + ASSERT32FLAT(); + dprintf(3, "config_usb: %p\n", pipe); + + // Set the max packet size for endpoint 0 of this device. + struct usb_device_descriptor dinfo; + int ret = get_device_info8(pipe, &dinfo); + if (ret) + return 0; + dprintf(3, "device rev=%04x cls=%02x sub=%02x proto=%02x size=%02x\n" + , dinfo.bcdUSB, dinfo.bDeviceClass, dinfo.bDeviceSubClass + , dinfo.bDeviceProtocol, dinfo.bMaxPacketSize0); + if (dinfo.bMaxPacketSize0 < 8 || dinfo.bMaxPacketSize0 > 64) + return 0; + pipe->maxpacket = dinfo.bMaxPacketSize0; + + // Get configuration + struct usb_config_descriptor *config = get_device_config(pipe); + if (!config) + return 0; + + // Determine if a driver exists for this device - only look at the + // first interface of the first configuration. + struct usb_interface_descriptor *iface = (void*)(&config[1]); + if (iface->bInterfaceClass != USB_CLASS_HID + && iface->bInterfaceClass != USB_CLASS_MASS_STORAGE + && iface->bInterfaceClass != USB_CLASS_HUB) + // Not a supported device. + goto fail; + + // Set the configuration. + ret = set_configuration(pipe, config->bConfigurationValue); + if (ret) + goto fail; + + // Configure driver. + int imax = (void*)config + config->wTotalLength - (void*)iface; + if (iface->bInterfaceClass == USB_CLASS_HUB) + ret = usb_hub_init(pipe); + else if (iface->bInterfaceClass == USB_CLASS_MASS_STORAGE) + ret = usb_msc_init(pipe, iface, imax); + else + ret = usb_hid_init(pipe, iface, imax); + if (ret) + goto fail; + + free(config); + return 1; +fail: + free(config); + return 0; +} + +static void +usb_init_hub_port(void *data) +{ + struct usbhub_s *hub = data; + u32 port = hub->port; // XXX - find better way to pass port + + // Detect if device present (and possibly start reset) + int ret = hub->op->detect(hub, port); + if (ret) + // No device present + goto done; + + // Reset port and determine device speed + mutex_lock(&hub->cntl->resetlock); + ret = hub->op->reset(hub, port); + if (ret < 0) + // Reset failed + goto resetfail; + + // Set address of port + struct usb_pipe *pipe = usb_set_address(hub, port, ret); + if (!pipe) { + hub->op->disconnect(hub, port); + goto resetfail; + } + mutex_unlock(&hub->cntl->resetlock); + + // Configure the device + int count = configure_usb_device(pipe); + free_pipe(pipe); + if (!count) + hub->op->disconnect(hub, port); + hub->devcount += count; +done: + hub->threads--; + return; + +resetfail: + mutex_unlock(&hub->cntl->resetlock); + goto done; +} + +void +usb_enumerate(struct usbhub_s *hub) +{ + u32 portcount = hub->portcount; + hub->threads = portcount; + + // Launch a thread for every port. + int i; + for (i=0; iport = i; + run_thread(usb_init_hub_port, hub); + } + + // Wait for threads to complete. + while (hub->threads) + yield(); +} + +void +usb_setup(void) +{ + ASSERT32FLAT(); + if (! CONFIG_USB) + return; + + dprintf(3, "init usb\n"); + + // Look for USB controllers + int count = 0; + struct pci_device *ehcipci = PCIDevices; + struct pci_device *pci; + foreachpci(pci) { + if (pci->class != PCI_CLASS_SERIAL_USB) + continue; + + if (pci->bdf >= ehcipci->bdf) { + // Check to see if this device has an ehci controller + int found = 0; + ehcipci = pci; + for (;;) { + if (pci_classprog(ehcipci) == PCI_CLASS_SERIAL_USB_EHCI) { + // Found an ehci controller. + int ret = ehci_init(ehcipci, count++, pci); + if (ret) + // Error + break; + count += found; + pci = ehcipci; + break; + } + if (ehcipci->class == PCI_CLASS_SERIAL_USB) + found++; + ehcipci = ehcipci->next; + if (!ehcipci || (pci_bdf_to_busdev(ehcipci->bdf) + != pci_bdf_to_busdev(pci->bdf))) + // No ehci controller found. + break; + } + } + + if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_UHCI) + uhci_init(pci, count++); + else if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_OHCI) + ohci_init(pci, count++); + } +} diff --git a/bios/seabios/src/usb.h b/bios/seabios/src/usb.h new file mode 100644 index 0000000..8b2af40 --- /dev/null +++ b/bios/seabios/src/usb.h @@ -0,0 +1,216 @@ +// USB functions and data. +#ifndef __USB_H +#define __USB_H + +#include "util.h" // struct mutex_s + +// Information on a USB end point. +struct usb_pipe { + struct usb_s *cntl; + u64 path; + u8 type; + u8 ep; + u8 devaddr; + u8 speed; + u16 maxpacket; + u8 tt_devaddr; + u8 tt_port; +}; + +// Common information for usb controllers. +struct usb_s { + struct usb_pipe *defaultpipe; + struct mutex_s resetlock; + struct pci_device *pci; + int busid; + u8 type; + u8 maxaddr; +}; + +// Information for enumerating USB hubs +struct usbhub_s { + struct usbhub_op_s *op; + struct usb_pipe *pipe; + struct usb_s *cntl; + struct mutex_s lock; + u32 powerwait; + u32 port; + u32 threads; + u32 portcount; + u32 devcount; +}; + +// Hub callback (32bit) info +struct usbhub_op_s { + int (*detect)(struct usbhub_s *hub, u32 port); + int (*reset)(struct usbhub_s *hub, u32 port); + void (*disconnect)(struct usbhub_s *hub, u32 port); +}; + +#define USB_TYPE_UHCI 1 +#define USB_TYPE_OHCI 2 +#define USB_TYPE_EHCI 3 + +#define USB_FULLSPEED 0 +#define USB_LOWSPEED 1 +#define USB_HIGHSPEED 2 + +#define USB_MAXADDR 127 + + +/**************************************************************** + * usb structs and flags + ****************************************************************/ + +// USB mandated timings (in ms) +#define USB_TIME_SIGATT 100 +#define USB_TIME_ATTDB 100 +#define USB_TIME_DRST 10 +#define USB_TIME_DRSTR 50 +#define USB_TIME_RSTRCY 10 + +#define USB_TIME_SETADDR_RECOVERY 2 + +#define USB_PID_OUT 0xe1 +#define USB_PID_IN 0x69 +#define USB_PID_SETUP 0x2d + +#define USB_DIR_OUT 0 /* to device */ +#define USB_DIR_IN 0x80 /* to host */ + +#define USB_TYPE_MASK (0x03 << 5) +#define USB_TYPE_STANDARD (0x00 << 5) +#define USB_TYPE_CLASS (0x01 << 5) +#define USB_TYPE_VENDOR (0x02 << 5) +#define USB_TYPE_RESERVED (0x03 << 5) + +#define USB_RECIP_MASK 0x1f +#define USB_RECIP_DEVICE 0x00 +#define USB_RECIP_INTERFACE 0x01 +#define USB_RECIP_ENDPOINT 0x02 +#define USB_RECIP_OTHER 0x03 + +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C + +struct usb_ctrlrequest { + u8 bRequestType; + u8 bRequest; + u16 wValue; + u16 wIndex; + u16 wLength; +} PACKED; + +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 +#define USB_DT_DEVICE_QUALIFIER 0x06 +#define USB_DT_OTHER_SPEED_CONFIG 0x07 + +struct usb_device_descriptor { + u8 bLength; + u8 bDescriptorType; + + u16 bcdUSB; + u8 bDeviceClass; + u8 bDeviceSubClass; + u8 bDeviceProtocol; + u8 bMaxPacketSize0; + u16 idVendor; + u16 idProduct; + u16 bcdDevice; + u8 iManufacturer; + u8 iProduct; + u8 iSerialNumber; + u8 bNumConfigurations; +} PACKED; + +#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */ +#define USB_CLASS_AUDIO 1 +#define USB_CLASS_COMM 2 +#define USB_CLASS_HID 3 +#define USB_CLASS_PHYSICAL 5 +#define USB_CLASS_STILL_IMAGE 6 +#define USB_CLASS_PRINTER 7 +#define USB_CLASS_MASS_STORAGE 8 +#define USB_CLASS_HUB 9 + +struct usb_config_descriptor { + u8 bLength; + u8 bDescriptorType; + + u16 wTotalLength; + u8 bNumInterfaces; + u8 bConfigurationValue; + u8 iConfiguration; + u8 bmAttributes; + u8 bMaxPower; +} PACKED; + +struct usb_interface_descriptor { + u8 bLength; + u8 bDescriptorType; + + u8 bInterfaceNumber; + u8 bAlternateSetting; + u8 bNumEndpoints; + u8 bInterfaceClass; + u8 bInterfaceSubClass; + u8 bInterfaceProtocol; + u8 iInterface; +} PACKED; + +struct usb_endpoint_descriptor { + u8 bLength; + u8 bDescriptorType; + + u8 bEndpointAddress; + u8 bmAttributes; + u16 wMaxPacketSize; + u8 bInterval; +} PACKED; + +#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */ +#define USB_ENDPOINT_DIR_MASK 0x80 + +#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */ +#define USB_ENDPOINT_XFER_CONTROL 0 +#define USB_ENDPOINT_XFER_ISOC 1 +#define USB_ENDPOINT_XFER_BULK 2 +#define USB_ENDPOINT_XFER_INT 3 +#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80 + + +/**************************************************************** + * function defs + ****************************************************************/ + +// usb.c +void usb_setup(void); +void usb_enumerate(struct usbhub_s *hub); +int send_default_control(struct usb_pipe *pipe, const struct usb_ctrlrequest *req + , void *data); +int usb_send_bulk(struct usb_pipe *pipe, int dir, void *data, int datasize); +void free_pipe(struct usb_pipe *pipe); +struct usb_pipe *alloc_bulk_pipe(struct usb_pipe *pipe + , struct usb_endpoint_descriptor *epdesc); +struct usb_pipe *alloc_intr_pipe(struct usb_pipe *pipe + , struct usb_endpoint_descriptor *epdesc); +int usb_poll_intr(struct usb_pipe *pipe, void *data); +struct usb_endpoint_descriptor *findEndPointDesc( + struct usb_interface_descriptor *iface, int imax, int type, int dir); +u32 mkendpFromDesc(struct usb_pipe *pipe + , struct usb_endpoint_descriptor *epdesc); + +#endif // usb.h diff --git a/bios/seabios/src/util.c b/bios/seabios/src/util.c new file mode 100644 index 0000000..ed73d63 --- /dev/null +++ b/bios/seabios/src/util.c @@ -0,0 +1,324 @@ +// Misc utility functions. +// +// Copyright (C) 2008,2009 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // call16 +#include "bregs.h" // struct bregs +#include "config.h" // BUILD_STACK_ADDR + + +/**************************************************************** + * 16bit calls + ****************************************************************/ + +// Call a function with a specified register state. Note that on +// return, the interrupt enable/disable flag may be altered. +inline void +call16(struct bregs *callregs) +{ + if (!MODESEGMENT && getesp() > BUILD_STACK_ADDR) + panic("call16 with invalid stack\n"); + asm volatile( +#if MODE16 == 1 + "calll __call16\n" + "cli\n" + "cld" +#else + "calll __call16_from32" +#endif + : "+a" (callregs), "+m" (*callregs) + : + : "ebx", "ecx", "edx", "esi", "edi", "cc", "memory"); +} + +inline void +call16big(struct bregs *callregs) +{ + ASSERT32FLAT(); + if (getesp() > BUILD_STACK_ADDR) + panic("call16 with invalid stack\n"); + asm volatile( + "calll __call16big_from32" + : "+a" (callregs), "+m" (*callregs) + : + : "ebx", "ecx", "edx", "esi", "edi", "cc", "memory"); +} + +inline void +__call16_int(struct bregs *callregs, u16 offset) +{ + if (MODESEGMENT) + callregs->code.seg = GET_SEG(CS); + else + callregs->code.seg = SEG_BIOS; + callregs->code.offset = offset; + call16(callregs); +} + + +/**************************************************************** + * String ops + ****************************************************************/ + +// Sum the bytes in the specified area. +u8 +checksum_far(u16 buf_seg, void *buf_far, u32 len) +{ + SET_SEG(ES, buf_seg); + u32 i; + u8 sum = 0; + for (i=0; i 3) { + u32 copylen = len; + if (copylen > 2048) + copylen = 2048; + copylen /= 4; + len -= copylen * 4; + asm volatile( + "rep movsl (%%esi),%%es:(%%edi)" + : "+c"(copylen), "+S"(s), "+D"(d) + : : "cc", "memory"); + yield(); + } + if (len) + // Copy any remaining bytes. + memcpy(d, s, len); +} + +void * +memmove(void *d, const void *s, size_t len) +{ + if (s >= d) + return memcpy(d, s, len); + + d += len-1; + s += len-1; + while (len--) { + *(char*)d = *(char*)s; + d--; + s--; + } + + return d; +} + +// Copy a string - truncating it if necessary. +char * +strtcpy(char *dest, const char *src, size_t len) +{ + char *d = dest; + while (--len && *src != '\0') + *d++ = *src++; + *d = '\0'; + return dest; +} + +// locate first occurance of character c in the string s +char * +strchr(const char *s, int c) +{ + for (; *s; s++) + if (*s == c) + return (char*)s; + return NULL; +} + +// Remove any trailing blank characters (spaces, new lines, carriage returns) +void +nullTrailingSpace(char *buf) +{ + int len = strlen(buf); + char *end = &buf[len-1]; + while (end >= buf && *end <= ' ') + *(end--) = '\0'; +} + +/**************************************************************** + * Keyboard calls + ****************************************************************/ + +// See if a keystroke is pending in the keyboard buffer. +static int +check_for_keystroke(void) +{ + struct bregs br; + memset(&br, 0, sizeof(br)); + br.flags = F_IF; + br.ah = 1; + call16_int(0x16, &br); + return !(br.flags & F_ZF); +} + +// Return a keystroke - waiting forever if necessary. +static int +get_raw_keystroke(void) +{ + struct bregs br; + memset(&br, 0, sizeof(br)); + br.flags = F_IF; + call16_int(0x16, &br); + return br.ah; +} + +// Read a keystroke - waiting up to 'msec' milliseconds. +int +get_keystroke(int msec) +{ + u32 end = calc_future_timer(msec); + for (;;) { + if (check_for_keystroke()) + return get_raw_keystroke(); + if (check_timer(end)) + return -1; + wait_irq(); + } +} diff --git a/bios/seabios/src/util.h b/bios/seabios/src/util.h new file mode 100644 index 0000000..174e94b --- /dev/null +++ b/bios/seabios/src/util.h @@ -0,0 +1,484 @@ +// Basic x86 asm functions and function defs. +// +// Copyright (C) 2008-2010 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. +#ifndef __UTIL_H +#define __UTIL_H + +#include "types.h" // u32 + +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): :"memory"); + irq_disable(); + return flags; +} + +static inline void irq_restore(unsigned long flags) +{ + asm volatile("pushl %0 ; popfl" : : "g" (flags) : "memory", "cc"); +} + +static inline void cpu_relax(void) +{ + asm volatile("rep ; nop": : :"memory"); +} + +static inline void nop(void) +{ + asm volatile("nop"); +} + +static inline void hlt(void) +{ + asm volatile("hlt": : :"memory"); +} + +static inline void wbinvd(void) +{ + asm volatile("wbinvd": : :"memory"); +} + +#define CPUID_MSR (1 << 5) +#define CPUID_APIC (1 << 9) +#define CPUID_MTRR (1 << 12) +static inline void cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx) +{ + asm("cpuid" + : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) + : "0" (index)); +} + +static inline u32 getcr0(void) { + u32 cr0; + asm("movl %%cr0, %0" : "=r"(cr0)); + return cr0; +} +static inline void setcr0(u32 cr0) { + asm("movl %0, %%cr0" : : "r"(cr0)); +} + +static inline u64 rdmsr(u32 index) +{ + u64 ret; + asm ("rdmsr" : "=A"(ret) : "c"(index)); + return ret; +} + +static inline void wrmsr(u32 index, u64 val) +{ + asm volatile ("wrmsr" : : "c"(index), "A"(val)); +} + +static inline u64 rdtscll(void) +{ + u64 val; + asm volatile("rdtsc" : "=A" (val)); + return val; +} + +static inline u32 __ffs(u32 word) +{ + asm("bsf %1,%0" + : "=r" (word) + : "rm" (word)); + return word; +} +static inline u32 __fls(u32 word) +{ + asm("bsr %1,%0" + : "=r" (word) + : "rm" (word)); + return word; +} + +static inline u16 __htons_constant(u16 val) { + return (val<<8) | (val>>8); +} +static inline u32 __htonl_constant(u32 val) { + return (val<<24) | ((val&0xff00)<<8) | ((val&0xff0000)>>8) | (val>>24); +} +static inline u32 __htonl(u32 val) { + asm("bswapl %0" : "+r"(val)); + return val; +} +#define htonl(x) (__builtin_constant_p((u32)(x)) ? __htonl_constant(x) : __htonl(x)) +#define ntohl(x) htonl(x) +#define htons(x) __htons_constant(x) +#define ntohs(x) htons(x) + +static inline u16 cpu_to_le16(u16 x) +{ + return x; +} + +static inline u32 cpu_to_le32(u32 x) +{ + return x; +} + +static inline u32 getesp(void) { + u32 esp; + asm("movl %%esp, %0" : "=rm"(esp)); + return esp; +} + +static inline void writel(void *addr, u32 val) { + *(volatile u32 *)addr = val; +} +static inline void writew(void *addr, u16 val) { + *(volatile u16 *)addr = val; +} +static inline void writeb(void *addr, u8 val) { + *(volatile u8 *)addr = val; +} +static inline u32 readl(const void *addr) { + return *(volatile const u32 *)addr; +} +static inline u16 readw(const void *addr) { + return *(volatile const u16 *)addr; +} +static inline u8 readb(const void *addr) { + return *(volatile const u8 *)addr; +} + +#define call16_simpint(nr, peax, pflags) do { \ + ASSERT16(); \ + asm volatile( \ + "pushl %%ebp\n" \ + "sti\n" \ + "stc\n" \ + "int %2\n" \ + "pushfl\n" \ + "popl %1\n" \ + "cli\n" \ + "cld\n" \ + "popl %%ebp" \ + : "+a"(*peax), "=c"(*pflags) \ + : "i"(nr) \ + : "ebx", "edx", "esi", "edi", "cc", "memory"); \ + } while (0) + +// GDT bits +#define GDT_CODE (0x9bULL << 40) // Code segment - P,R,A bits also set +#define GDT_DATA (0x93ULL << 40) // Data segment - W,A bits also set +#define GDT_B (0x1ULL << 54) // Big flag +#define GDT_G (0x1ULL << 55) // Granularity flag +// GDT bits for segment base +#define GDT_BASE(v) ((((u64)(v) & 0xff000000) << 32) \ + | (((u64)(v) & 0x00ffffff) << 16)) +// GDT bits for segment limit (0-1Meg) +#define GDT_LIMIT(v) ((((u64)(v) & 0x000f0000) << 32) \ + | (((u64)(v) & 0x0000ffff) << 0)) +// GDT bits for segment limit (0-4Gig in 4K chunks) +#define GDT_GRANLIMIT(v) (GDT_G | GDT_LIMIT((v) >> 12)) + +struct descloc_s { + u16 length; + u32 addr; +} PACKED; + +// util.c +struct bregs; +inline void call16(struct bregs *callregs); +inline void call16big(struct bregs *callregs); +inline void __call16_int(struct bregs *callregs, u16 offset); +#define call16_int(nr, callregs) do { \ + extern void irq_trampoline_ ##nr (); \ + __call16_int((callregs), (u32)&irq_trampoline_ ##nr ); \ + } while (0) +u8 checksum_far(u16 buf_seg, void *buf_far, u32 len); +u8 checksum(void *buf, u32 len); +size_t strlen(const char *s); +int memcmp(const void *s1, const void *s2, size_t n); +int strcmp(const char *s1, const char *s2); +inline void memset_far(u16 d_seg, void *d_far, u8 c, size_t len); +inline void memset16_far(u16 d_seg, void *d_far, u16 c, size_t len); +void *memset(void *s, int c, size_t n); +void memset_fl(void *ptr, u8 val, size_t size); +inline void memcpy_far(u16 d_seg, void *d_far + , u16 s_seg, const void *s_far, size_t len); +void memcpy_fl(void *d_fl, const void *s_fl, size_t len); +void *memcpy(void *d1, const void *s1, size_t len); +#if MODESEGMENT == 0 +#define memcpy __builtin_memcpy +#endif +void iomemcpy(void *d, const void *s, u32 len); +void *memmove(void *d, const void *s, size_t len); +char *strtcpy(char *dest, const char *src, size_t len); +char *strchr(const char *s, int c); +void nullTrailingSpace(char *buf); +int get_keystroke(int msec); + +// stacks.c +u32 call32(void *func, u32 eax, u32 errret); +inline u32 stack_hop(u32 eax, u32 edx, void *func); +extern struct thread_info MainThread; +extern int CanPreempt; +struct thread_info *getCurThread(void); +void yield(void); +void wait_irq(void); +void run_thread(void (*func)(void*), void *data); +void wait_threads(void); +struct mutex_s { u32 isLocked; }; +void mutex_lock(struct mutex_s *mutex); +void mutex_unlock(struct mutex_s *mutex); +void start_preempt(void); +void finish_preempt(void); +int wait_preempt(void); +void check_preempt(void); + +// output.c +void debug_serial_setup(void); +void panic(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))) __noreturn; +void printf(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); +int snprintf(char *str, size_t size, const char *fmt, ...) + __attribute__ ((format (printf, 3, 4))); +char * znprintf(size_t size, const char *fmt, ...) + __attribute__ ((format (printf, 2, 3))); +void __dprintf(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); +void __debug_enter(struct bregs *regs, const char *fname); +void __debug_isr(const char *fname); +void __debug_stub(struct bregs *regs, int lineno, const char *fname); +void __warn_invalid(struct bregs *regs, int lineno, const char *fname); +void __warn_unimplemented(struct bregs *regs, int lineno, const char *fname); +void __warn_internalerror(int lineno, const char *fname); +void __warn_noalloc(int lineno, const char *fname); +void __warn_timeout(int lineno, const char *fname); +void __set_invalid(struct bregs *regs, int lineno, const char *fname); +void __set_unimplemented(struct bregs *regs, int lineno, const char *fname); +void __set_code_invalid(struct bregs *regs, u32 linecode, const char *fname); +void __set_code_unimplemented(struct bregs *regs, u32 linecode + , const char *fname); +void hexdump(const void *d, int len); + +#define dprintf(lvl, fmt, args...) do { \ + if (CONFIG_DEBUG_LEVEL && (lvl) <= CONFIG_DEBUG_LEVEL) \ + __dprintf((fmt) , ##args ); \ + } while (0) +#define debug_enter(regs, lvl) do { \ + if ((lvl) && (lvl) <= CONFIG_DEBUG_LEVEL) \ + __debug_enter((regs), __func__); \ + } while (0) +#define debug_isr(lvl) do { \ + if ((lvl) && (lvl) <= CONFIG_DEBUG_LEVEL) \ + __debug_isr(__func__); \ + } while (0) +#define debug_stub(regs) \ + __debug_stub((regs), __LINE__, __func__) +#define warn_invalid(regs) \ + __warn_invalid((regs), __LINE__, __func__) +#define warn_unimplemented(regs) \ + __warn_unimplemented((regs), __LINE__, __func__) +#define warn_internalerror() \ + __warn_internalerror(__LINE__, __func__) +#define warn_noalloc() \ + __warn_noalloc(__LINE__, __func__) +#define warn_timeout() \ + __warn_timeout(__LINE__, __func__) +#define set_invalid(regs) \ + __set_invalid((regs), __LINE__, __func__) +#define set_code_invalid(regs, code) \ + __set_code_invalid((regs), (code) | (__LINE__ << 8), __func__) +#define set_unimplemented(regs) \ + __set_unimplemented((regs), __LINE__, __func__) +#define set_code_unimplemented(regs, code) \ + __set_code_unimplemented((regs), (code) | (__LINE__ << 8), __func__) + +// kbd.c +void kbd_setup(void); +void handle_15c2(struct bregs *regs); +void process_key(u8 key); + +// mouse.c +void mouse_setup(void); +void process_mouse(u8 data); + +// system.c +extern u32 RamSize; +extern u64 RamSizeOver4G; +void mathcp_setup(void); + +// serial.c +void serial_setup(void); +void lpt_setup(void); + +// clock.c +#define PIT_TICK_RATE 1193180 // Underlying HZ of PIT +#define PIT_TICK_INTERVAL 65536 // Default interval for 18.2Hz timer +static inline int check_tsc(u64 end) { + return (s64)(rdtscll() - end) > 0; +} +void timer_setup(void); +void ndelay(u32 count); +void udelay(u32 count); +void mdelay(u32 count); +void nsleep(u32 count); +void usleep(u32 count); +void msleep(u32 count); +u64 calc_future_tsc(u32 msecs); +u64 calc_future_tsc_usec(u32 usecs); +u32 calc_future_timer_ticks(u32 count); +u32 calc_future_timer(u32 msecs); +int check_timer(u32 end); +void handle_1583(struct bregs *regs); +void handle_1586(struct bregs *regs); +void useRTC(void); +void releaseRTC(void); + +// apm.c +void apm_shutdown(void); +void handle_1553(struct bregs *regs); + +// pcibios.c +void handle_1ab1(struct bregs *regs); +void bios32_setup(void); + +// shadow.c +void make_bios_writable(void); +void make_bios_readonly(void); +void qemu_prep_reset(void); + +// pciinit.c +extern const u8 pci_irqs[4]; +void pci_setup(void); + +// smm.c +void smm_init(void); + +// smp.c +extern u32 CountCPUs; +extern u32 MaxCountCPUs; +void wrmsr_smp(u32 index, u64 val); +void smp_probe(void); + +// coreboot.c +extern const char *CBvendor, *CBpart; +struct cbfs_file; +struct cbfs_file *cbfs_finddatafile(const char *fname); +struct cbfs_file *cbfs_findprefix(const char *prefix, struct cbfs_file *last); +u32 cbfs_datasize(struct cbfs_file *file); +const char *cbfs_filename(struct cbfs_file *file); +int cbfs_copyfile(struct cbfs_file *file, void *dst, u32 maxlen); +void cbfs_run_payload(struct cbfs_file *file); +void coreboot_copy_biostable(void); +void cbfs_payload_setup(void); +void coreboot_setup(void); + +// biostable.c +void copy_pir(void *pos); +void copy_mptable(void *pos); +void copy_acpi_rsdp(void *pos); +void copy_smbios(void *pos); + +// vgahooks.c +void handle_155f(struct bregs *regs); +struct pci_device; +void vgahook_setup(struct pci_device *pci); + +// optionroms.c +void call_bcv(u16 seg, u16 ip); +void optionrom_setup(void); +void vga_setup(void); +void s3_resume_vga_init(void); +extern u32 RomEnd; +extern int ScreenAndDebug; + +// bootsplash.c +void enable_vga_console(void); +void enable_bootsplash(void); +void disable_bootsplash(void); + +// resume.c +extern int HaveRunPost; +void init_dma(void); + +// pnpbios.c +#define PNP_SIGNATURE 0x506e5024 // $PnP +u16 get_pnp_offset(void); +void pnp_setup(void); + +// pmm.c +extern struct zone_s ZoneLow, ZoneHigh, ZoneFSeg, ZoneTmpLow, ZoneTmpHigh; +void malloc_setup(void); +void malloc_fixupreloc(void); +void malloc_finalize(void); +void *pmm_malloc(struct zone_s *zone, u32 handle, u32 size, u32 align); +int pmm_free(void *data); +void pmm_setup(void); +void pmm_finalize(void); +#define PMM_DEFAULT_HANDLE 0xFFFFFFFF +// Minimum alignment of malloc'd memory +#define MALLOC_MIN_ALIGN 16 +// Helper functions for memory allocation. +static inline void *malloc_low(u32 size) { + return pmm_malloc(&ZoneLow, PMM_DEFAULT_HANDLE, size, MALLOC_MIN_ALIGN); +} +static inline void *malloc_high(u32 size) { + return pmm_malloc(&ZoneHigh, PMM_DEFAULT_HANDLE, size, MALLOC_MIN_ALIGN); +} +static inline void *malloc_fseg(u32 size) { + return pmm_malloc(&ZoneFSeg, PMM_DEFAULT_HANDLE, size, MALLOC_MIN_ALIGN); +} +static inline void *malloc_tmplow(u32 size) { + return pmm_malloc(&ZoneTmpLow, PMM_DEFAULT_HANDLE, size, MALLOC_MIN_ALIGN); +} +static inline void *malloc_tmphigh(u32 size) { + return pmm_malloc(&ZoneTmpHigh, PMM_DEFAULT_HANDLE, size, MALLOC_MIN_ALIGN); +} +static inline void *malloc_tmp(u32 size) { + void *ret = malloc_tmphigh(size); + if (ret) + return ret; + return malloc_tmplow(size); +} +static inline void *memalign_low(u32 align, u32 size) { + return pmm_malloc(&ZoneLow, PMM_DEFAULT_HANDLE, size, align); +} +static inline void *memalign_high(u32 align, u32 size) { + return pmm_malloc(&ZoneHigh, PMM_DEFAULT_HANDLE, size, align); +} +static inline void *memalign_tmplow(u32 align, u32 size) { + return pmm_malloc(&ZoneTmpLow, PMM_DEFAULT_HANDLE, size, align); +} +static inline void *memalign_tmphigh(u32 align, u32 size) { + return pmm_malloc(&ZoneTmpHigh, PMM_DEFAULT_HANDLE, size, align); +} +static inline void *memalign_tmp(u32 align, u32 size) { + void *ret = memalign_tmphigh(align, size); + if (ret) + return ret; + return memalign_tmplow(align, size); +} +static inline void free(void *data) { + pmm_free(data); +} + +// mtrr.c +void mtrr_setup(void); + +// romlayout.S +void reset_vector(void) __noreturn; + +// misc.c +extern u8 BiosChecksum; + +// version (auto generated file out/version.c) +extern const char VERSION[]; + +#endif // util.h diff --git a/bios/seabios/src/vgahooks.c b/bios/seabios/src/vgahooks.c new file mode 100644 index 0000000..a8f667c --- /dev/null +++ b/bios/seabios/src/vgahooks.c @@ -0,0 +1,268 @@ +// Hooks for via vgabios calls into main bios. +// +// Copyright (C) 2008 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "bregs.h" // set_code_invalid +#include "biosvar.h" // GET_GLOBAL +#include "pci.h" // pci_find_device +#include "pci_regs.h" // PCI_VENDOR_ID +#include "pci_ids.h" // PCI_VENDOR_ID_VIA +#include "util.h" // handle_155f +#include "config.h" // CONFIG_* + +#define VH_VIA 1 +#define VH_INTEL 2 + +int VGAHookHandlerType VAR16VISIBLE; + +static void +handle_155fXX(struct bregs *regs) +{ + set_code_unimplemented(regs, RET_EUNSUPPORTED); +} + + +/**************************************************************** + * Via hooks + ****************************************************************/ + +int ViaFBsize VAR16VISIBLE, ViaRamSpeed VAR16VISIBLE; + +static void +via_155f01(struct bregs *regs) +{ + regs->eax = 0x5f; + regs->cl = 2; // panel type = 2 = 1024 * 768 + set_success(regs); + dprintf(1, "Warning: VGA panel type is hardcoded\n"); +} + +static void +via_155f02(struct bregs *regs) +{ + regs->eax = 0x5f; + regs->bx = 2; + regs->cx = 0x401; // PAL + crt only + regs->dx = 0; // TV Layout - default + set_success(regs); + dprintf(1, "Warning: VGA TV/CRT output type is hardcoded\n"); +} + +static void +via_155f18(struct bregs *regs) +{ + int fbsize = GET_GLOBAL(ViaFBsize), ramspeed = GET_GLOBAL(ViaRamSpeed); + if (fbsize < 0 || ramspeed < 0) { + set_code_invalid(regs, RET_EUNSUPPORTED); + return; + } + regs->eax = 0x5f; + regs->ebx = 0x500 | (ramspeed << 4) | fbsize; + regs->ecx = 0x060; + set_success(regs); +} + +static void +via_155f19(struct bregs *regs) +{ + set_invalid_silent(regs); +} + +static void +via_155f(struct bregs *regs) +{ + switch (regs->al) { + case 0x01: via_155f01(regs); break; + case 0x02: via_155f02(regs); break; + case 0x18: via_155f18(regs); break; + case 0x19: via_155f19(regs); break; + default: handle_155fXX(regs); break; + } +} + +static int +getFBSize(struct pci_device *pci) +{ + /* FB config */ + u8 reg = pci_config_readb(pci->bdf, 0xa1); + + /* GFX disabled ? */ + if (!(reg & 0x80)) + return -1; + + static u8 mem_power[] = {0, 3, 4, 5, 6, 7, 8, 9}; + return mem_power[(reg >> 4) & 0x7]; +} + +static int +getViaRamSpeed(struct pci_device *pci) +{ + return (pci_config_readb(pci->bdf, 0x90) & 0x07) + 3; +} + +static int +getAMDRamSpeed(void) +{ + struct pci_device *pci = pci_find_device(PCI_VENDOR_ID_AMD + , PCI_DEVICE_ID_AMD_K8_NB_MEMCTL); + if (!pci) + return -1; + + /* mem clk 0 = DDR2 400 */ + return (pci_config_readb(pci->bdf, 0x94) & 0x7) + 6; +} + +/* int 0x15 - 5f18 + + ECX = unknown/dont care + EBX[3..0] Frame Buffer Size 2^N MiB + EBX[7..4] Memory speed: + 0: SDR 66Mhz + 1: SDR 100Mhz + 2: SDR 133Mhz + 3: DDR 100Mhz (PC1600 or DDR200) + 4: DDR 133Mhz (PC2100 or DDR266) + 5: DDR 166Mhz (PC2700 or DDR333) + 6: DDR 200Mhz (PC3200 or DDR400) + 7: DDR2 133Mhz (DDR2 533) + 8: DDR2 166Mhz (DDR2 667) + 9: DDR2 200Mhz (DDR2 800) + A: DDR2 233Mhz (DDR2 1066) + B: and above: Unknown + EBX[?..8] Total memory size? + EAX = 0x5f for success +*/ + +#define PCI_DEVICE_ID_VIA_K8M890CE_3 0x3336 +#define PCI_DEVICE_ID_VIA_VX855_MEMCTRL 0x3409 + +static void +via_setup(struct pci_device *pci) +{ + VGAHookHandlerType = VH_VIA; + + struct pci_device *d = pci_find_device(PCI_VENDOR_ID_VIA + , PCI_DEVICE_ID_VIA_K8M890CE_3); + if (d) { + ViaFBsize = getFBSize(d); + ViaRamSpeed = getAMDRamSpeed(); + return; + } + d = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855_MEMCTRL); + if (d) { + ViaFBsize = getFBSize(d); + ViaRamSpeed = getViaRamSpeed(d); + return; + } + + dprintf(1, "Warning: VGA memory size and speed is hardcoded\n"); + ViaFBsize = 5; // 32M frame buffer + ViaRamSpeed = 4; // MCLK = DDR266 +} + + +/**************************************************************** + * Intel VGA hooks + ****************************************************************/ + +u8 IntelDisplayType VAR16VISIBLE, IntelDisplayId VAR16VISIBLE; + +static void +intel_155f35(struct bregs *regs) +{ + regs->ax = 0x005f; + regs->cl = GET_GLOBAL(IntelDisplayType); + set_success(regs); +} + +static void +intel_155f40(struct bregs *regs) +{ + regs->ax = 0x005f; + regs->cl = GET_GLOBAL(IntelDisplayId); + set_success(regs); +} + +static void +intel_155f(struct bregs *regs) +{ + switch (regs->al) { + case 0x35: intel_155f35(regs); break; + case 0x40: intel_155f40(regs); break; + default: handle_155fXX(regs); break; + } +} + +#define BOOT_DISPLAY_DEFAULT (0) +#define BOOT_DISPLAY_CRT (1 << 0) +#define BOOT_DISPLAY_TV (1 << 1) +#define BOOT_DISPLAY_EFP (1 << 2) +#define BOOT_DISPLAY_LCD (1 << 3) +#define BOOT_DISPLAY_CRT2 (1 << 4) +#define BOOT_DISPLAY_TV2 (1 << 5) +#define BOOT_DISPLAY_EFP2 (1 << 6) +#define BOOT_DISPLAY_LCD2 (1 << 7) + +static void +roda_setup(struct pci_device *pci) +{ + VGAHookHandlerType = VH_INTEL; + // IntelDisplayType = BOOT_DISPLAY_DEFAULT; + IntelDisplayType = BOOT_DISPLAY_LCD; + // IntelDisplayId = inb(0x60f) & 0x0f; // Correct according to Crete + IntelDisplayId = 3; // Correct according to empirical studies +} + +static void +kontron_setup(struct pci_device *pci) +{ + VGAHookHandlerType = VH_INTEL; + IntelDisplayType = BOOT_DISPLAY_CRT; + IntelDisplayId = 3; +} + +static void +getac_setup(struct pci_device *pci) +{ +} + + +/**************************************************************** + * Entry and setup + ****************************************************************/ + +// Main 16bit entry point +void +handle_155f(struct bregs *regs) +{ + if (!CONFIG_VGAHOOKS) { + handle_155fXX(regs); + return; + } + + int htype = GET_GLOBAL(VGAHookHandlerType); + switch (htype) { + case VH_VIA: via_155f(regs); break; + case VH_INTEL: intel_155f(regs); break; + default: handle_155fXX(regs); break; + } +} + +// Setup +void +vgahook_setup(struct pci_device *pci) +{ + if (!CONFIG_VGAHOOKS || !CBvendor || !CBpart) + return; + + if (strcmp(CBvendor, "KONTRON") == 0 && strcmp(CBpart, "986LCD-M") == 0) + kontron_setup(pci); + else if (strcmp(CBvendor, "GETAC") == 0 && strcmp(CBpart, "P470") == 0) + getac_setup(pci); + else if (strcmp(CBvendor, "RODA") == 0 && strcmp(CBpart, "RK886EX") == 0) + roda_setup(pci); + else if (pci->vendor == PCI_VENDOR_ID_VIA) + via_setup(pci); +} diff --git a/bios/seabios/src/virtio-blk.c b/bios/seabios/src/virtio-blk.c new file mode 100644 index 0000000..b1274fc --- /dev/null +++ b/bios/seabios/src/virtio-blk.c @@ -0,0 +1,184 @@ +// Virtio block boot support. +// +// Copyright (C) 2010 Red Hat Inc. +// +// Authors: +// Gleb Natapov +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // dprintf +#include "pci.h" // foreachpci +#include "config.h" // CONFIG_* +#include "biosvar.h" // GET_GLOBAL +#include "pci_ids.h" // PCI_DEVICE_ID_VIRTIO_BLK +#include "pci_regs.h" // PCI_VENDOR_ID +#include "boot.h" // boot_add_hd +#include "virtio-pci.h" +#include "virtio-ring.h" +#include "virtio-blk.h" +#include "disk.h" + +struct virtiodrive_s { + struct drive_s drive; + struct vring_virtqueue *vq; + u16 ioaddr; +}; + +static int +virtio_blk_op(struct disk_op_s *op, int write) +{ + struct virtiodrive_s *vdrive_g = + container_of(op->drive_g, struct virtiodrive_s, drive); + struct vring_virtqueue *vq = GET_GLOBAL(vdrive_g->vq); + struct virtio_blk_outhdr hdr = { + .type = write ? VIRTIO_BLK_T_OUT : VIRTIO_BLK_T_IN, + .ioprio = 0, + .sector = op->lba, + }; + u8 status = VIRTIO_BLK_S_UNSUPP; + struct vring_list sg[] = { + { + .addr = MAKE_FLATPTR(GET_SEG(SS), &hdr), + .length = sizeof(hdr), + }, + { + .addr = op->buf_fl, + .length = GET_GLOBAL(vdrive_g->drive.blksize) * op->count, + }, + { + .addr = MAKE_FLATPTR(GET_SEG(SS), &status), + .length = sizeof(status), + }, + }; + + /* Add to virtqueue and kick host */ + if (write) + vring_add_buf(vq, sg, 2, 1, 0, 0); + else + vring_add_buf(vq, sg, 1, 2, 0, 0); + vring_kick(GET_GLOBAL(vdrive_g->ioaddr), vq, 1); + + /* Wait for reply */ + while (!vring_more_used(vq)) + usleep(5); + + /* Reclaim virtqueue element */ + vring_get_buf(vq, NULL); + + /* Clear interrupt status register. Avoid leaving interrupts stuck if + * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised. + */ + vp_get_isr(GET_GLOBAL(vdrive_g->ioaddr)); + + return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK; +} + +int +process_virtio_op(struct disk_op_s *op) +{ + if (! CONFIG_VIRTIO_BLK || CONFIG_COREBOOT) + return 0; + switch (op->command) { + case CMD_READ: + return virtio_blk_op(op, 0); + case CMD_WRITE: + return virtio_blk_op(op, 1); + case CMD_FORMAT: + case CMD_RESET: + case CMD_ISREADY: + case CMD_VERIFY: + case CMD_SEEK: + return DISK_RET_SUCCESS; + default: + op->count = 0; + return DISK_RET_EPARAM; + } +} + +static void +init_virtio_blk(struct pci_device *pci) +{ + u16 bdf = pci->bdf; + dprintf(1, "found virtio-blk at %x:%x\n", pci_bdf_to_bus(bdf), + pci_bdf_to_dev(bdf)); + struct virtiodrive_s *vdrive_g = malloc_fseg(sizeof(*vdrive_g)); + struct vring_virtqueue *vq = memalign_low(PAGE_SIZE, sizeof(*vq)); + if (!vdrive_g || !vq) { + warn_noalloc(); + goto fail; + } + memset(vdrive_g, 0, sizeof(*vdrive_g)); + memset(vq, 0, sizeof(*vq)); + vdrive_g->drive.type = DTYPE_VIRTIO; + vdrive_g->drive.cntl_id = bdf; + vdrive_g->vq = vq; + + u16 ioaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) & + PCI_BASE_ADDRESS_IO_MASK; + + vdrive_g->ioaddr = ioaddr; + + vp_reset(ioaddr); + vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE | + VIRTIO_CONFIG_S_DRIVER ); + + if (vp_find_vq(ioaddr, 0, vdrive_g->vq) < 0 ) { + dprintf(1, "fail to find vq for virtio-blk %x:%x\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); + goto fail; + } + + struct virtio_blk_config cfg; + vp_get(ioaddr, 0, &cfg, sizeof(cfg)); + + u32 f = vp_get_features(ioaddr); + vdrive_g->drive.blksize = (f & (1 << VIRTIO_BLK_F_BLK_SIZE)) ? + cfg.blk_size : DISK_SECTOR_SIZE; + + vdrive_g->drive.sectors = cfg.capacity; + dprintf(3, "virtio-blk %x:%x blksize=%d sectors=%u\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), + vdrive_g->drive.blksize, (u32)vdrive_g->drive.sectors); + + if (vdrive_g->drive.blksize != DISK_SECTOR_SIZE) { + dprintf(1, "virtio-blk %x:%x block size %d is unsupported\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), + vdrive_g->drive.blksize); + goto fail; + } + + vdrive_g->drive.pchs.cylinders = cfg.cylinders; + vdrive_g->drive.pchs.heads = cfg.heads; + vdrive_g->drive.pchs.spt = cfg.sectors; + char *desc = znprintf(MAXDESCSIZE, "Virtio disk PCI:%x:%x", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); + + boot_add_hd(&vdrive_g->drive, desc, bootprio_find_pci_device(pci)); + + vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE | + VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK); + return; + +fail: + free(vdrive_g); + free(vq); +} + +void +virtio_blk_setup(void) +{ + ASSERT32FLAT(); + if (! CONFIG_VIRTIO_BLK || CONFIG_COREBOOT) + return; + + dprintf(3, "init virtio-blk\n"); + + struct pci_device *pci; + foreachpci(pci) { + if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET + || pci->device != PCI_DEVICE_ID_VIRTIO_BLK) + continue; + init_virtio_blk(pci); + } +} diff --git a/bios/seabios/src/virtio-blk.h b/bios/seabios/src/virtio-blk.h new file mode 100644 index 0000000..7243704 --- /dev/null +++ b/bios/seabios/src/virtio-blk.h @@ -0,0 +1,43 @@ +#ifndef _VIRTIO_BLK_H +#define _VIRTIO_BLK_H + +struct virtio_blk_config +{ + u64 capacity; + u32 size_max; + u32 seg_max; + u16 cylinders; + u8 heads; + u8 sectors; + u32 blk_size; + u8 physical_block_exp; + u8 alignment_offset; + u16 min_io_size; + u32 opt_io_size; +} __attribute__((packed)); + +#define VIRTIO_BLK_F_BLK_SIZE 6 + +/* These two define direction. */ +#define VIRTIO_BLK_T_IN 0 +#define VIRTIO_BLK_T_OUT 1 + +/* This is the first element of the read scatter-gather list. */ +struct virtio_blk_outhdr { + /* VIRTIO_BLK_T* */ + u32 type; + /* io priority. */ + u32 ioprio; + /* Sector (ie. 512 byte offset) */ + u64 sector; +}; + +#define VIRTIO_BLK_S_OK 0 +#define VIRTIO_BLK_S_IOERR 1 +#define VIRTIO_BLK_S_UNSUPP 2 + +struct disk_op_s; +int process_virtio_op(struct disk_op_s *op); +void virtio_blk_setup(void); + +#endif /* _VIRTIO_BLK_H */ diff --git a/bios/seabios/src/virtio-pci.c b/bios/seabios/src/virtio-pci.c new file mode 100644 index 0000000..db19e97 --- /dev/null +++ b/bios/seabios/src/virtio-pci.c @@ -0,0 +1,69 @@ +/* virtio-pci.c - pci interface for virtio interface + * + * (c) Copyright 2008 Bull S.A.S. + * + * Author: Laurent Vivier + * + * some parts from Linux Virtio PCI driver + * + * Copyright IBM Corp. 2007 + * Authors: Anthony Liguori + * + * Adopted for Seabios: Gleb Natapov + * + * This work is licensed under the terms of the GNU LGPLv3 + * See the COPYING file in the top-level directory. + */ + +#include "virtio-ring.h" +#include "virtio-pci.h" +#include "config.h" // CONFIG_DEBUG_LEVEL +#include "util.h" // dprintf + +int vp_find_vq(unsigned int ioaddr, int queue_index, + struct vring_virtqueue *vq) +{ + struct vring * vr = &vq->vring; + u16 num; + + ASSERT32FLAT(); + /* select the queue */ + + outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL); + + /* check if the queue is available */ + + num = inw(ioaddr + VIRTIO_PCI_QUEUE_NUM); + if (!num) { + dprintf(1, "ERROR: queue size is 0\n"); + return -1; + } + + if (num > MAX_QUEUE_NUM) { + dprintf(1, "ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM); + return -1; + } + + /* check if the queue is already active */ + + if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) { + dprintf(1, "ERROR: queue already active\n"); + return -1; + } + + vq->queue_index = queue_index; + + /* initialize the queue */ + + vring_init(vr, num, (unsigned char*)&vq->queue); + + /* activate the queue + * + * NOTE: vr->desc is initialized by vring_init() + */ + + outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT, + ioaddr + VIRTIO_PCI_QUEUE_PFN); + + return num; +} diff --git a/bios/seabios/src/virtio-pci.h b/bios/seabios/src/virtio-pci.h new file mode 100644 index 0000000..d21d5a5 --- /dev/null +++ b/bios/seabios/src/virtio-pci.h @@ -0,0 +1,104 @@ +#ifndef _VIRTIO_PCI_H +#define _VIRTIO_PCI_H + +#include "ioport.h" // inl + +/* A 32-bit r/o bitmask of the features supported by the host */ +#define VIRTIO_PCI_HOST_FEATURES 0 + +/* A 32-bit r/w bitmask of features activated by the guest */ +#define VIRTIO_PCI_GUEST_FEATURES 4 + +/* A 32-bit r/w PFN for the currently selected queue */ +#define VIRTIO_PCI_QUEUE_PFN 8 + +/* A 16-bit r/o queue size for the currently selected queue */ +#define VIRTIO_PCI_QUEUE_NUM 12 + +/* A 16-bit r/w queue selector */ +#define VIRTIO_PCI_QUEUE_SEL 14 + +/* A 16-bit r/w queue notifier */ +#define VIRTIO_PCI_QUEUE_NOTIFY 16 + +/* An 8-bit device status register. */ +#define VIRTIO_PCI_STATUS 18 + +/* An 8-bit r/o interrupt status register. Reading the value will return the + * current contents of the ISR and will also clear it. This is effectively + * a read-and-acknowledge. */ +#define VIRTIO_PCI_ISR 19 + +/* The bit of the ISR which indicates a device configuration change. */ +#define VIRTIO_PCI_ISR_CONFIG 0x2 + +/* The remaining space is defined by each driver as the per-driver + * configuration space */ +#define VIRTIO_PCI_CONFIG 20 + +/* Virtio ABI version, this must match exactly */ +#define VIRTIO_PCI_ABI_VERSION 0 + +static inline u32 vp_get_features(unsigned int ioaddr) +{ + return inl(ioaddr + VIRTIO_PCI_HOST_FEATURES); +} + +static inline void vp_set_features(unsigned int ioaddr, u32 features) +{ + outl(features, ioaddr + VIRTIO_PCI_GUEST_FEATURES); +} + +static inline void vp_get(unsigned int ioaddr, unsigned offset, + void *buf, unsigned len) +{ + u8 *ptr = buf; + unsigned i; + + for (i = 0; i < len; i++) + ptr[i] = inb(ioaddr + VIRTIO_PCI_CONFIG + offset + i); +} + +static inline u8 vp_get_status(unsigned int ioaddr) +{ + return inb(ioaddr + VIRTIO_PCI_STATUS); +} + +static inline void vp_set_status(unsigned int ioaddr, u8 status) +{ + if (status == 0) /* reset */ + return; + outb(status, ioaddr + VIRTIO_PCI_STATUS); +} + +static inline u8 vp_get_isr(unsigned int ioaddr) +{ + return inb(ioaddr + VIRTIO_PCI_ISR); +} + +static inline void vp_reset(unsigned int ioaddr) +{ + outb(0, ioaddr + VIRTIO_PCI_STATUS); + (void)inb(ioaddr + VIRTIO_PCI_ISR); +} + +static inline void vp_notify(unsigned int ioaddr, int queue_index) +{ + outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_NOTIFY); +} + +static inline void vp_del_vq(unsigned int ioaddr, int queue_index) +{ + /* select the queue */ + + outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL); + + /* deactivate the queue */ + + outl(0, ioaddr + VIRTIO_PCI_QUEUE_PFN); +} + +struct vring_virtqueue; +int vp_find_vq(unsigned int ioaddr, int queue_index, + struct vring_virtqueue *vq); +#endif /* _VIRTIO_PCI_H_ */ diff --git a/bios/seabios/src/virtio-ring.c b/bios/seabios/src/virtio-ring.c new file mode 100644 index 0000000..97a3ffe --- /dev/null +++ b/bios/seabios/src/virtio-ring.c @@ -0,0 +1,151 @@ +/* virtio-pci.c - virtio ring management + * + * (c) Copyright 2008 Bull S.A.S. + * + * Author: Laurent Vivier + * + * some parts from Linux Virtio Ring + * + * Copyright Rusty Russell IBM Corporation 2007 + * + * Adopted for Seabios: Gleb Natapov + * + * This work is licensed under the terms of the GNU LGPLv3 + * See the COPYING file in the top-level directory. + * + * + */ + +#include "virtio-ring.h" +#include "virtio-pci.h" +#include "biosvar.h" // GET_GLOBAL +#include "util.h" // dprintf + +#define BUG() do { \ + dprintf(1, "BUG: failure at %s:%d/%s()!\n", \ + __FILE__, __LINE__, __func__); \ + while(1); \ + } while (0) +#define BUG_ON(condition) do { if (condition) BUG(); } while (0) + +/* + * vring_more_used + * + * is there some used buffers ? + * + */ + +int vring_more_used(struct vring_virtqueue *vq) +{ + struct vring_used *used = GET_FLATPTR(vq->vring.used); + int more = GET_FLATPTR(vq->last_used_idx) != GET_FLATPTR(used->idx); + /* Make sure ring reads are done after idx read above. */ + smp_rmb(); + return more; +} + +/* + * vring_free + * + * put at the begin of the free list the current desc[head] + */ + +void vring_detach(struct vring_virtqueue *vq, unsigned int head) +{ + struct vring *vr = &vq->vring; + struct vring_desc *desc = GET_FLATPTR(vr->desc); + unsigned int i; + + /* find end of given descriptor */ + + i = head; + while (GET_FLATPTR(desc[i].flags) & VRING_DESC_F_NEXT) + i = GET_FLATPTR(desc[i].next); + + /* link it with free list and point to it */ + + SET_FLATPTR(desc[i].next, GET_FLATPTR(vq->free_head)); + SET_FLATPTR(vq->free_head, head); +} + +/* + * vring_get_buf + * + * get a buffer from the used list + * + */ + +int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len) +{ + struct vring *vr = &vq->vring; + struct vring_used_elem *elem; + struct vring_used *used = GET_FLATPTR(vq->vring.used); + u32 id; + int ret; + +// BUG_ON(!vring_more_used(vq)); + + elem = &used->ring[GET_FLATPTR(vq->last_used_idx) % GET_FLATPTR(vr->num)]; + id = GET_FLATPTR(elem->id); + if (len != NULL) + *len = GET_FLATPTR(elem->len); + + ret = GET_FLATPTR(vq->vdata[id]); + + vring_detach(vq, id); + + SET_FLATPTR(vq->last_used_idx, GET_FLATPTR(vq->last_used_idx) + 1); + + return ret; +} + +void vring_add_buf(struct vring_virtqueue *vq, + struct vring_list list[], + unsigned int out, unsigned int in, + int index, int num_added) +{ + struct vring *vr = &vq->vring; + int i, av, head, prev; + struct vring_desc *desc = GET_FLATPTR(vr->desc); + struct vring_avail *avail = GET_FLATPTR(vr->avail); + + BUG_ON(out + in == 0); + + prev = 0; + head = GET_FLATPTR(vq->free_head); + for (i = head; out; i = GET_FLATPTR(desc[i].next), out--) { + SET_FLATPTR(desc[i].flags, VRING_DESC_F_NEXT); + SET_FLATPTR(desc[i].addr, (u64)virt_to_phys(list->addr)); + SET_FLATPTR(desc[i].len, list->length); + prev = i; + list++; + } + for ( ; in; i = GET_FLATPTR(desc[i].next), in--) { + SET_FLATPTR(desc[i].flags, VRING_DESC_F_NEXT|VRING_DESC_F_WRITE); + SET_FLATPTR(desc[i].addr, (u64)virt_to_phys(list->addr)); + SET_FLATPTR(desc[i].len, list->length); + prev = i; + list++; + } + SET_FLATPTR(desc[prev].flags, + GET_FLATPTR(desc[prev].flags) & ~VRING_DESC_F_NEXT); + + SET_FLATPTR(vq->free_head, i); + + SET_FLATPTR(vq->vdata[head], index); + + av = (GET_FLATPTR(avail->idx) + num_added) % GET_FLATPTR(vr->num); + SET_FLATPTR(avail->ring[av], head); +} + +void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added) +{ + struct vring *vr = &vq->vring; + struct vring_avail *avail = GET_FLATPTR(vr->avail); + + /* Make sure idx update is done after ring write. */ + smp_wmb(); + SET_FLATPTR(avail->idx, GET_FLATPTR(avail->idx) + num_added); + + vp_notify(ioaddr, GET_FLATPTR(vq->queue_index)); +} diff --git a/bios/seabios/src/virtio-ring.h b/bios/seabios/src/virtio-ring.h new file mode 100644 index 0000000..b7a7aaf --- /dev/null +++ b/bios/seabios/src/virtio-ring.h @@ -0,0 +1,131 @@ +#ifndef _VIRTIO_RING_H +#define _VIRTIO_RING_H + +#include "types.h" // u64 +#include "memmap.h" // PAGE_SIZE + +#define PAGE_SHIFT 12 +#define PAGE_MASK (PAGE_SIZE-1) + +#define virt_to_phys(v) (unsigned long)(v) +#define phys_to_virt(p) (void*)(p) +/* Compiler barrier is enough as an x86 CPU does not reorder reads or writes */ +#define smp_rmb() barrier() +#define smp_wmb() barrier() + +/* Status byte for guest to report progress, and synchronize features. */ +/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */ +#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1 +/* We have found a driver for the device. */ +#define VIRTIO_CONFIG_S_DRIVER 2 +/* Driver has used its parts of the config, and is happy */ +#define VIRTIO_CONFIG_S_DRIVER_OK 4 +/* We've given up on this device. */ +#define VIRTIO_CONFIG_S_FAILED 0x80 + +#define MAX_QUEUE_NUM (128) + +#define VRING_DESC_F_NEXT 1 +#define VRING_DESC_F_WRITE 2 + +#define VRING_AVAIL_F_NO_INTERRUPT 1 + +#define VRING_USED_F_NO_NOTIFY 1 + +struct vring_desc +{ + u64 addr; + u32 len; + u16 flags; + u16 next; +}; + +struct vring_avail +{ + u16 flags; + u16 idx; + u16 ring[0]; +}; + +struct vring_used_elem +{ + u32 id; + u32 len; +}; + +struct vring_used +{ + u16 flags; + u16 idx; + struct vring_used_elem ring[]; +}; + +struct vring { + unsigned int num; + struct vring_desc *desc; + struct vring_avail *avail; + struct vring_used *used; +}; + +#define vring_size(num) \ + (((((sizeof(struct vring_desc) * num) + \ + (sizeof(struct vring_avail) + sizeof(u16) * num)) \ + + PAGE_MASK) & ~PAGE_MASK) + \ + (sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num)) + +typedef unsigned char virtio_queue_t[vring_size(MAX_QUEUE_NUM)]; + +struct vring_virtqueue { + virtio_queue_t queue; + struct vring vring; + u16 free_head; + u16 last_used_idx; + u16 vdata[MAX_QUEUE_NUM]; + /* PCI */ + int queue_index; +}; + +struct vring_list { + char *addr; + unsigned int length; +}; + +static inline void vring_init(struct vring *vr, + unsigned int num, unsigned char *queue) +{ + unsigned int i; + unsigned long pa; + + ASSERT32FLAT(); + vr->num = num; + + /* physical address of desc must be page aligned */ + + pa = virt_to_phys(queue); + pa = (pa + PAGE_MASK) & ~PAGE_MASK; + vr->desc = phys_to_virt(pa); + + vr->avail = (struct vring_avail *)&vr->desc[num]; + /* disable interrupts */ + vr->avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; + + /* physical address of used must be page aligned */ + + pa = virt_to_phys(&vr->avail->ring[num]); + pa = (pa + PAGE_MASK) & ~PAGE_MASK; + vr->used = phys_to_virt(pa); + + for (i = 0; i < num - 1; i++) + vr->desc[i].next = i + 1; + vr->desc[i].next = 0; +} + +int vring_more_used(struct vring_virtqueue *vq); +void vring_detach(struct vring_virtqueue *vq, unsigned int head); +int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len); +void vring_add_buf(struct vring_virtqueue *vq, struct vring_list list[], + unsigned int out, unsigned int in, + int index, int num_added); +void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added); + +#endif /* _VIRTIO_RING_H_ */ diff --git a/bios/seabios/src/xen.c b/bios/seabios/src/xen.c new file mode 100644 index 0000000..4072793 --- /dev/null +++ b/bios/seabios/src/xen.c @@ -0,0 +1,149 @@ +// Xen HVM support +// +// Copyright (C) 2011 Citrix Systems. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "config.h" +#include "xen.h" + +#include "memmap.h" // add_e820 +#include "types.h" // ASM32FLAT +#include "util.h" // copy_acpi_rsdp + +#define INFO_PHYSICAL_ADDRESS 0x00001000 + +u32 xen_cpuid_base = 0; + +struct xen_seabios_info { + char signature[14]; /* XenHVMSeaBIOS\0 */ + u8 length; /* Length of this struct */ + u8 checksum; /* Set such that the sum over bytes 0..length == 0 */ + /* + * Physical address of an array of tables_nr elements. + * + * Each element is a 32 bit value contianing the physical address + * of a BIOS table. + */ + u32 tables; + u32 tables_nr; + /* + * Physical address of the e820 table, contains e820_nr entries. + */ + u32 e820; + u32 e820_nr; +} PACKED; + +static void validate_info(struct xen_seabios_info *t) +{ + if ( memcmp(t->signature, "XenHVMSeaBIOS", 14) ) + panic("Bad Xen info signature\n"); + + if ( t->length < sizeof(struct xen_seabios_info) ) + panic("Bad Xen info length\n"); + + if (checksum(t, t->length) != 0) + panic("Bad Xen info checksum\n"); +} + +void xen_probe(void) +{ + u32 base, eax, ebx, ecx, edx; + char signature[13]; + + if (!CONFIG_XEN) + return; + + for (base = 0x40000000; base < 0x40010000; base += 0x100) { + cpuid(base, &eax, &ebx, &ecx, &edx); + memcpy(signature + 0, &ebx, 4); + memcpy(signature + 4, &ecx, 4); + memcpy(signature + 8, &edx, 4); + signature[12] = 0; + + dprintf(1, "Found hypervisor signature \"%s\" at %x\n", + signature, base); + if (strcmp(signature, "XenVMMXenVMM") == 0) { + if ((eax - base) < 2) + panic("Insufficient Xen cpuid leaves. eax=%x at base %x\n", + eax, base); + xen_cpuid_base = base; + break; + } + } +} + +static int hypercall_xen_version( int cmd, void *arg) +{ + return _hypercall2(int, xen_version, cmd, arg); +} + +/* Fill in hypercall transfer pages. */ +void xen_init_hypercalls(void) +{ + u32 eax, ebx, ecx, edx; + xen_extraversion_t extraversion; + unsigned long i; + + if (!usingXen()) + return; + + cpuid(xen_cpuid_base + 2, &eax, &ebx, &ecx, &edx); + + xen_hypercall_page = (unsigned long)memalign_high(PAGE_SIZE, eax*PAGE_SIZE); + if (!xen_hypercall_page) + panic("unable to allocate Xen hypercall page\n"); + + dprintf(1, "Allocated Xen hypercall page at %lx\n", xen_hypercall_page); + for ( i = 0; i < eax; i++ ) + wrmsr(ebx, xen_hypercall_page + (i << 12) + i); + + /* Print version information. */ + cpuid(xen_cpuid_base + 1, &eax, &ebx, &ecx, &edx); + hypercall_xen_version(XENVER_extraversion, extraversion); + dprintf(1, "Detected Xen v%u.%u%s\n", eax >> 16, eax & 0xffff, extraversion); +} + +void xen_copy_biostables(void) +{ + struct xen_seabios_info *info = (void *)INFO_PHYSICAL_ADDRESS; + u32 *tables = (u32 *)info->tables; + int i; + + dprintf(1, "xen: copy BIOS tables...\n"); + for (i=0; itables_nr; i++) { + void *table = (void *)tables[i]; + copy_acpi_rsdp(table); + copy_mptable(table); + copy_pir(table); + copy_smbios(table); + } +} + +void xen_setup(void) +{ + u64 maxram = 0, maxram_over4G = 0; + int i; + struct xen_seabios_info *info = (void *)INFO_PHYSICAL_ADDRESS; + struct e820entry *e820 = (struct e820entry *)info->e820; + validate_info(info); + + dprintf(1, "xen: copy e820...\n"); + + for (i = 0; i < info->e820_nr; i++) { + struct e820entry *e = &e820[i]; + if (e->type == E820_ACPI || e->type == E820_RAM) { + u64 end = e->start + e->size; + if (end > 0x100000000ull) { + end -= 0x100000000ull; + if (end > maxram_over4G) + maxram_over4G = end; + } else if (end > maxram) + maxram = end; + } + add_e820(e->start, e->size, e->type); + } + + RamSize = maxram; + RamSizeOver4G = maxram_over4G; +} diff --git a/bios/seabios/src/xen.h b/bios/seabios/src/xen.h new file mode 100644 index 0000000..0ed1e9f --- /dev/null +++ b/bios/seabios/src/xen.h @@ -0,0 +1,135 @@ +#ifndef __XEN_H +#define __XEN_H + +#include "util.h" + +extern u32 xen_cpuid_base; + +void xen_probe(void); +void xen_setup(void); +void xen_init_hypercalls(void); +void xen_copy_biostables(void); + +static inline int usingXen(void) { + if (!CONFIG_XEN) + return 0; + return (xen_cpuid_base != 0); +} + +unsigned long xen_hypercall_page; + +#define _hypercall0(type, name) \ +({ \ + unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \ + long __res; \ + asm volatile ( \ + "call *%%eax" \ + : "=a" (__res) \ + : "0" (__hentry) \ + : "memory" ); \ + (type)__res; \ +}) + +#define _hypercall1(type, name, a1) \ +({ \ + unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \ + long __res, __ign1; \ + asm volatile ( \ + "call *%%eax" \ + : "=a" (__res), "=b" (__ign1) \ + : "0" (__hentry), "1" ((long)(a1)) \ + : "memory" ); \ + (type)__res; \ +}) + +#define _hypercall2(type, name, a1, a2) \ +({ \ + unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \ + long __res, __ign1, __ign2; \ + asm volatile ( \ + "call *%%eax" \ + : "=a" (__res), "=b" (__ign1), "=c" (__ign2) \ + : "0" (__hentry), "1" ((long)(a1)), "2" ((long)(a2)) \ + : "memory" ); \ + (type)__res; \ +}) + +#define _hypercall3(type, name, a1, a2, a3) \ +({ \ + unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \ + long __res, __ign1, __ign2, __ign3; \ + asm volatile ( \ + "call *%%eax" \ + : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ + "=d" (__ign3) \ + : "0" (__hentry), "1" ((long)(a1)), "2" ((long)(a2)), \ + "3" ((long)(a3)) \ + : "memory" ); \ + (type)__res; \ +}) + +#define _hypercall4(type, name, a1, a2, a3, a4) \ +({ \ + unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \ + long __res, __ign1, __ign2, __ign3, __ign4; \ + asm volatile ( \ + "call *%%eax" \ + : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ + "=d" (__ign3), "=S" (__ign4) \ + : "0" (__hentry), "1" ((long)(a1)), "2" ((long)(a2)), \ + "3" ((long)(a3)), "4" ((long)(a4)) \ + : "memory" ); \ + (type)__res; \ +}) + +#define _hypercall5(type, name, a1, a2, a3, a4, a5) \ +({ \ + unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \ + long __res, __ign1, __ign2, __ign3, __ign4, __ign5; \ + asm volatile ( \ + "call *%%eax" \ + : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ + "=d" (__ign3), "=S" (__ign4), "=D" (__ign5) \ + : "0" (__hentry), "1" ((long)(a1)), "2" ((long)(a2)), \ + "3" ((long)(a3)), "4" ((long)(a4)), \ + "5" ((long)(a5)) \ + : "memory" ); \ + (type)__res; \ +}) + +/****************************************************************************** + * + * The following interface definitions are taken from Xen and have the + * following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* xen.h */ + +#define __HYPERVISOR_xen_version 17 + +/* version.h */ + +/* arg == xen_extraversion_t. */ +#define XENVER_extraversion 1 +typedef char xen_extraversion_t[16]; +#define XEN_EXTRAVERSION_LEN (sizeof(xen_extraversion_t)) + +#endif diff --git a/bios/seabios/tools/buildrom.py b/bios/seabios/tools/buildrom.py new file mode 100755 index 0000000..19b715a --- /dev/null +++ b/bios/seabios/tools/buildrom.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python +# Fill in checksum/size of an option rom, and pad it to proper length. +# +# Copyright (C) 2009 Kevin O'Connor +# +# This file may be distributed under the terms of the GNU GPLv3 license. + +import sys + +def alignpos(pos, alignbytes): + mask = alignbytes - 1 + return (pos + mask) & ~mask + +def checksum(data): + ords = map(ord, data) + return sum(ords) + +def main(): + inname = sys.argv[1] + outname = sys.argv[2] + + # Read data in + f = open(inname, 'rb') + data = f.read() + count = len(data) + + # Pad to a 512 byte boundary + data += "\0" * (alignpos(count, 512) - count) + count = len(data) + + # Fill in size field; clear checksum field + data = data[:2] + chr(count/512) + data[3:6] + "\0" + data[7:] + + # Checksum rom + newsum = (256 - checksum(data)) & 0xff + data = data[:6] + chr(newsum) + data[7:] + + # Write new rom + f = open(outname, 'wb') + f.write(data) + +if __name__ == '__main__': + main() diff --git a/bios/seabios/tools/checkrom.py b/bios/seabios/tools/checkrom.py new file mode 100755 index 0000000..69d65e8 --- /dev/null +++ b/bios/seabios/tools/checkrom.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# Script to check a bios image and report info on it. +# +# Copyright (C) 2008 Kevin O'Connor +# +# This file may be distributed under the terms of the GNU GPLv3 license. + +import sys +import layoutrom + +def main(): + # Get args + objinfo, rawfile, outfile = sys.argv[1:] + + # Read in symbols + objinfofile = open(objinfo, 'rb') + symbols = layoutrom.parseObjDump(objinfofile, 'in')[1] + + # Read in raw file + f = open(rawfile, 'rb') + rawdata = f.read() + f.close() + datasize = len(rawdata) + finalsize = 64*1024 + if datasize > 64*1024: + finalsize = 128*1024 + if datasize > 128*1024: + finalsize = 256*1024 + + # Sanity checks + start = symbols['code32flat_start'].offset + end = symbols['code32flat_end'].offset + expend = layoutrom.BUILD_BIOS_ADDR + layoutrom.BUILD_BIOS_SIZE + if end != expend: + print "Error! Code does not end at 0x%x (got 0x%x)" % ( + expend, end) + sys.exit(1) + if datasize > finalsize: + print "Error! Code is too big (0x%x vs 0x%x)" % ( + datasize, finalsize) + sys.exit(1) + expdatasize = end - start + if datasize != expdatasize: + print "Error! Unknown extra data (0x%x vs 0x%x)" % ( + datasize, expdatasize) + sys.exit(1) + + # Print statistics + runtimesize = datasize + if '_reloc_abs_start' in symbols: + runtimesize = end - symbols['code32init_end'].offset + print "Total size: %d Fixed: %d Free: %d (used %.1f%% of %dKiB rom)" % ( + datasize, runtimesize, finalsize - datasize + , (datasize / float(finalsize)) * 100.0 + , finalsize / 1024) + + # Write final file + f = open(outfile, 'wb') + f.write(("\0" * (finalsize - datasize)) + rawdata) + f.close() + +if __name__ == '__main__': + main() diff --git a/bios/seabios/tools/checkstack.py b/bios/seabios/tools/checkstack.py new file mode 100755 index 0000000..428c296 --- /dev/null +++ b/bios/seabios/tools/checkstack.py @@ -0,0 +1,225 @@ +#!/usr/bin/env python +# Script that tries to find how much stack space each function in an +# object is using. +# +# Copyright (C) 2008 Kevin O'Connor +# +# This file may be distributed under the terms of the GNU GPLv3 license. + +# Usage: +# objdump -m i386 -M i8086 -M suffix -d out/rom16.o | tools/checkstack.py + +import sys +import re + +# Functions that change stacks +STACKHOP = ['__send_disk_op'] +# List of functions we can assume are never called. +#IGNORE = ['panic', '__dprintf'] +IGNORE = ['panic'] + +OUTPUTDESC = """ +#funcname1[preamble_stack_usage,max_usage_with_callers]: +# insn_addr:called_function [usage_at_call_point+caller_preamble,total_usage] +# +#funcname2[p,m,max_usage_to_yield_point]: +# insn_addr:called_function [u+c,t,usage_to_yield_point] +""" + +# Find out maximum stack usage for a function +def calcmaxstack(funcs, funcaddr): + info = funcs[funcaddr] + # Find max of all nested calls. + maxusage = info[1] + maxyieldusage = doesyield = 0 + if info[3] is not None: + maxyieldusage = info[3] + doesyield = 1 + info[2] = maxusage + info[4] = info[3] + seenbefore = {} + totcalls = 0 + for insnaddr, calladdr, usage in info[6]: + callinfo = funcs.get(calladdr) + if callinfo is None: + continue + if callinfo[2] is None: + calcmaxstack(funcs, calladdr) + if callinfo[0] not in seenbefore: + seenbefore[callinfo[0]] = 1 + totcalls += 1 + callinfo[5] + funcnameroot = callinfo[0].split('.')[0] + if funcnameroot in IGNORE: + # This called function is ignored - don't contribute it to + # the max stack. + continue + if funcnameroot in STACKHOP: + if usage > maxusage: + maxusage = usage + if callinfo[4] is not None: + doesyield = 1 + if usage > maxyieldusage: + maxyieldusage = usage + continue + totusage = usage + callinfo[2] + if totusage > maxusage: + maxusage = totusage + if callinfo[4] is not None: + doesyield = 1 + totyieldusage = usage + callinfo[4] + if totyieldusage > maxyieldusage: + maxyieldusage = totyieldusage + info[2] = maxusage + if doesyield: + info[4] = maxyieldusage + info[5] = totcalls + +# Try to arrange output so that functions that call each other are +# near each other. +def orderfuncs(funcaddrs, availfuncs): + l = [(availfuncs[funcaddr][5], availfuncs[funcaddr][0], funcaddr) + for funcaddr in funcaddrs if funcaddr in availfuncs] + l.sort() + l.reverse() + out = [] + while l: + count, name, funcaddr = l.pop(0) + if funcaddr not in availfuncs: + continue + calladdrs = [calls[1] for calls in availfuncs[funcaddr][6]] + del availfuncs[funcaddr] + out = out + orderfuncs(calladdrs, availfuncs) + [funcaddr] + return out + +# Update function info with a found "yield" point. +def noteYield(info, stackusage): + prevyield = info[3] + if prevyield is None or prevyield < stackusage: + info[3] = stackusage + +# Update function info with a found "call" point. +def noteCall(info, subfuncs, insnaddr, calladdr, stackusage): + if (calladdr, stackusage) in subfuncs: + # Already noted a nearly identical call - ignore this one. + return + info[6].append((insnaddr, calladdr, stackusage)) + subfuncs[(calladdr, stackusage)] = 1 + +hex_s = r'[0-9a-f]+' +re_func = re.compile(r'^(?P' + hex_s + r') <(?P.*)>:$') +re_asm = re.compile( + r'^[ ]*(?P' + hex_s + + r'):\t.*\t(addr32 )?(?P.+?)[ ]*((?P' + hex_s + + r') <(?P.*)>)?$') +re_usestack = re.compile( + r'^(push[f]?[lw])|(sub.* [$](?P0x' + hex_s + r'),%esp)$') + +def calc(): + # funcs[funcaddr] = [funcname, basicstackusage, maxstackusage + # , yieldusage, maxyieldusage, totalcalls + # , [(insnaddr, calladdr, stackusage), ...]] + funcs = {-1: ['', 0, 0, None, None, 0, []]} + cur = None + atstart = 0 + stackusage = 0 + + # Parse input lines + for line in sys.stdin.readlines(): + m = re_func.match(line) + if m is not None: + # Found function + funcaddr = int(m.group('funcaddr'), 16) + funcs[funcaddr] = cur = [m.group('func'), 0, None, None, None, 0, []] + stackusage = 0 + atstart = 1 + subfuncs = {} + continue + m = re_asm.match(line) + if m is not None: + insn = m.group('insn') + + im = re_usestack.match(insn) + if im is not None: + if insn.startswith('pushl') or insn.startswith('pushfl'): + stackusage += 4 + continue + elif insn.startswith('pushw') or insn.startswith('pushfw'): + stackusage += 2 + continue + stackusage += int(im.group('num'), 16) + + if atstart: + if insn == 'movl %esp,%ebp': + # Still part of initial header + continue + cur[1] = stackusage + atstart = 0 + + insnaddr = m.group('insnaddr') + calladdr = m.group('calladdr') + if calladdr is None: + if insn.startswith('lcallw'): + noteCall(cur, subfuncs, insnaddr, -1, stackusage + 4) + noteYield(cur, stackusage + 4) + elif insn.startswith('int'): + noteCall(cur, subfuncs, insnaddr, -1, stackusage + 6) + noteYield(cur, stackusage + 6) + elif insn.startswith('sti'): + noteYield(cur, stackusage) + else: + # misc instruction + continue + else: + # Jump or call insn + calladdr = int(calladdr, 16) + ref = m.group('ref') + if '+' in ref: + # Inter-function jump. + pass + elif insn.startswith('j'): + # Tail call + noteCall(cur, subfuncs, insnaddr, calladdr, 0) + elif insn.startswith('calll'): + noteCall(cur, subfuncs, insnaddr, calladdr, stackusage + 4) + else: + print "unknown call", ref + noteCall(cur, subfuncs, insnaddr, calladdr, stackusage) + # Reset stack usage to preamble usage + stackusage = cur[1] + + #print "other", repr(line) + + # Calculate maxstackusage + for funcaddr, info in funcs.items(): + if info[2] is not None: + continue + calcmaxstack(funcs, funcaddr) + + # Sort functions for output + funcaddrs = orderfuncs(funcs.keys(), funcs.copy()) + + # Show all functions + print OUTPUTDESC + for funcaddr in funcaddrs: + name, basicusage, maxusage, yieldusage, maxyieldusage, count, calls = \ + funcs[funcaddr] + if maxusage == 0 and maxyieldusage is None: + continue + yieldstr = "" + if maxyieldusage is not None: + yieldstr = ",%d" % maxyieldusage + print "\n%s[%d,%d%s]:" % (name, basicusage, maxusage, yieldstr) + for insnaddr, calladdr, stackusage in calls: + callinfo = funcs.get(calladdr, ("", 0, 0, 0, None)) + yieldstr = "" + if callinfo[4] is not None: + yieldstr = ",%d" % (stackusage + callinfo[4]) + print " %04s:%-40s [%d+%d,%d%s]" % ( + insnaddr, callinfo[0], stackusage, callinfo[1] + , stackusage+callinfo[2], yieldstr) + +def main(): + calc() + +if __name__ == '__main__': + main() diff --git a/bios/seabios/tools/checksum.py b/bios/seabios/tools/checksum.py new file mode 100755 index 0000000..8c7665d --- /dev/null +++ b/bios/seabios/tools/checksum.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python +# Script to report the checksum of a file. +# +# Copyright (C) 2009 Kevin O'Connor +# +# This file may be distributed under the terms of the GNU GPLv3 license. + +import sys + +def main(): + data = sys.stdin.read() + ords = map(ord, data) + print "sum=%x\n" % sum(ords) + +if __name__ == '__main__': + main() diff --git a/bios/seabios/tools/encodeint.py b/bios/seabios/tools/encodeint.py new file mode 100755 index 0000000..12be5fe --- /dev/null +++ b/bios/seabios/tools/encodeint.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +# Encode an integer in little endian format in a file. +# +# Copyright (C) 2011 Kevin O'Connor +# +# This file may be distributed under the terms of the GNU GPLv3 license. + +import sys +import struct + +def main(): + filename = sys.argv[1] + value = int(sys.argv[2]) + + outval = struct.pack(' "$OUTFILE" </{s:->#\(.*\):/* \1 */:; \ + s:^->\([^ ]*\) [\$\#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \ + s:->::; p;}" < "$INFILE" >> "$OUTFILE" +cat >> "$OUTFILE" < .tmp.config + $(Q)if [ -f .config ]; then \ + cmp -s .tmp.config .config || \ + (mv -f .config .config.old.1; \ + mv -f .tmp.config .config; \ + $(obj)/conf --silentoldconfig $(Kconfig); \ + mv -f .config.old.1 .config.old) \ + else \ + mv -f .tmp.config .config; \ + $(obj)/conf --silentoldconfig $(Kconfig); \ + fi + $(Q)rm -f .tmp.config + +localyesconfig: $(obj)/streamline_config.pl $(obj)/conf + $(Q)mkdir -p include/generated + $(Q)perl $< $(srctree) $(Kconfig) $(LSMOD_F) > .tmp.config + $(Q)sed -i s/=m/=y/ .tmp.config + $(Q)if [ -f .config ]; then \ + cmp -s .tmp.config .config || \ + (mv -f .config .config.old.1; \ + mv -f .tmp.config .config; \ + $(obj)/conf --silentoldconfig $(Kconfig); \ + mv -f .config.old.1 .config.old) \ + else \ + mv -f .tmp.config .config; \ + $(obj)/conf --silentoldconfig $(Kconfig); \ + fi + $(Q)rm -f .tmp.config + +# Create new linux.pot file +# Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files +# The symlink is used to repair a deficiency in arch/um +update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h + $(Q)echo " GEN config" + $(Q)xgettext --default-domain=linux \ + --add-comments --keyword=_ --keyword=N_ \ + --from-code=UTF-8 \ + --files-from=tools/kconfig/POTFILES.in \ + --output $(obj)/config.pot + $(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot + $(Q)ln -fs Kconfig.i386 arch/um/Kconfig.arch + $(Q)(for i in `ls arch/*/Kconfig`; \ + do \ + echo " GEN $$i"; \ + $(obj)/kxgettext $$i \ + >> $(obj)/config.pot; \ + done ) + $(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \ + --output $(obj)/linux.pot + $(Q)rm -f arch/um/Kconfig.arch + $(Q)rm -f $(obj)/config.pot + +PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig + +allnoconfig allyesconfig allmodconfig alldefconfig randconfig: $(obj)/conf + $< --$@ $(Kconfig) + +PHONY += listnewconfig oldnoconfig savedefconfig defconfig + +listnewconfig oldnoconfig: $(obj)/conf + $< --$@ $(Kconfig) + +savedefconfig: $(obj)/conf + $< --$@=defconfig $(Kconfig) + +defconfig: $(obj)/conf + @echo " Build default config" + $(Q)$< --defconfig=/dev/null $(Kconfig) + +# Help text used by make help +help: + @echo ' config - Update current config utilising a line-oriented program' + @echo ' nconfig - Update current config utilising a ncurses menu based program' + @echo ' menuconfig - Update current config utilising a menu based program' + @echo ' xconfig - Update current config utilising a QT based front-end' + @echo ' gconfig - Update current config utilising a GTK based front-end' + @echo ' oldconfig - Update current config utilising a provided .config as base' + @echo ' localmodconfig - Update current config disabling modules not loaded' + @echo ' localyesconfig - Update current config converting local mods to core' + @echo ' silentoldconfig - Same as oldconfig, but quietly, additionally update deps' + @echo ' defconfig - New config with default from ARCH supplied defconfig' + @echo ' savedefconfig - Save current config as ./defconfig (minimal config)' + @echo ' allnoconfig - New config where all options are answered with no' + @echo ' allyesconfig - New config where all options are accepted with yes' + @echo ' allmodconfig - New config selecting modules when possible' + @echo ' alldefconfig - New config with all symbols set to default' + @echo ' randconfig - New config with random answer to all options' + @echo ' listnewconfig - List new options' + @echo ' oldnoconfig - Same as silentoldconfig but set new symbols to n (unset)' + +# lxdialog stuff +check-lxdialog := $(srctree)/$(src)/lxdialog/check-lxdialog.sh + +# Use recursively expanded variables so we do not call gcc unless +# we really need to do so. (Do not call gcc as part of make mrproper) +HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \ + -DLOCALE + +# =========================================================================== +# Shared Makefile for the various kconfig executables: +# conf: Used for defconfig, oldconfig and related targets +# nconf: Used for the nconfig target. +# Utilizes ncurses +# mconf: Used for the menuconfig target +# Utilizes the lxdialog package +# qconf: Used for the xconfig target +# Based on QT which needs to be installed to compile it +# gconf: Used for the gconfig target +# Based on GTK which needs to be installed to compile it +# object files used by all kconfig flavours + +lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o +lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o + +conf-objs := conf.o zconf.tab.o +mconf-objs := mconf.o zconf.tab.o $(lxdialog) +nconf-objs := nconf.o zconf.tab.o nconf.gui.o +kxgettext-objs := kxgettext.o zconf.tab.o + +hostprogs-y := conf qconf gconf kxgettext + +ifeq ($(MAKECMDGOALS),nconfig) + hostprogs-y += nconf +endif + +ifeq ($(MAKECMDGOALS),menuconfig) + hostprogs-y += mconf +endif + +ifeq ($(MAKECMDGOALS),xconfig) + qconf-target := 1 +endif +ifeq ($(MAKECMDGOALS),gconfig) + gconf-target := 1 +endif + + +ifeq ($(qconf-target),1) +qconf-cxxobjs := qconf.o +qconf-objs := kconfig_load.o zconf.tab.o +endif + +ifeq ($(gconf-target),1) +gconf-objs := gconf.o kconfig_load.o zconf.tab.o +endif + +clean-files := lkc_defs.h qconf.moc .tmp_qtcheck \ + .tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c gconf.glade.h +clean-files += mconf qconf gconf nconf +clean-files += config.pot linux.pot + +# Check that we have the required ncurses stuff installed for lxdialog (menuconfig) +PHONY += $(obj)/dochecklxdialog +$(addprefix $(obj)/,$(lxdialog)): $(obj)/dochecklxdialog +$(obj)/dochecklxdialog: + $(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTLOADLIBES_mconf) + +always := dochecklxdialog + +# Add environment specific flags +HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(srctree)/$(src)/check.sh $(HOSTCC) $(HOSTCFLAGS)) + +# generated files seem to need this to find local include files +HOSTCFLAGS_lex.zconf.o := -I$(src) +HOSTCFLAGS_zconf.tab.o := -I$(src) + +HOSTLOADLIBES_qconf = $(KC_QT_LIBS) -ldl +HOSTCXXFLAGS_qconf.o = $(KC_QT_CFLAGS) -D LKC_DIRECT_LINK + +HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` -ldl +HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \ + -D LKC_DIRECT_LINK + +HOSTLOADLIBES_mconf = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC)) + +HOSTLOADLIBES_nconf = -lmenu -lpanel -lncurses +$(obj)/qconf.o: $(obj)/.tmp_qtcheck + +ifeq ($(qconf-target),1) +$(obj)/.tmp_qtcheck: $(src)/Makefile +-include $(obj)/.tmp_qtcheck + +# QT needs some extra effort... +$(obj)/.tmp_qtcheck: + @set -e; echo " CHECK qt"; dir=""; pkg=""; \ + if ! pkg-config --exists QtCore 2> /dev/null; then \ + echo "* Unable to find the QT4 tool qmake. Trying to use QT3"; \ + pkg-config --exists qt 2> /dev/null && pkg=qt; \ + pkg-config --exists qt-mt 2> /dev/null && pkg=qt-mt; \ + if [ -n "$$pkg" ]; then \ + cflags="\$$(shell pkg-config $$pkg --cflags)"; \ + libs="\$$(shell pkg-config $$pkg --libs)"; \ + moc="\$$(shell pkg-config $$pkg --variable=prefix)/bin/moc"; \ + dir="$$(pkg-config $$pkg --variable=prefix)"; \ + else \ + for d in $$QTDIR /usr/share/qt* /usr/lib/qt*; do \ + if [ -f $$d/include/qconfig.h ]; then dir=$$d; break; fi; \ + done; \ + if [ -z "$$dir" ]; then \ + echo "*"; \ + echo "* Unable to find any QT installation. Please make sure that"; \ + echo "* the QT4 or QT3 development package is correctly installed and"; \ + echo "* either qmake can be found or install pkg-config or set"; \ + echo "* the QTDIR environment variable to the correct location."; \ + echo "*"; \ + false; \ + fi; \ + libpath=$$dir/lib; lib=qt; osdir=""; \ + $(HOSTCXX) -print-multi-os-directory > /dev/null 2>&1 && \ + osdir=x$$($(HOSTCXX) -print-multi-os-directory); \ + test -d $$libpath/$$osdir && libpath=$$libpath/$$osdir; \ + test -f $$libpath/libqt-mt.so && lib=qt-mt; \ + cflags="-I$$dir/include"; \ + libs="-L$$libpath -Wl,-rpath,$$libpath -l$$lib"; \ + moc="$$dir/bin/moc"; \ + fi; \ + if [ ! -x $$dir/bin/moc -a -x /usr/bin/moc ]; then \ + echo "*"; \ + echo "* Unable to find $$dir/bin/moc, using /usr/bin/moc instead."; \ + echo "*"; \ + moc="/usr/bin/moc"; \ + fi; \ + else \ + cflags="\$$(shell pkg-config QtCore QtGui Qt3Support --cflags)"; \ + libs="\$$(shell pkg-config QtCore QtGui Qt3Support --libs)"; \ + binpath="\$$(shell pkg-config QtCore --variable=prefix)"; \ + moc="$$binpath/bin/moc"; \ + fi; \ + echo "KC_QT_CFLAGS=$$cflags" > $@; \ + echo "KC_QT_LIBS=$$libs" >> $@; \ + echo "KC_QT_MOC=$$moc" >> $@ +endif + +$(obj)/gconf.o: $(obj)/.tmp_gtkcheck + +ifeq ($(gconf-target),1) +-include $(obj)/.tmp_gtkcheck + +# GTK needs some extra effort, too... +$(obj)/.tmp_gtkcheck: + @if `pkg-config --exists gtk+-2.0 gmodule-2.0 libglade-2.0`; then \ + if `pkg-config --atleast-version=2.0.0 gtk+-2.0`; then \ + touch $@; \ + else \ + echo "*"; \ + echo "* GTK+ is present but version >= 2.0.0 is required."; \ + echo "*"; \ + false; \ + fi \ + else \ + echo "*"; \ + echo "* Unable to find the GTK+ installation. Please make sure that"; \ + echo "* the GTK+ 2.0 development package is correctly installed..."; \ + echo "* You need gtk+-2.0, glib-2.0 and libglade-2.0."; \ + echo "*"; \ + false; \ + fi +endif + +$(obj)/zconf.tab.o: $(obj)/lex.zconf.c $(obj)/zconf.hash.c + +$(obj)/kconfig_load.o: $(obj)/lkc_defs.h + +$(obj)/qconf.o: $(obj)/qconf.moc $(obj)/lkc_defs.h + +$(obj)/gconf.o: $(obj)/lkc_defs.h + +$(obj)/%.moc: $(src)/%.h + $(KC_QT_MOC) -i $< -o $@ + +$(obj)/lkc_defs.h: $(src)/lkc_proto.h + sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/' + +# Extract gconf menu items for I18N support +$(obj)/gconf.glade.h: $(obj)/gconf.glade + intltool-extract --type=gettext/glade $(obj)/gconf.glade + +### +# The following requires flex/bison/gperf +# By default we use the _shipped versions, uncomment the following line if +# you are modifying the flex/bison src. +# LKC_GENPARSER := 1 + +ifdef LKC_GENPARSER + +$(obj)/zconf.tab.c: $(src)/zconf.y +$(obj)/lex.zconf.c: $(src)/zconf.l +$(obj)/zconf.hash.c: $(src)/zconf.gperf + +%.tab.c: %.y + bison -l -b $* -p $(notdir $*) $< + cp $@ $@_shipped + +lex.%.c: %.l + flex -L -P$(notdir $*) -o$@ $< + cp $@ $@_shipped + +%.hash.c: %.gperf + gperf < $< > $@ + cp $@ $@_shipped + +endif + +VPATH := $(srctree) + +$(obj)/%:: $(src)/%_shipped + $(Q)cat $< > $@ + +host-cobjs := $(sort $(foreach m,$(hostprogs-y),$($(m)-objs))) +host-cobjs := $(addprefix $(obj)/,$(host-cobjs)) +hostprogs-y := $(addprefix $(obj)/,$(hostprogs-y)) +$(host-cobjs) : $(obj)/%.o : $(src)/%.c + $(Q)$(HOSTCC) -I$(obj) -I$(srctree)/$(src) $(HOSTCFLAGS) $(HOSTCFLAGS_$(@F)) $(HOST_EXTRACFLAGS) -c -o $@ $< +$(hostprogs-y) : $(obj)/% : $(host-cobjs) + $(Q)$(HOSTCC) $(HOSTLDFLAGS) -o $@ $(addprefix $(obj)/,$($(@F)-objs)) $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F)) diff --git a/bios/seabios/tools/kconfig/POTFILES.in b/bios/seabios/tools/kconfig/POTFILES.in new file mode 100644 index 0000000..f0baccd --- /dev/null +++ b/bios/seabios/tools/kconfig/POTFILES.in @@ -0,0 +1,12 @@ +tools/kconfig/lxdialog/checklist.c +tools/kconfig/lxdialog/inputbox.c +tools/kconfig/lxdialog/menubox.c +tools/kconfig/lxdialog/textbox.c +tools/kconfig/lxdialog/util.c +tools/kconfig/lxdialog/yesno.c +tools/kconfig/mconf.c +tools/kconfig/conf.c +tools/kconfig/confdata.c +tools/kconfig/gconf.c +tools/kconfig/gconf.glade.h +tools/kconfig/qconf.cc diff --git a/bios/seabios/tools/kconfig/check.sh b/bios/seabios/tools/kconfig/check.sh new file mode 100755 index 0000000..fa59cbf --- /dev/null +++ b/bios/seabios/tools/kconfig/check.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# Needed for systems without gettext +$* -xc -o /dev/null - > /dev/null 2>&1 << EOF +#include +int main() +{ + gettext(""); + return 0; +} +EOF +if [ ! "$?" -eq "0" ]; then + echo -DKBUILD_NO_NLS; +fi + diff --git a/bios/seabios/tools/kconfig/conf.c b/bios/seabios/tools/kconfig/conf.c new file mode 100644 index 0000000..659326c --- /dev/null +++ b/bios/seabios/tools/kconfig/conf.c @@ -0,0 +1,654 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +static void conf(struct menu *menu); +static void check_conf(struct menu *menu); + +enum input_mode { + oldaskconfig, + silentoldconfig, + oldconfig, + allnoconfig, + allyesconfig, + allmodconfig, + alldefconfig, + randconfig, + defconfig, + savedefconfig, + listnewconfig, + oldnoconfig, +} input_mode = oldaskconfig; + +char *defconfig_file; + +static int indent = 1; +static int valid_stdin = 1; +static int sync_kconfig; +static int conf_cnt; +static char line[128]; +static struct menu *rootEntry; + +static void print_help(struct menu *menu) +{ + struct gstr help = str_new(); + + menu_get_ext_help(menu, &help); + + printf("\n%s\n", str_get(&help)); + str_free(&help); +} + +static void strip(char *str) +{ + char *p = str; + int l; + + while ((isspace(*p))) + p++; + l = strlen(p); + if (p != str) + memmove(str, p, l + 1); + if (!l) + return; + p = str + l - 1; + while ((isspace(*p))) + *p-- = 0; +} + +static void check_stdin(void) +{ + if (!valid_stdin) { + printf(_("aborted!\n\n")); + printf(_("Console input/output is redirected. ")); + printf(_("Run 'make oldconfig' to update configuration.\n\n")); + exit(1); + } +} + +static int conf_askvalue(struct symbol *sym, const char *def) +{ + enum symbol_type type = sym_get_type(sym); + + if (!sym_has_value(sym)) + printf(_("(NEW) ")); + + line[0] = '\n'; + line[1] = 0; + + if (!sym_is_changable(sym)) { + printf("%s\n", def); + line[0] = '\n'; + line[1] = 0; + return 0; + } + + switch (input_mode) { + case oldconfig: + case silentoldconfig: + if (sym_has_value(sym)) { + printf("%s\n", def); + return 0; + } + check_stdin(); + case oldaskconfig: + fflush(stdout); + xfgets(line, 128, stdin); + return 1; + default: + break; + } + + switch (type) { + case S_INT: + case S_HEX: + case S_STRING: + printf("%s\n", def); + return 1; + default: + ; + } + printf("%s", line); + return 1; +} + +static int conf_string(struct menu *menu) +{ + struct symbol *sym = menu->sym; + const char *def; + + while (1) { + printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); + printf("(%s) ", sym->name); + def = sym_get_string_value(sym); + if (sym_get_string_value(sym)) + printf("[%s] ", def); + if (!conf_askvalue(sym, def)) + return 0; + switch (line[0]) { + case '\n': + break; + case '?': + /* print help */ + if (line[1] == '\n') { + print_help(menu); + def = NULL; + break; + } + default: + line[strlen(line)-1] = 0; + def = line; + } + if (def && sym_set_string_value(sym, def)) + return 0; + } +} + +static int conf_sym(struct menu *menu) +{ + struct symbol *sym = menu->sym; + tristate oldval, newval; + + while (1) { + printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); + if (sym->name) + printf("(%s) ", sym->name); + putchar('['); + oldval = sym_get_tristate_value(sym); + switch (oldval) { + case no: + putchar('N'); + break; + case mod: + putchar('M'); + break; + case yes: + putchar('Y'); + break; + } + if (oldval != no && sym_tristate_within_range(sym, no)) + printf("/n"); + if (oldval != mod && sym_tristate_within_range(sym, mod)) + printf("/m"); + if (oldval != yes && sym_tristate_within_range(sym, yes)) + printf("/y"); + if (menu_has_help(menu)) + printf("/?"); + printf("] "); + if (!conf_askvalue(sym, sym_get_string_value(sym))) + return 0; + strip(line); + + switch (line[0]) { + case 'n': + case 'N': + newval = no; + if (!line[1] || !strcmp(&line[1], "o")) + break; + continue; + case 'm': + case 'M': + newval = mod; + if (!line[1]) + break; + continue; + case 'y': + case 'Y': + newval = yes; + if (!line[1] || !strcmp(&line[1], "es")) + break; + continue; + case 0: + newval = oldval; + break; + case '?': + goto help; + default: + continue; + } + if (sym_set_tristate_value(sym, newval)) + return 0; +help: + print_help(menu); + } +} + +static int conf_choice(struct menu *menu) +{ + struct symbol *sym, *def_sym; + struct menu *child; + bool is_new; + + sym = menu->sym; + is_new = !sym_has_value(sym); + if (sym_is_changable(sym)) { + conf_sym(menu); + sym_calc_value(sym); + switch (sym_get_tristate_value(sym)) { + case no: + return 1; + case mod: + return 0; + case yes: + break; + } + } else { + switch (sym_get_tristate_value(sym)) { + case no: + return 1; + case mod: + printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu))); + return 0; + case yes: + break; + } + } + + while (1) { + int cnt, def; + + printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu))); + def_sym = sym_get_choice_value(sym); + cnt = def = 0; + line[0] = 0; + for (child = menu->list; child; child = child->next) { + if (!menu_is_visible(child)) + continue; + if (!child->sym) { + printf("%*c %s\n", indent, '*', _(menu_get_prompt(child))); + continue; + } + cnt++; + if (child->sym == def_sym) { + def = cnt; + printf("%*c", indent, '>'); + } else + printf("%*c", indent, ' '); + printf(" %d. %s", cnt, _(menu_get_prompt(child))); + if (child->sym->name) + printf(" (%s)", child->sym->name); + if (!sym_has_value(child->sym)) + printf(_(" (NEW)")); + printf("\n"); + } + printf(_("%*schoice"), indent - 1, ""); + if (cnt == 1) { + printf("[1]: 1\n"); + goto conf_childs; + } + printf("[1-%d", cnt); + if (menu_has_help(menu)) + printf("?"); + printf("]: "); + switch (input_mode) { + case oldconfig: + case silentoldconfig: + if (!is_new) { + cnt = def; + printf("%d\n", cnt); + break; + } + check_stdin(); + case oldaskconfig: + fflush(stdout); + xfgets(line, 128, stdin); + strip(line); + if (line[0] == '?') { + print_help(menu); + continue; + } + if (!line[0]) + cnt = def; + else if (isdigit(line[0])) + cnt = atoi(line); + else + continue; + break; + default: + break; + } + + conf_childs: + for (child = menu->list; child; child = child->next) { + if (!child->sym || !menu_is_visible(child)) + continue; + if (!--cnt) + break; + } + if (!child) + continue; + if (line[strlen(line) - 1] == '?') { + print_help(child); + continue; + } + sym_set_choice_value(sym, child->sym); + for (child = child->list; child; child = child->next) { + indent += 2; + conf(child); + indent -= 2; + } + return 1; + } +} + +static void conf(struct menu *menu) +{ + struct symbol *sym; + struct property *prop; + struct menu *child; + + if (!menu_is_visible(menu)) + return; + + sym = menu->sym; + prop = menu->prompt; + if (prop) { + const char *prompt; + + switch (prop->type) { + case P_MENU: + if ((input_mode == silentoldconfig || + input_mode == listnewconfig || + input_mode == oldnoconfig) && + rootEntry != menu) { + check_conf(menu); + return; + } + case P_COMMENT: + prompt = menu_get_prompt(menu); + if (prompt) + printf("%*c\n%*c %s\n%*c\n", + indent, '*', + indent, '*', _(prompt), + indent, '*'); + default: + ; + } + } + + if (!sym) + goto conf_childs; + + if (sym_is_choice(sym)) { + conf_choice(menu); + if (sym->curr.tri != mod) + return; + goto conf_childs; + } + + switch (sym->type) { + case S_INT: + case S_HEX: + case S_STRING: + conf_string(menu); + break; + default: + conf_sym(menu); + break; + } + +conf_childs: + if (sym) + indent += 2; + for (child = menu->list; child; child = child->next) + conf(child); + if (sym) + indent -= 2; +} + +static void check_conf(struct menu *menu) +{ + struct symbol *sym; + struct menu *child; + + if (!menu_is_visible(menu)) + return; + + sym = menu->sym; + if (sym && !sym_has_value(sym)) { + if (sym_is_changable(sym) || + (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) { + if (input_mode == listnewconfig) { + if (sym->name && !sym_is_choice_value(sym)) { + printf("%s%s\n", CONFIG_, sym->name); + } + } else if (input_mode != oldnoconfig) { + if (!conf_cnt++) + printf(_("*\n* Restart config...\n*\n")); + rootEntry = menu_get_parent_menu(menu); + conf(rootEntry); + } + } + } + + for (child = menu->list; child; child = child->next) + check_conf(child); +} + +static struct option long_opts[] = { + {"oldaskconfig", no_argument, NULL, oldaskconfig}, + {"oldconfig", no_argument, NULL, oldconfig}, + {"silentoldconfig", no_argument, NULL, silentoldconfig}, + {"defconfig", optional_argument, NULL, defconfig}, + {"savedefconfig", required_argument, NULL, savedefconfig}, + {"allnoconfig", no_argument, NULL, allnoconfig}, + {"allyesconfig", no_argument, NULL, allyesconfig}, + {"allmodconfig", no_argument, NULL, allmodconfig}, + {"alldefconfig", no_argument, NULL, alldefconfig}, + {"randconfig", no_argument, NULL, randconfig}, + {"listnewconfig", no_argument, NULL, listnewconfig}, + {"oldnoconfig", no_argument, NULL, oldnoconfig}, + {NULL, 0, NULL, 0} +}; + +int main(int ac, char **av) +{ + int opt; + const char *name; + struct stat tmpstat; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + while ((opt = getopt_long(ac, av, "", long_opts, NULL)) != -1) { + input_mode = (enum input_mode)opt; + switch (opt) { + case silentoldconfig: + sync_kconfig = 1; + break; + case defconfig: + case savedefconfig: + defconfig_file = optarg; + break; + case randconfig: + { + struct timeval now; + unsigned int seed; + + /* + * Use microseconds derived seed, + * compensate for systems where it may be zero + */ + gettimeofday(&now, NULL); + + seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1)); + srand(seed); + break; + } + case '?': + fprintf(stderr, _("See README for usage info\n")); + exit(1); + break; + } + } + if (ac == optind) { + printf(_("%s: Kconfig file missing\n"), av[0]); + exit(1); + } + name = av[optind]; + conf_parse(name); + //zconfdump(stdout); + if (sync_kconfig) { + name = conf_get_configname(); + if (stat(name, &tmpstat)) { + fprintf(stderr, _("***\n" + "*** Configuration file \"%s\" not found!\n" + "***\n" + "*** Please run some configurator (e.g. \"make oldconfig\" or\n" + "*** \"make menuconfig\" or \"make xconfig\").\n" + "***\n"), name); + exit(1); + } + } + + switch (input_mode) { + case defconfig: + if (!defconfig_file) + defconfig_file = conf_get_default_confname(); + if (conf_read(defconfig_file)) { + printf(_("***\n" + "*** Can't find default configuration \"%s\"!\n" + "***\n"), defconfig_file); + exit(1); + } + break; + case savedefconfig: + case silentoldconfig: + case oldaskconfig: + case oldconfig: + case listnewconfig: + case oldnoconfig: + conf_read(NULL); + break; + case allnoconfig: + case allyesconfig: + case allmodconfig: + case alldefconfig: + case randconfig: + name = getenv("KCONFIG_ALLCONFIG"); + if (name && !stat(name, &tmpstat)) { + conf_read_simple(name, S_DEF_USER); + break; + } + switch (input_mode) { + case allnoconfig: name = "allno.config"; break; + case allyesconfig: name = "allyes.config"; break; + case allmodconfig: name = "allmod.config"; break; + case alldefconfig: name = "alldef.config"; break; + case randconfig: name = "allrandom.config"; break; + default: break; + } + if (!stat(name, &tmpstat)) + conf_read_simple(name, S_DEF_USER); + else if (!stat("all.config", &tmpstat)) + conf_read_simple("all.config", S_DEF_USER); + break; + default: + break; + } + + if (sync_kconfig) { + if (conf_get_changed()) { + name = getenv("KCONFIG_NOSILENTUPDATE"); + if (name && *name) { + fprintf(stderr, + _("\n*** The configuration requires explicit update.\n\n")); + return 1; + } + } + valid_stdin = isatty(0) && isatty(1) && isatty(2); + } + + switch (input_mode) { + case allnoconfig: + conf_set_all_new_symbols(def_no); + break; + case allyesconfig: + conf_set_all_new_symbols(def_yes); + break; + case allmodconfig: + conf_set_all_new_symbols(def_mod); + break; + case alldefconfig: + conf_set_all_new_symbols(def_default); + break; + case randconfig: + conf_set_all_new_symbols(def_random); + break; + case defconfig: + conf_set_all_new_symbols(def_default); + break; + case savedefconfig: + break; + case oldaskconfig: + rootEntry = &rootmenu; + conf(&rootmenu); + input_mode = silentoldconfig; + /* fall through */ + case oldconfig: + case listnewconfig: + case oldnoconfig: + case silentoldconfig: + /* Update until a loop caused no more changes */ + do { + conf_cnt = 0; + check_conf(&rootmenu); + } while (conf_cnt && + (input_mode != listnewconfig && + input_mode != oldnoconfig)); + break; + } + + if (sync_kconfig) { + /* silentoldconfig is used during the build so we shall update autoconf. + * All other commands are only used to generate a config. + */ + if (conf_get_changed() && conf_write(NULL)) { + fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); + exit(1); + } + if (conf_write_autoconf()) { + fprintf(stderr, _("\n*** Error during update of the configuration.\n\n")); + return 1; + } + } else if (input_mode == savedefconfig) { + if (conf_write_defconfig(defconfig_file)) { + fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"), + defconfig_file); + return 1; + } + } else if (input_mode != listnewconfig) { + if (conf_write(NULL)) { + fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); + exit(1); + } + } + return 0; +} +/* + * Helper function to facilitate fgets() by Jean Sacren. + */ +void xfgets(str, size, in) + char *str; + int size; + FILE *in; +{ + if (fgets(str, size, in) == NULL) + fprintf(stderr, "\nError in reading or end of file.\n"); +} diff --git a/bios/seabios/tools/kconfig/confdata.c b/bios/seabios/tools/kconfig/confdata.c new file mode 100644 index 0000000..f110bf5 --- /dev/null +++ b/bios/seabios/tools/kconfig/confdata.c @@ -0,0 +1,1062 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +static void conf_warning(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +static void conf_message(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +static const char *conf_filename; +static int conf_lineno, conf_warnings, conf_unsaved; + +const char conf_defname[] = "arch/$ARCH/defconfig"; + +static void conf_warning(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + conf_warnings++; +} + +static void conf_default_message_callback(const char *fmt, va_list ap) +{ + printf("#\n# "); + vprintf(fmt, ap); + printf("\n#\n"); +} + +static void (*conf_message_callback) (const char *fmt, va_list ap) = + conf_default_message_callback; +void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap)) +{ + conf_message_callback = fn; +} + +static void conf_message(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (conf_message_callback) + conf_message_callback(fmt, ap); +} + +const char *conf_get_configname(void) +{ + char *name = getenv("KCONFIG_CONFIG"); + + return name ? name : ".config"; +} + +const char *conf_get_autoconfig_name(void) +{ + char *name = getenv("KCONFIG_AUTOCONFIG"); + + return name ? name : "include/config/auto.conf"; +} + +static char *conf_expand_value(const char *in) +{ + struct symbol *sym; + const char *src; + static char res_value[SYMBOL_MAXLENGTH]; + char *dst, name[SYMBOL_MAXLENGTH]; + + res_value[0] = 0; + dst = name; + while ((src = strchr(in, '$'))) { + strncat(res_value, in, src - in); + src++; + dst = name; + while (isalnum(*src) || *src == '_') + *dst++ = *src++; + *dst = 0; + sym = sym_lookup(name, 0); + sym_calc_value(sym); + strcat(res_value, sym_get_string_value(sym)); + in = src; + } + strcat(res_value, in); + + return res_value; +} + +char *conf_get_default_confname(void) +{ + struct stat buf; + static char fullname[PATH_MAX+1]; + char *env, *name; + + name = conf_expand_value(conf_defname); + env = getenv(SRCTREE); + if (env) { + sprintf(fullname, "%s/%s", env, name); + if (!stat(fullname, &buf)) + return fullname; + } + return name; +} + +static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) +{ + char *p2; + + switch (sym->type) { + case S_TRISTATE: + if (p[0] == 'm') { + sym->def[def].tri = mod; + sym->flags |= def_flags; + break; + } + case S_BOOLEAN: + if (p[0] == 'y') { + sym->def[def].tri = yes; + sym->flags |= def_flags; + break; + } + if (p[0] == 'n') { + sym->def[def].tri = no; + sym->flags |= def_flags; + break; + } + conf_warning("symbol value '%s' invalid for %s", p, sym->name); + break; + case S_OTHER: + if (*p != '"') { + for (p2 = p; *p2 && !isspace(*p2); p2++) + ; + sym->type = S_STRING; + goto done; + } + case S_STRING: + if (*p++ != '"') + break; + for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { + if (*p2 == '"') { + *p2 = 0; + break; + } + memmove(p2, p2 + 1, strlen(p2)); + } + if (!p2) { + conf_warning("invalid string found"); + return 1; + } + case S_INT: + case S_HEX: + done: + if (sym_string_valid(sym, p)) { + sym->def[def].val = strdup(p); + sym->flags |= def_flags; + } else { + conf_warning("symbol value '%s' invalid for %s", p, sym->name); + return 1; + } + break; + default: + ; + } + return 0; +} + +int conf_read_simple(const char *name, int def) +{ + FILE *in = NULL; + char line[1024]; + char *p, *p2; + struct symbol *sym; + int i, def_flags; + + if (name) { + in = zconf_fopen(name); + } else { + struct property *prop; + + name = conf_get_configname(); + in = zconf_fopen(name); + if (in) + goto load; + sym_add_change_count(1); + if (!sym_defconfig_list) { + if (modules_sym) + sym_calc_value(modules_sym); + return 1; + } + + for_all_defaults(sym_defconfig_list, prop) { + if (expr_calc_value(prop->visible.expr) == no || + prop->expr->type != E_SYMBOL) + continue; + name = conf_expand_value(prop->expr->left.sym->name); + in = zconf_fopen(name); + if (in) { + conf_message(_("using defaults found in %s"), + name); + goto load; + } + } + } + if (!in) + return 1; + +load: + conf_filename = name; + conf_lineno = 0; + conf_warnings = 0; + conf_unsaved = 0; + + def_flags = SYMBOL_DEF << def; + for_all_symbols(i, sym) { + sym->flags |= SYMBOL_CHANGED; + sym->flags &= ~(def_flags|SYMBOL_VALID); + if (sym_is_choice(sym)) + sym->flags |= def_flags; + switch (sym->type) { + case S_INT: + case S_HEX: + case S_STRING: + if (sym->def[def].val) + free(sym->def[def].val); + default: + sym->def[def].val = NULL; + sym->def[def].tri = no; + } + } + + while (fgets(line, sizeof(line), in)) { + conf_lineno++; + sym = NULL; + if (line[0] == '#') { + if (memcmp(line + 2, CONFIG_, strlen(CONFIG_))) + continue; + p = strchr(line + 2 + strlen(CONFIG_), ' '); + if (!p) + continue; + *p++ = 0; + if (strncmp(p, "is not set", 10)) + continue; + if (def == S_DEF_USER) { + sym = sym_find(line + 2 + strlen(CONFIG_)); + if (!sym) { + sym_add_change_count(1); + goto setsym; + } + } else { + sym = sym_lookup(line + 2 + strlen(CONFIG_), 0); + if (sym->type == S_UNKNOWN) + sym->type = S_BOOLEAN; + } + if (sym->flags & def_flags) { + conf_warning("override: reassigning to symbol %s", sym->name); + } + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + sym->def[def].tri = no; + sym->flags |= def_flags; + break; + default: + ; + } + } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) { + p = strchr(line + strlen(CONFIG_), '='); + if (!p) + continue; + *p++ = 0; + p2 = strchr(p, '\n'); + if (p2) { + *p2-- = 0; + if (*p2 == '\r') + *p2 = 0; + } + if (def == S_DEF_USER) { + sym = sym_find(line + strlen(CONFIG_)); + if (!sym) { + sym_add_change_count(1); + goto setsym; + } + } else { + sym = sym_lookup(line + strlen(CONFIG_), 0); + if (sym->type == S_UNKNOWN) + sym->type = S_OTHER; + } + if (sym->flags & def_flags) { + conf_warning("override: reassigning to symbol %s", sym->name); + } + if (conf_set_sym_val(sym, def, def_flags, p)) + continue; + } else { + if (line[0] != '\r' && line[0] != '\n') + conf_warning("unexpected data"); + continue; + } +setsym: + if (sym && sym_is_choice_value(sym)) { + struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); + switch (sym->def[def].tri) { + case no: + break; + case mod: + if (cs->def[def].tri == yes) { + conf_warning("%s creates inconsistent choice state", sym->name); + cs->flags &= ~def_flags; + } + break; + case yes: + if (cs->def[def].tri != no) + conf_warning("override: %s changes choice state", sym->name); + cs->def[def].val = sym; + break; + } + cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri); + } + } + fclose(in); + + if (modules_sym) + sym_calc_value(modules_sym); + return 0; +} + +int conf_read(const char *name) +{ + struct symbol *sym, *choice_sym; + struct property *prop; + struct expr *e; + int i, flags; + + sym_set_change_count(0); + + if (conf_read_simple(name, S_DEF_USER)) + return 1; + + for_all_symbols(i, sym) { + sym_calc_value(sym); + if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO)) + goto sym_ok; + if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) { + /* check that calculated value agrees with saved value */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym)) + break; + if (!sym_is_choice(sym)) + goto sym_ok; + default: + if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val)) + goto sym_ok; + break; + } + } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE)) + /* no previous value and not saved */ + goto sym_ok; + conf_unsaved++; + /* maybe print value in verbose mode... */ + sym_ok: + if (!sym_is_choice(sym)) + continue; + /* The choice symbol only has a set value (and thus is not new) + * if all its visible childs have values. + */ + prop = sym_get_choice_prop(sym); + flags = sym->flags; + expr_list_for_each_sym(prop->expr, e, choice_sym) + if (choice_sym->visible != no) + flags &= choice_sym->flags; + sym->flags &= flags | ~SYMBOL_DEF_USER; + } + + for_all_symbols(i, sym) { + if (sym_has_value(sym) && !sym_is_choice_value(sym)) { + /* Reset values of generates values, so they'll appear + * as new, if they should become visible, but that + * doesn't quite work if the Kconfig and the saved + * configuration disagree. + */ + if (sym->visible == no && !conf_unsaved) + sym->flags &= ~SYMBOL_DEF_USER; + switch (sym->type) { + case S_STRING: + case S_INT: + case S_HEX: + /* Reset a string value if it's out of range */ + if (sym_string_within_range(sym, sym->def[S_DEF_USER].val)) + break; + sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER); + conf_unsaved++; + break; + default: + break; + } + } + } + + sym_add_change_count(conf_warnings || conf_unsaved); + + return 0; +} + +/* Write a S_STRING */ +static void conf_write_string(bool headerfile, const char *name, + const char *str, FILE *out) +{ + int l; + if (headerfile) + fprintf(out, "#define %s%s \"", CONFIG_, name); + else + fprintf(out, "%s%s=\"", CONFIG_, name); + + while (1) { + l = strcspn(str, "\"\\"); + if (l) { + xfwrite(str, l, 1, out); + str += l; + } + if (!*str) + break; + fprintf(out, "\\%c", *str++); + } + fputs("\"\n", out); +} + +static void conf_write_symbol(struct symbol *sym, FILE *out, bool write_no) +{ + const char *str; + + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + switch (sym_get_tristate_value(sym)) { + case no: + if (write_no) + fprintf(out, "# %s%s is not set\n", + CONFIG_, sym->name); + break; + case mod: + fprintf(out, "%s%s=m\n", CONFIG_, sym->name); + break; + case yes: + fprintf(out, "%s%s=y\n", CONFIG_, sym->name); + break; + } + break; + case S_STRING: + conf_write_string(false, sym->name, sym_get_string_value(sym), out); + break; + case S_HEX: + case S_INT: + str = sym_get_string_value(sym); + fprintf(out, "%s%s=%s\n", CONFIG_, sym->name, str); + break; + case S_OTHER: + case S_UNKNOWN: + break; + } +} + +/* + * Write out a minimal config. + * All values that has default values are skipped as this is redundant. + */ +int conf_write_defconfig(const char *filename) +{ + struct symbol *sym; + struct menu *menu; + FILE *out; + + out = fopen(filename, "w"); + if (!out) + return 1; + + sym_clear_all_valid(); + + /* Traverse all menus to find all relevant symbols */ + menu = rootmenu.list; + + while (menu != NULL) + { + sym = menu->sym; + if (sym == NULL) { + if (!menu_is_visible(menu)) + goto next_menu; + } else if (!sym_is_choice(sym)) { + sym_calc_value(sym); + if (!(sym->flags & SYMBOL_WRITE)) + goto next_menu; + sym->flags &= ~SYMBOL_WRITE; + /* If we cannot change the symbol - skip */ + if (!sym_is_changable(sym)) + goto next_menu; + /* If symbol equals to default value - skip */ + if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0) + goto next_menu; + + /* + * If symbol is a choice value and equals to the + * default for a choice - skip. + * But only if value is bool and equal to "y" and + * choice is not "optional". + * (If choice is "optional" then all values can be "n") + */ + if (sym_is_choice_value(sym)) { + struct symbol *cs; + struct symbol *ds; + + cs = prop_get_symbol(sym_get_choice_prop(sym)); + ds = sym_choice_default(cs); + if (!sym_is_optional(cs) && sym == ds) { + if ((sym->type == S_BOOLEAN) && + sym_get_tristate_value(sym) == yes) + goto next_menu; + } + } + conf_write_symbol(sym, out, true); + } +next_menu: + if (menu->list != NULL) { + menu = menu->list; + } + else if (menu->next != NULL) { + menu = menu->next; + } else { + while ((menu = menu->parent)) { + if (menu->next != NULL) { + menu = menu->next; + break; + } + } + } + } + fclose(out); + return 0; +} + +int conf_write(const char *name) +{ + FILE *out; + struct symbol *sym; + struct menu *menu; + const char *basename; + const char *str; + char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1]; + time_t now; + int use_timestamp = 1; + char *env; + + dirname[0] = 0; + if (name && name[0]) { + struct stat st; + char *slash; + + if (!stat(name, &st) && S_ISDIR(st.st_mode)) { + strcpy(dirname, name); + strcat(dirname, "/"); + basename = conf_get_configname(); + } else if ((slash = strrchr(name, '/'))) { + int size = slash - name + 1; + memcpy(dirname, name, size); + dirname[size] = 0; + if (slash[1]) + basename = slash + 1; + else + basename = conf_get_configname(); + } else + basename = name; + } else + basename = conf_get_configname(); + + sprintf(newname, "%s%s", dirname, basename); + env = getenv("KCONFIG_OVERWRITECONFIG"); + if (!env || !*env) { + sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid()); + out = fopen(tmpname, "w"); + } else { + *tmpname = 0; + out = fopen(newname, "w"); + } + if (!out) + return 1; + + time(&now); + env = getenv("KCONFIG_NOTIMESTAMP"); + if (env && *env) + use_timestamp = 0; + + fprintf(out, _("#\n" + "# Automatically generated make config: don't edit\n" + "# %s\n" + "%s%s" + "#\n"), + rootmenu.prompt->text, + use_timestamp ? "# " : "", + use_timestamp ? ctime(&now) : ""); + + if (!conf_get_changed()) + sym_clear_all_valid(); + + menu = rootmenu.list; + while (menu) { + sym = menu->sym; + if (!sym) { + if (!menu_is_visible(menu)) + goto next; + str = menu_get_prompt(menu); + fprintf(out, "\n" + "#\n" + "# %s\n" + "#\n", str); + } else if (!(sym->flags & SYMBOL_CHOICE)) { + sym_calc_value(sym); + if (!(sym->flags & SYMBOL_WRITE)) + goto next; + sym->flags &= ~SYMBOL_WRITE; + /* Write config symbol to file */ + conf_write_symbol(sym, out, true); + } + +next: + if (menu->list) { + menu = menu->list; + continue; + } + if (menu->next) + menu = menu->next; + else while ((menu = menu->parent)) { + if (menu->next) { + menu = menu->next; + break; + } + } + } + fclose(out); + + if (*tmpname) { + strcat(dirname, basename); + strcat(dirname, ".old"); + rename(newname, dirname); + if (rename(tmpname, newname)) + return 1; + } + + conf_message(_("configuration written to %s"), newname); + + sym_set_change_count(0); + + return 0; +} + +static int conf_split_config(void) +{ + const char *name; + char path[PATH_MAX+1]; + char *s, *d, c; + struct symbol *sym; + struct stat sb; + int res, i, fd; + + name = conf_get_autoconfig_name(); + conf_read_simple(name, S_DEF_AUTO); + + if (chdir("include/config")) + return 1; + + res = 0; + for_all_symbols(i, sym) { + sym_calc_value(sym); + if ((sym->flags & SYMBOL_AUTO) || !sym->name) + continue; + if (sym->flags & SYMBOL_WRITE) { + if (sym->flags & SYMBOL_DEF_AUTO) { + /* + * symbol has old and new value, + * so compare them... + */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym_get_tristate_value(sym) == + sym->def[S_DEF_AUTO].tri) + continue; + break; + case S_STRING: + case S_HEX: + case S_INT: + if (!strcmp(sym_get_string_value(sym), + sym->def[S_DEF_AUTO].val)) + continue; + break; + default: + break; + } + } else { + /* + * If there is no old value, only 'no' (unset) + * is allowed as new value. + */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym_get_tristate_value(sym) == no) + continue; + break; + default: + break; + } + } + } else if (!(sym->flags & SYMBOL_DEF_AUTO)) + /* There is neither an old nor a new value. */ + continue; + /* else + * There is an old value, but no new value ('no' (unset) + * isn't saved in auto.conf, so the old value is always + * different from 'no'). + */ + + /* Replace all '_' and append ".h" */ + s = sym->name; + d = path; + while ((c = *s++)) { + c = tolower(c); + *d++ = (c == '_') ? '/' : c; + } + strcpy(d, ".h"); + + /* Assume directory path already exists. */ + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { + if (errno != ENOENT) { + res = 1; + break; + } + /* + * Create directory components, + * unless they exist already. + */ + d = path; + while ((d = strchr(d, '/'))) { + *d = 0; + if (stat(path, &sb) && mkdir(path, 0755)) { + res = 1; + goto out; + } + *d++ = '/'; + } + /* Try it again. */ + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { + res = 1; + break; + } + } + close(fd); + } +out: + if (chdir("../..")) + return 1; + + return res; +} + +int conf_write_autoconf(void) +{ + struct symbol *sym; + const char *str; + const char *name; + FILE *out, *tristate, *out_h; + time_t now; + int i; + + sym_clear_all_valid(); + + file_write_dep("include/config/auto.conf.cmd"); + + if (conf_split_config()) + return 1; + + out = fopen(".tmpconfig", "w"); + if (!out) + return 1; + + tristate = fopen(".tmpconfig_tristate", "w"); + if (!tristate) { + fclose(out); + return 1; + } + + out_h = fopen(".tmpconfig.h", "w"); + if (!out_h) { + fclose(out); + fclose(tristate); + return 1; + } + + time(&now); + fprintf(out, "#\n" + "# Automatically generated make config: don't edit\n" + "# %s\n" + "# %s" + "#\n", + rootmenu.prompt->text, ctime(&now)); + fprintf(tristate, "#\n" + "# Automatically generated - do not edit\n" + "\n"); + fprintf(out_h, "/*\n" + " * Automatically generated C config: don't edit\n" + " * %s\n" + " * %s" + " */\n", + rootmenu.prompt->text, ctime(&now)); + + for_all_symbols(i, sym) { + sym_calc_value(sym); + if (!sym->name) + continue; + if (!(sym->flags & SYMBOL_WRITE)) { + if (sym->type == S_BOOLEAN || sym->type == S_HEX + || sym->type == S_INT) + fprintf(out_h, "#define %s%s 0\n", + CONFIG_, sym->name); + continue; + } + + /* write symbol to config file */ + conf_write_symbol(sym, out, false); + + /* update autoconf and tristate files */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + switch (sym_get_tristate_value(sym)) { + case no: + fprintf(out_h, "#define %s%s 0\n", + CONFIG_, sym->name); + break; + case mod: + fprintf(tristate, "%s%s=M\n", + CONFIG_, sym->name); + fprintf(out_h, "#define %s%s_MODULE 1\n", + CONFIG_, sym->name); + break; + case yes: + if (sym->type == S_TRISTATE) + fprintf(tristate,"%s%s=Y\n", + CONFIG_, sym->name); + fprintf(out_h, "#define %s%s 1\n", + CONFIG_, sym->name); + break; + } + break; + case S_STRING: + conf_write_string(true, sym->name, sym_get_string_value(sym), out_h); + break; + case S_HEX: + str = sym_get_string_value(sym); + if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) { + fprintf(out_h, "#define %s%s 0x%s\n", + CONFIG_, sym->name, str); + break; + } + case S_INT: + str = sym_get_string_value(sym); + fprintf(out_h, "#define %s%s %s\n", + CONFIG_, sym->name, str); + break; + default: + break; + } + } + fclose(out); + fclose(tristate); + fclose(out_h); + + name = getenv("KCONFIG_AUTOHEADER"); + if (!name) + name = "include/generated/autoconf.h"; + if (rename(".tmpconfig.h", name)) + return 1; + name = getenv("KCONFIG_TRISTATE"); + if (!name) + name = "include/config/tristate.conf"; + if (rename(".tmpconfig_tristate", name)) + return 1; + name = conf_get_autoconfig_name(); + /* + * This must be the last step, kbuild has a dependency on auto.conf + * and this marks the successful completion of the previous steps. + */ + if (rename(".tmpconfig", name)) + return 1; + + return 0; +} + +static int sym_change_count; +static void (*conf_changed_callback)(void); + +void sym_set_change_count(int count) +{ + int _sym_change_count = sym_change_count; + sym_change_count = count; + if (conf_changed_callback && + (bool)_sym_change_count != (bool)count) + conf_changed_callback(); +} + +void sym_add_change_count(int count) +{ + sym_set_change_count(count + sym_change_count); +} + +bool conf_get_changed(void) +{ + return sym_change_count; +} + +void conf_set_changed_callback(void (*fn)(void)) +{ + conf_changed_callback = fn; +} + +static void randomize_choice_values(struct symbol *csym) +{ + struct property *prop; + struct symbol *sym; + struct expr *e; + int cnt, def; + + /* + * If choice is mod then we may have more items selected + * and if no then no-one. + * In both cases stop. + */ + if (csym->curr.tri != yes) + return; + + prop = sym_get_choice_prop(csym); + + /* count entries in choice block */ + cnt = 0; + expr_list_for_each_sym(prop->expr, e, sym) + cnt++; + + /* + * find a random value and set it to yes, + * set the rest to no so we have only one set + */ + def = (rand() % cnt); + + cnt = 0; + expr_list_for_each_sym(prop->expr, e, sym) { + if (def == cnt++) { + sym->def[S_DEF_USER].tri = yes; + csym->def[S_DEF_USER].val = sym; + } + else { + sym->def[S_DEF_USER].tri = no; + } + } + csym->flags |= SYMBOL_DEF_USER; + /* clear VALID to get value calculated */ + csym->flags &= ~(SYMBOL_VALID); +} + +static void set_all_choice_values(struct symbol *csym) +{ + struct property *prop; + struct symbol *sym; + struct expr *e; + + prop = sym_get_choice_prop(csym); + + /* + * Set all non-assinged choice values to no + */ + expr_list_for_each_sym(prop->expr, e, sym) { + if (!sym_has_value(sym)) + sym->def[S_DEF_USER].tri = no; + } + csym->flags |= SYMBOL_DEF_USER; + /* clear VALID to get value calculated */ + csym->flags &= ~(SYMBOL_VALID); +} + +void conf_set_all_new_symbols(enum conf_def_mode mode) +{ + struct symbol *sym, *csym; + int i, cnt; + + for_all_symbols(i, sym) { + if (sym_has_value(sym)) + continue; + switch (sym_get_type(sym)) { + case S_BOOLEAN: + case S_TRISTATE: + switch (mode) { + case def_yes: + sym->def[S_DEF_USER].tri = yes; + break; + case def_mod: + sym->def[S_DEF_USER].tri = mod; + break; + case def_no: + sym->def[S_DEF_USER].tri = no; + break; + case def_random: + cnt = sym_get_type(sym) == S_TRISTATE ? 3 : 2; + sym->def[S_DEF_USER].tri = (tristate)(rand() % cnt); + break; + default: + continue; + } + if (!(sym_is_choice(sym) && mode == def_random)) + sym->flags |= SYMBOL_DEF_USER; + break; + default: + break; + } + + } + + sym_clear_all_valid(); + + /* + * We have different type of choice blocks. + * If curr.tri equals to mod then we can select several + * choice symbols in one block. + * In this case we do nothing. + * If curr.tri equals yes then only one symbol can be + * selected in a choice block and we set it to yes, + * and the rest to no. + */ + for_all_symbols(i, csym) { + if (sym_has_value(csym) || !sym_is_choice(csym)) + continue; + + sym_calc_value(csym); + if (mode == def_random) + randomize_choice_values(csym); + else + set_all_choice_values(csym); + } +} diff --git a/bios/seabios/tools/kconfig/expr.c b/bios/seabios/tools/kconfig/expr.c new file mode 100644 index 0000000..0010034 --- /dev/null +++ b/bios/seabios/tools/kconfig/expr.c @@ -0,0 +1,1173 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +#define DEBUG_EXPR 0 + +struct expr *expr_alloc_symbol(struct symbol *sym) +{ + struct expr *e = malloc(sizeof(*e)); + memset(e, 0, sizeof(*e)); + e->type = E_SYMBOL; + e->left.sym = sym; + return e; +} + +struct expr *expr_alloc_one(enum expr_type type, struct expr *ce) +{ + struct expr *e = malloc(sizeof(*e)); + memset(e, 0, sizeof(*e)); + e->type = type; + e->left.expr = ce; + return e; +} + +struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2) +{ + struct expr *e = malloc(sizeof(*e)); + memset(e, 0, sizeof(*e)); + e->type = type; + e->left.expr = e1; + e->right.expr = e2; + return e; +} + +struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2) +{ + struct expr *e = malloc(sizeof(*e)); + memset(e, 0, sizeof(*e)); + e->type = type; + e->left.sym = s1; + e->right.sym = s2; + return e; +} + +struct expr *expr_alloc_and(struct expr *e1, struct expr *e2) +{ + if (!e1) + return e2; + return e2 ? expr_alloc_two(E_AND, e1, e2) : e1; +} + +struct expr *expr_alloc_or(struct expr *e1, struct expr *e2) +{ + if (!e1) + return e2; + return e2 ? expr_alloc_two(E_OR, e1, e2) : e1; +} + +struct expr *expr_copy(const struct expr *org) +{ + struct expr *e; + + if (!org) + return NULL; + + e = malloc(sizeof(*org)); + memcpy(e, org, sizeof(*org)); + switch (org->type) { + case E_SYMBOL: + e->left = org->left; + break; + case E_NOT: + e->left.expr = expr_copy(org->left.expr); + break; + case E_EQUAL: + case E_UNEQUAL: + e->left.sym = org->left.sym; + e->right.sym = org->right.sym; + break; + case E_AND: + case E_OR: + case E_LIST: + e->left.expr = expr_copy(org->left.expr); + e->right.expr = expr_copy(org->right.expr); + break; + default: + printf("can't copy type %d\n", e->type); + free(e); + e = NULL; + break; + } + + return e; +} + +void expr_free(struct expr *e) +{ + if (!e) + return; + + switch (e->type) { + case E_SYMBOL: + break; + case E_NOT: + expr_free(e->left.expr); + return; + case E_EQUAL: + case E_UNEQUAL: + break; + case E_OR: + case E_AND: + expr_free(e->left.expr); + expr_free(e->right.expr); + break; + default: + printf("how to free type %d?\n", e->type); + break; + } + free(e); +} + +static int trans_count; + +#define e1 (*ep1) +#define e2 (*ep2) + +static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2) +{ + if (e1->type == type) { + __expr_eliminate_eq(type, &e1->left.expr, &e2); + __expr_eliminate_eq(type, &e1->right.expr, &e2); + return; + } + if (e2->type == type) { + __expr_eliminate_eq(type, &e1, &e2->left.expr); + __expr_eliminate_eq(type, &e1, &e2->right.expr); + return; + } + if (e1->type == E_SYMBOL && e2->type == E_SYMBOL && + e1->left.sym == e2->left.sym && + (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no)) + return; + if (!expr_eq(e1, e2)) + return; + trans_count++; + expr_free(e1); expr_free(e2); + switch (type) { + case E_OR: + e1 = expr_alloc_symbol(&symbol_no); + e2 = expr_alloc_symbol(&symbol_no); + break; + case E_AND: + e1 = expr_alloc_symbol(&symbol_yes); + e2 = expr_alloc_symbol(&symbol_yes); + break; + default: + ; + } +} + +void expr_eliminate_eq(struct expr **ep1, struct expr **ep2) +{ + if (!e1 || !e2) + return; + switch (e1->type) { + case E_OR: + case E_AND: + __expr_eliminate_eq(e1->type, ep1, ep2); + default: + ; + } + if (e1->type != e2->type) switch (e2->type) { + case E_OR: + case E_AND: + __expr_eliminate_eq(e2->type, ep1, ep2); + default: + ; + } + e1 = expr_eliminate_yn(e1); + e2 = expr_eliminate_yn(e2); +} + +#undef e1 +#undef e2 + +int expr_eq(struct expr *e1, struct expr *e2) +{ + int res, old_count; + + if (e1->type != e2->type) + return 0; + switch (e1->type) { + case E_EQUAL: + case E_UNEQUAL: + return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym; + case E_SYMBOL: + return e1->left.sym == e2->left.sym; + case E_NOT: + return expr_eq(e1->left.expr, e2->left.expr); + case E_AND: + case E_OR: + e1 = expr_copy(e1); + e2 = expr_copy(e2); + old_count = trans_count; + expr_eliminate_eq(&e1, &e2); + res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL && + e1->left.sym == e2->left.sym); + expr_free(e1); + expr_free(e2); + trans_count = old_count; + return res; + case E_LIST: + case E_RANGE: + case E_NONE: + /* panic */; + } + + if (DEBUG_EXPR) { + expr_fprint(e1, stdout); + printf(" = "); + expr_fprint(e2, stdout); + printf(" ?\n"); + } + + return 0; +} + +struct expr *expr_eliminate_yn(struct expr *e) +{ + struct expr *tmp; + + if (e) switch (e->type) { + case E_AND: + e->left.expr = expr_eliminate_yn(e->left.expr); + e->right.expr = expr_eliminate_yn(e->right.expr); + if (e->left.expr->type == E_SYMBOL) { + if (e->left.expr->left.sym == &symbol_no) { + expr_free(e->left.expr); + expr_free(e->right.expr); + e->type = E_SYMBOL; + e->left.sym = &symbol_no; + e->right.expr = NULL; + return e; + } else if (e->left.expr->left.sym == &symbol_yes) { + free(e->left.expr); + tmp = e->right.expr; + *e = *(e->right.expr); + free(tmp); + return e; + } + } + if (e->right.expr->type == E_SYMBOL) { + if (e->right.expr->left.sym == &symbol_no) { + expr_free(e->left.expr); + expr_free(e->right.expr); + e->type = E_SYMBOL; + e->left.sym = &symbol_no; + e->right.expr = NULL; + return e; + } else if (e->right.expr->left.sym == &symbol_yes) { + free(e->right.expr); + tmp = e->left.expr; + *e = *(e->left.expr); + free(tmp); + return e; + } + } + break; + case E_OR: + e->left.expr = expr_eliminate_yn(e->left.expr); + e->right.expr = expr_eliminate_yn(e->right.expr); + if (e->left.expr->type == E_SYMBOL) { + if (e->left.expr->left.sym == &symbol_no) { + free(e->left.expr); + tmp = e->right.expr; + *e = *(e->right.expr); + free(tmp); + return e; + } else if (e->left.expr->left.sym == &symbol_yes) { + expr_free(e->left.expr); + expr_free(e->right.expr); + e->type = E_SYMBOL; + e->left.sym = &symbol_yes; + e->right.expr = NULL; + return e; + } + } + if (e->right.expr->type == E_SYMBOL) { + if (e->right.expr->left.sym == &symbol_no) { + free(e->right.expr); + tmp = e->left.expr; + *e = *(e->left.expr); + free(tmp); + return e; + } else if (e->right.expr->left.sym == &symbol_yes) { + expr_free(e->left.expr); + expr_free(e->right.expr); + e->type = E_SYMBOL; + e->left.sym = &symbol_yes; + e->right.expr = NULL; + return e; + } + } + break; + default: + ; + } + return e; +} + +/* + * bool FOO!=n => FOO + */ +struct expr *expr_trans_bool(struct expr *e) +{ + if (!e) + return NULL; + switch (e->type) { + case E_AND: + case E_OR: + case E_NOT: + e->left.expr = expr_trans_bool(e->left.expr); + e->right.expr = expr_trans_bool(e->right.expr); + break; + case E_UNEQUAL: + // FOO!=n -> FOO + if (e->left.sym->type == S_TRISTATE) { + if (e->right.sym == &symbol_no) { + e->type = E_SYMBOL; + e->right.sym = NULL; + } + } + break; + default: + ; + } + return e; +} + +/* + * e1 || e2 -> ? + */ +static struct expr *expr_join_or(struct expr *e1, struct expr *e2) +{ + struct expr *tmp; + struct symbol *sym1, *sym2; + + if (expr_eq(e1, e2)) + return expr_copy(e1); + if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) + return NULL; + if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) + return NULL; + if (e1->type == E_NOT) { + tmp = e1->left.expr; + if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL) + return NULL; + sym1 = tmp->left.sym; + } else + sym1 = e1->left.sym; + if (e2->type == E_NOT) { + if (e2->left.expr->type != E_SYMBOL) + return NULL; + sym2 = e2->left.expr->left.sym; + } else + sym2 = e2->left.sym; + if (sym1 != sym2) + return NULL; + if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE) + return NULL; + if (sym1->type == S_TRISTATE) { + if (e1->type == E_EQUAL && e2->type == E_EQUAL && + ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) || + (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) { + // (a='y') || (a='m') -> (a!='n') + return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no); + } + if (e1->type == E_EQUAL && e2->type == E_EQUAL && + ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) || + (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) { + // (a='y') || (a='n') -> (a!='m') + return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod); + } + if (e1->type == E_EQUAL && e2->type == E_EQUAL && + ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) || + (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) { + // (a='m') || (a='n') -> (a!='y') + return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes); + } + } + if (sym1->type == S_BOOLEAN && sym1 == sym2) { + if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) || + (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL)) + return expr_alloc_symbol(&symbol_yes); + } + + if (DEBUG_EXPR) { + printf("optimize ("); + expr_fprint(e1, stdout); + printf(") || ("); + expr_fprint(e2, stdout); + printf(")?\n"); + } + return NULL; +} + +static struct expr *expr_join_and(struct expr *e1, struct expr *e2) +{ + struct expr *tmp; + struct symbol *sym1, *sym2; + + if (expr_eq(e1, e2)) + return expr_copy(e1); + if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) + return NULL; + if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) + return NULL; + if (e1->type == E_NOT) { + tmp = e1->left.expr; + if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL) + return NULL; + sym1 = tmp->left.sym; + } else + sym1 = e1->left.sym; + if (e2->type == E_NOT) { + if (e2->left.expr->type != E_SYMBOL) + return NULL; + sym2 = e2->left.expr->left.sym; + } else + sym2 = e2->left.sym; + if (sym1 != sym2) + return NULL; + if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE) + return NULL; + + if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) || + (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes)) + // (a) && (a='y') -> (a='y') + return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); + + if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) || + (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no)) + // (a) && (a!='n') -> (a) + return expr_alloc_symbol(sym1); + + if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) || + (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod)) + // (a) && (a!='m') -> (a='y') + return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); + + if (sym1->type == S_TRISTATE) { + if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) { + // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' + sym2 = e1->right.sym; + if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST)) + return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2) + : expr_alloc_symbol(&symbol_no); + } + if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) { + // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' + sym2 = e2->right.sym; + if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST)) + return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2) + : expr_alloc_symbol(&symbol_no); + } + if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && + ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) || + (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) + // (a!='y') && (a!='n') -> (a='m') + return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod); + + if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && + ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) || + (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) + // (a!='y') && (a!='m') -> (a='n') + return expr_alloc_comp(E_EQUAL, sym1, &symbol_no); + + if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && + ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) || + (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) + // (a!='m') && (a!='n') -> (a='m') + return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); + + if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) || + (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) || + (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) || + (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes)) + return NULL; + } + + if (DEBUG_EXPR) { + printf("optimize ("); + expr_fprint(e1, stdout); + printf(") && ("); + expr_fprint(e2, stdout); + printf(")?\n"); + } + return NULL; +} + +static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2) +{ +#define e1 (*ep1) +#define e2 (*ep2) + struct expr *tmp; + + if (e1->type == type) { + expr_eliminate_dups1(type, &e1->left.expr, &e2); + expr_eliminate_dups1(type, &e1->right.expr, &e2); + return; + } + if (e2->type == type) { + expr_eliminate_dups1(type, &e1, &e2->left.expr); + expr_eliminate_dups1(type, &e1, &e2->right.expr); + return; + } + if (e1 == e2) + return; + + switch (e1->type) { + case E_OR: case E_AND: + expr_eliminate_dups1(e1->type, &e1, &e1); + default: + ; + } + + switch (type) { + case E_OR: + tmp = expr_join_or(e1, e2); + if (tmp) { + expr_free(e1); expr_free(e2); + e1 = expr_alloc_symbol(&symbol_no); + e2 = tmp; + trans_count++; + } + break; + case E_AND: + tmp = expr_join_and(e1, e2); + if (tmp) { + expr_free(e1); expr_free(e2); + e1 = expr_alloc_symbol(&symbol_yes); + e2 = tmp; + trans_count++; + } + break; + default: + ; + } +#undef e1 +#undef e2 +} + +static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct expr **ep2) +{ +#define e1 (*ep1) +#define e2 (*ep2) + struct expr *tmp, *tmp1, *tmp2; + + if (e1->type == type) { + expr_eliminate_dups2(type, &e1->left.expr, &e2); + expr_eliminate_dups2(type, &e1->right.expr, &e2); + return; + } + if (e2->type == type) { + expr_eliminate_dups2(type, &e1, &e2->left.expr); + expr_eliminate_dups2(type, &e1, &e2->right.expr); + } + if (e1 == e2) + return; + + switch (e1->type) { + case E_OR: + expr_eliminate_dups2(e1->type, &e1, &e1); + // (FOO || BAR) && (!FOO && !BAR) -> n + tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1))); + tmp2 = expr_copy(e2); + tmp = expr_extract_eq_and(&tmp1, &tmp2); + if (expr_is_yes(tmp1)) { + expr_free(e1); + e1 = expr_alloc_symbol(&symbol_no); + trans_count++; + } + expr_free(tmp2); + expr_free(tmp1); + expr_free(tmp); + break; + case E_AND: + expr_eliminate_dups2(e1->type, &e1, &e1); + // (FOO && BAR) || (!FOO || !BAR) -> y + tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1))); + tmp2 = expr_copy(e2); + tmp = expr_extract_eq_or(&tmp1, &tmp2); + if (expr_is_no(tmp1)) { + expr_free(e1); + e1 = expr_alloc_symbol(&symbol_yes); + trans_count++; + } + expr_free(tmp2); + expr_free(tmp1); + expr_free(tmp); + break; + default: + ; + } +#undef e1 +#undef e2 +} + +struct expr *expr_eliminate_dups(struct expr *e) +{ + int oldcount; + if (!e) + return e; + + oldcount = trans_count; + while (1) { + trans_count = 0; + switch (e->type) { + case E_OR: case E_AND: + expr_eliminate_dups1(e->type, &e, &e); + expr_eliminate_dups2(e->type, &e, &e); + default: + ; + } + if (!trans_count) + break; + e = expr_eliminate_yn(e); + } + trans_count = oldcount; + return e; +} + +struct expr *expr_transform(struct expr *e) +{ + struct expr *tmp; + + if (!e) + return NULL; + switch (e->type) { + case E_EQUAL: + case E_UNEQUAL: + case E_SYMBOL: + case E_LIST: + break; + default: + e->left.expr = expr_transform(e->left.expr); + e->right.expr = expr_transform(e->right.expr); + } + + switch (e->type) { + case E_EQUAL: + if (e->left.sym->type != S_BOOLEAN) + break; + if (e->right.sym == &symbol_no) { + e->type = E_NOT; + e->left.expr = expr_alloc_symbol(e->left.sym); + e->right.sym = NULL; + break; + } + if (e->right.sym == &symbol_mod) { + printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name); + e->type = E_SYMBOL; + e->left.sym = &symbol_no; + e->right.sym = NULL; + break; + } + if (e->right.sym == &symbol_yes) { + e->type = E_SYMBOL; + e->right.sym = NULL; + break; + } + break; + case E_UNEQUAL: + if (e->left.sym->type != S_BOOLEAN) + break; + if (e->right.sym == &symbol_no) { + e->type = E_SYMBOL; + e->right.sym = NULL; + break; + } + if (e->right.sym == &symbol_mod) { + printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name); + e->type = E_SYMBOL; + e->left.sym = &symbol_yes; + e->right.sym = NULL; + break; + } + if (e->right.sym == &symbol_yes) { + e->type = E_NOT; + e->left.expr = expr_alloc_symbol(e->left.sym); + e->right.sym = NULL; + break; + } + break; + case E_NOT: + switch (e->left.expr->type) { + case E_NOT: + // !!a -> a + tmp = e->left.expr->left.expr; + free(e->left.expr); + free(e); + e = tmp; + e = expr_transform(e); + break; + case E_EQUAL: + case E_UNEQUAL: + // !a='x' -> a!='x' + tmp = e->left.expr; + free(e); + e = tmp; + e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL; + break; + case E_OR: + // !(a || b) -> !a && !b + tmp = e->left.expr; + e->type = E_AND; + e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); + tmp->type = E_NOT; + tmp->right.expr = NULL; + e = expr_transform(e); + break; + case E_AND: + // !(a && b) -> !a || !b + tmp = e->left.expr; + e->type = E_OR; + e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); + tmp->type = E_NOT; + tmp->right.expr = NULL; + e = expr_transform(e); + break; + case E_SYMBOL: + if (e->left.expr->left.sym == &symbol_yes) { + // !'y' -> 'n' + tmp = e->left.expr; + free(e); + e = tmp; + e->type = E_SYMBOL; + e->left.sym = &symbol_no; + break; + } + if (e->left.expr->left.sym == &symbol_mod) { + // !'m' -> 'm' + tmp = e->left.expr; + free(e); + e = tmp; + e->type = E_SYMBOL; + e->left.sym = &symbol_mod; + break; + } + if (e->left.expr->left.sym == &symbol_no) { + // !'n' -> 'y' + tmp = e->left.expr; + free(e); + e = tmp; + e->type = E_SYMBOL; + e->left.sym = &symbol_yes; + break; + } + break; + default: + ; + } + break; + default: + ; + } + return e; +} + +int expr_contains_symbol(struct expr *dep, struct symbol *sym) +{ + if (!dep) + return 0; + + switch (dep->type) { + case E_AND: + case E_OR: + return expr_contains_symbol(dep->left.expr, sym) || + expr_contains_symbol(dep->right.expr, sym); + case E_SYMBOL: + return dep->left.sym == sym; + case E_EQUAL: + case E_UNEQUAL: + return dep->left.sym == sym || + dep->right.sym == sym; + case E_NOT: + return expr_contains_symbol(dep->left.expr, sym); + default: + ; + } + return 0; +} + +bool expr_depends_symbol(struct expr *dep, struct symbol *sym) +{ + if (!dep) + return false; + + switch (dep->type) { + case E_AND: + return expr_depends_symbol(dep->left.expr, sym) || + expr_depends_symbol(dep->right.expr, sym); + case E_SYMBOL: + return dep->left.sym == sym; + case E_EQUAL: + if (dep->left.sym == sym) { + if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod) + return true; + } + break; + case E_UNEQUAL: + if (dep->left.sym == sym) { + if (dep->right.sym == &symbol_no) + return true; + } + break; + default: + ; + } + return false; +} + +struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2) +{ + struct expr *tmp = NULL; + expr_extract_eq(E_AND, &tmp, ep1, ep2); + if (tmp) { + *ep1 = expr_eliminate_yn(*ep1); + *ep2 = expr_eliminate_yn(*ep2); + } + return tmp; +} + +struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2) +{ + struct expr *tmp = NULL; + expr_extract_eq(E_OR, &tmp, ep1, ep2); + if (tmp) { + *ep1 = expr_eliminate_yn(*ep1); + *ep2 = expr_eliminate_yn(*ep2); + } + return tmp; +} + +void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2) +{ +#define e1 (*ep1) +#define e2 (*ep2) + if (e1->type == type) { + expr_extract_eq(type, ep, &e1->left.expr, &e2); + expr_extract_eq(type, ep, &e1->right.expr, &e2); + return; + } + if (e2->type == type) { + expr_extract_eq(type, ep, ep1, &e2->left.expr); + expr_extract_eq(type, ep, ep1, &e2->right.expr); + return; + } + if (expr_eq(e1, e2)) { + *ep = *ep ? expr_alloc_two(type, *ep, e1) : e1; + expr_free(e2); + if (type == E_AND) { + e1 = expr_alloc_symbol(&symbol_yes); + e2 = expr_alloc_symbol(&symbol_yes); + } else if (type == E_OR) { + e1 = expr_alloc_symbol(&symbol_no); + e2 = expr_alloc_symbol(&symbol_no); + } + } +#undef e1 +#undef e2 +} + +struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym) +{ + struct expr *e1, *e2; + + if (!e) { + e = expr_alloc_symbol(sym); + if (type == E_UNEQUAL) + e = expr_alloc_one(E_NOT, e); + return e; + } + switch (e->type) { + case E_AND: + e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym); + e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym); + if (sym == &symbol_yes) + e = expr_alloc_two(E_AND, e1, e2); + if (sym == &symbol_no) + e = expr_alloc_two(E_OR, e1, e2); + if (type == E_UNEQUAL) + e = expr_alloc_one(E_NOT, e); + return e; + case E_OR: + e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym); + e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym); + if (sym == &symbol_yes) + e = expr_alloc_two(E_OR, e1, e2); + if (sym == &symbol_no) + e = expr_alloc_two(E_AND, e1, e2); + if (type == E_UNEQUAL) + e = expr_alloc_one(E_NOT, e); + return e; + case E_NOT: + return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym); + case E_UNEQUAL: + case E_EQUAL: + if (type == E_EQUAL) { + if (sym == &symbol_yes) + return expr_copy(e); + if (sym == &symbol_mod) + return expr_alloc_symbol(&symbol_no); + if (sym == &symbol_no) + return expr_alloc_one(E_NOT, expr_copy(e)); + } else { + if (sym == &symbol_yes) + return expr_alloc_one(E_NOT, expr_copy(e)); + if (sym == &symbol_mod) + return expr_alloc_symbol(&symbol_yes); + if (sym == &symbol_no) + return expr_copy(e); + } + break; + case E_SYMBOL: + return expr_alloc_comp(type, e->left.sym, sym); + case E_LIST: + case E_RANGE: + case E_NONE: + /* panic */; + } + return NULL; +} + +tristate expr_calc_value(struct expr *e) +{ + tristate val1, val2; + const char *str1, *str2; + + if (!e) + return yes; + + switch (e->type) { + case E_SYMBOL: + sym_calc_value(e->left.sym); + return e->left.sym->curr.tri; + case E_AND: + val1 = expr_calc_value(e->left.expr); + val2 = expr_calc_value(e->right.expr); + return EXPR_AND(val1, val2); + case E_OR: + val1 = expr_calc_value(e->left.expr); + val2 = expr_calc_value(e->right.expr); + return EXPR_OR(val1, val2); + case E_NOT: + val1 = expr_calc_value(e->left.expr); + return EXPR_NOT(val1); + case E_EQUAL: + sym_calc_value(e->left.sym); + sym_calc_value(e->right.sym); + str1 = sym_get_string_value(e->left.sym); + str2 = sym_get_string_value(e->right.sym); + return !strcmp(str1, str2) ? yes : no; + case E_UNEQUAL: + sym_calc_value(e->left.sym); + sym_calc_value(e->right.sym); + str1 = sym_get_string_value(e->left.sym); + str2 = sym_get_string_value(e->right.sym); + return !strcmp(str1, str2) ? no : yes; + default: + printf("expr_calc_value: %d?\n", e->type); + return no; + } +} + +int expr_compare_type(enum expr_type t1, enum expr_type t2) +{ +#if 0 + return 1; +#else + if (t1 == t2) + return 0; + switch (t1) { + case E_EQUAL: + case E_UNEQUAL: + if (t2 == E_NOT) + return 1; + case E_NOT: + if (t2 == E_AND) + return 1; + case E_AND: + if (t2 == E_OR) + return 1; + case E_OR: + if (t2 == E_LIST) + return 1; + case E_LIST: + if (t2 == 0) + return 1; + default: + return -1; + } + printf("[%dgt%d?]", t1, t2); + return 0; +#endif +} + +static inline struct expr * +expr_get_leftmost_symbol(const struct expr *e) +{ + + if (e == NULL) + return NULL; + + while (e->type != E_SYMBOL) + e = e->left.expr; + + return expr_copy(e); +} + +/* + * Given expression `e1' and `e2', returns the leaf of the longest + * sub-expression of `e1' not containing 'e2. + */ +struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2) +{ + struct expr *ret; + + switch (e1->type) { + case E_OR: + return expr_alloc_and( + expr_simplify_unmet_dep(e1->left.expr, e2), + expr_simplify_unmet_dep(e1->right.expr, e2)); + case E_AND: { + struct expr *e; + e = expr_alloc_and(expr_copy(e1), expr_copy(e2)); + e = expr_eliminate_dups(e); + ret = (!expr_eq(e, e1)) ? e1 : NULL; + expr_free(e); + break; + } + default: + ret = e1; + break; + } + + return expr_get_leftmost_symbol(ret); +} + +void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken) +{ + if (!e) { + fn(data, NULL, "y"); + return; + } + + if (expr_compare_type(prevtoken, e->type) > 0) + fn(data, NULL, "("); + switch (e->type) { + case E_SYMBOL: + if (e->left.sym->name) + fn(data, e->left.sym, e->left.sym->name); + else + fn(data, NULL, ""); + break; + case E_NOT: + fn(data, NULL, "!"); + expr_print(e->left.expr, fn, data, E_NOT); + break; + case E_EQUAL: + if (e->left.sym->name) + fn(data, e->left.sym, e->left.sym->name); + else + fn(data, NULL, ""); + fn(data, NULL, "="); + fn(data, e->right.sym, e->right.sym->name); + break; + case E_UNEQUAL: + if (e->left.sym->name) + fn(data, e->left.sym, e->left.sym->name); + else + fn(data, NULL, ""); + fn(data, NULL, "!="); + fn(data, e->right.sym, e->right.sym->name); + break; + case E_OR: + expr_print(e->left.expr, fn, data, E_OR); + fn(data, NULL, " || "); + expr_print(e->right.expr, fn, data, E_OR); + break; + case E_AND: + expr_print(e->left.expr, fn, data, E_AND); + fn(data, NULL, " && "); + expr_print(e->right.expr, fn, data, E_AND); + break; + case E_LIST: + fn(data, e->right.sym, e->right.sym->name); + if (e->left.expr) { + fn(data, NULL, " ^ "); + expr_print(e->left.expr, fn, data, E_LIST); + } + break; + case E_RANGE: + fn(data, NULL, "["); + fn(data, e->left.sym, e->left.sym->name); + fn(data, NULL, " "); + fn(data, e->right.sym, e->right.sym->name); + fn(data, NULL, "]"); + break; + default: + { + char buf[32]; + sprintf(buf, "", e->type); + fn(data, NULL, buf); + break; + } + } + if (expr_compare_type(prevtoken, e->type) > 0) + fn(data, NULL, ")"); +} + +static void expr_print_file_helper(void *data, struct symbol *sym, const char *str) +{ + xfwrite(str, strlen(str), 1, data); +} + +void expr_fprint(struct expr *e, FILE *out) +{ + expr_print(e, expr_print_file_helper, out, E_NONE); +} + +static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str) +{ + struct gstr *gs = (struct gstr*)data; + const char *sym_str = NULL; + + if (sym) + sym_str = sym_get_string_value(sym); + + if (gs->max_width) { + unsigned extra_length = strlen(str); + const char *last_cr = strrchr(gs->s, '\n'); + unsigned last_line_length; + + if (sym_str) + extra_length += 4 + strlen(sym_str); + + if (!last_cr) + last_cr = gs->s; + + last_line_length = strlen(gs->s) - (last_cr - gs->s); + + if ((last_line_length + extra_length) > gs->max_width) + str_append(gs, "\\\n"); + } + + str_append(gs, str); + if (sym && sym->type != S_UNKNOWN) + str_printf(gs, " [=%s]", sym_str); +} + +void expr_gstr_print(struct expr *e, struct gstr *gs) +{ + expr_print(e, expr_print_gstr_helper, gs, E_NONE); +} diff --git a/bios/seabios/tools/kconfig/expr.h b/bios/seabios/tools/kconfig/expr.h new file mode 100644 index 0000000..3d238db --- /dev/null +++ b/bios/seabios/tools/kconfig/expr.h @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#ifndef EXPR_H +#define EXPR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifndef __cplusplus +#include +#endif + +struct file { + struct file *next; + struct file *parent; + const char *name; + int lineno; + int flags; +}; + +#define FILE_BUSY 0x0001 +#define FILE_SCANNED 0x0002 + +typedef enum tristate { + no, mod, yes +} tristate; + +enum expr_type { + E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_LIST, E_SYMBOL, E_RANGE +}; + +union expr_data { + struct expr *expr; + struct symbol *sym; +}; + +struct expr { + enum expr_type type; + union expr_data left, right; +}; + +#define EXPR_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2)) +#define EXPR_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2)) +#define EXPR_NOT(dep) (2-(dep)) + +#define expr_list_for_each_sym(l, e, s) \ + for (e = (l); e && (s = e->right.sym); e = e->left.expr) + +struct expr_value { + struct expr *expr; + tristate tri; +}; + +struct symbol_value { + void *val; + tristate tri; +}; + +enum symbol_type { + S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER +}; + +/* enum values are used as index to symbol.def[] */ +enum { + S_DEF_USER, /* main user value */ + S_DEF_AUTO, /* values read from auto.conf */ + S_DEF_DEF3, /* Reserved for UI usage */ + S_DEF_DEF4, /* Reserved for UI usage */ + S_DEF_COUNT +}; + +struct symbol { + struct symbol *next; + char *name; + enum symbol_type type; + struct symbol_value curr; + struct symbol_value def[S_DEF_COUNT]; + tristate visible; + int flags; + struct property *prop; + struct expr_value dir_dep; + struct expr_value rev_dep; +}; + +#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) + +#define SYMBOL_CONST 0x0001 /* symbol is const */ +#define SYMBOL_CHECK 0x0008 /* used during dependency checking */ +#define SYMBOL_CHOICE 0x0010 /* start of a choice block (null name) */ +#define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */ +#define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */ +#define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */ +#define SYMBOL_WRITE 0x0200 /* ? */ +#define SYMBOL_CHANGED 0x0400 /* ? */ +#define SYMBOL_AUTO 0x1000 /* value from environment variable */ +#define SYMBOL_CHECKED 0x2000 /* used during dependency checking */ +#define SYMBOL_WARNED 0x8000 /* warning has been issued */ + +/* Set when symbol.def[] is used */ +#define SYMBOL_DEF 0x10000 /* First bit of SYMBOL_DEF */ +#define SYMBOL_DEF_USER 0x10000 /* symbol.def[S_DEF_USER] is valid */ +#define SYMBOL_DEF_AUTO 0x20000 /* symbol.def[S_DEF_AUTO] is valid */ +#define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */ +#define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */ + +#define SYMBOL_MAXLENGTH 256 +#define SYMBOL_HASHSIZE 9973 + +/* A property represent the config options that can be associated + * with a config "symbol". + * Sample: + * config FOO + * default y + * prompt "foo prompt" + * select BAR + * config BAZ + * int "BAZ Value" + * range 1..255 + */ +enum prop_type { + P_UNKNOWN, + P_PROMPT, /* prompt "foo prompt" or "BAZ Value" */ + P_COMMENT, /* text associated with a comment */ + P_MENU, /* prompt associated with a menuconfig option */ + P_DEFAULT, /* default y */ + P_CHOICE, /* choice value */ + P_SELECT, /* select BAR */ + P_RANGE, /* range 7..100 (for a symbol) */ + P_ENV, /* value from environment variable */ + P_SYMBOL, /* where a symbol is defined */ +}; + +struct property { + struct property *next; /* next property - null if last */ + struct symbol *sym; /* the symbol for which the property is associated */ + enum prop_type type; /* type of property */ + const char *text; /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */ + struct expr_value visible; + struct expr *expr; /* the optional conditional part of the property */ + struct menu *menu; /* the menu the property are associated with + * valid for: P_SELECT, P_RANGE, P_CHOICE, + * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */ + struct file *file; /* what file was this property defined */ + int lineno; /* what lineno was this property defined */ +}; + +#define for_all_properties(sym, st, tok) \ + for (st = sym->prop; st; st = st->next) \ + if (st->type == (tok)) +#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT) +#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE) +#define for_all_prompts(sym, st) \ + for (st = sym->prop; st; st = st->next) \ + if (st->text) + +struct menu { + struct menu *next; + struct menu *parent; + struct menu *list; + struct symbol *sym; + struct property *prompt; + struct expr *visibility; + struct expr *dep; + unsigned int flags; + char *help; + struct file *file; + int lineno; + void *data; +}; + +#define MENU_CHANGED 0x0001 +#define MENU_ROOT 0x0002 + +#ifndef SWIG + +extern struct file *file_list; +extern struct file *current_file; +struct file *lookup_file(const char *name); + +extern struct symbol symbol_yes, symbol_no, symbol_mod; +extern struct symbol *modules_sym; +extern struct symbol *sym_defconfig_list; +extern int cdebug; +struct expr *expr_alloc_symbol(struct symbol *sym); +struct expr *expr_alloc_one(enum expr_type type, struct expr *ce); +struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2); +struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2); +struct expr *expr_alloc_and(struct expr *e1, struct expr *e2); +struct expr *expr_alloc_or(struct expr *e1, struct expr *e2); +struct expr *expr_copy(const struct expr *org); +void expr_free(struct expr *e); +int expr_eq(struct expr *e1, struct expr *e2); +void expr_eliminate_eq(struct expr **ep1, struct expr **ep2); +tristate expr_calc_value(struct expr *e); +struct expr *expr_eliminate_yn(struct expr *e); +struct expr *expr_trans_bool(struct expr *e); +struct expr *expr_eliminate_dups(struct expr *e); +struct expr *expr_transform(struct expr *e); +int expr_contains_symbol(struct expr *dep, struct symbol *sym); +bool expr_depends_symbol(struct expr *dep, struct symbol *sym); +struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2); +struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2); +void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2); +struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); +struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2); + +void expr_fprint(struct expr *e, FILE *out); +struct gstr; /* forward */ +void expr_gstr_print(struct expr *e, struct gstr *gs); + +static inline int expr_is_yes(struct expr *e) +{ + return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes); +} + +static inline int expr_is_no(struct expr *e) +{ + return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no); +} +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* EXPR_H */ diff --git a/bios/seabios/tools/kconfig/gconf.c b/bios/seabios/tools/kconfig/gconf.c new file mode 100644 index 0000000..b7f31f2 --- /dev/null +++ b/bios/seabios/tools/kconfig/gconf.c @@ -0,0 +1,1577 @@ +/* Hey EMACS -*- linux-c -*- */ +/* + * + * Copyright (C) 2002-2003 Romain Lievin + * Released under the terms of the GNU GPL v2.0. + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "lkc.h" +#include "images.c" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +//#define DEBUG + +enum { + SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW +}; + +enum { + OPT_NORMAL, OPT_ALL, OPT_PROMPT +}; + +static gint view_mode = FULL_VIEW; +static gboolean show_name = TRUE; +static gboolean show_range = TRUE; +static gboolean show_value = TRUE; +static gboolean resizeable = FALSE; +static int opt_mode = OPT_NORMAL; + +GtkWidget *main_wnd = NULL; +GtkWidget *tree1_w = NULL; // left frame +GtkWidget *tree2_w = NULL; // right frame +GtkWidget *text_w = NULL; +GtkWidget *hpaned = NULL; +GtkWidget *vpaned = NULL; +GtkWidget *back_btn = NULL; +GtkWidget *save_btn = NULL; +GtkWidget *save_menu_item = NULL; + +GtkTextTag *tag1, *tag2; +GdkColor color; + +GtkTreeStore *tree1, *tree2, *tree; +GtkTreeModel *model1, *model2; +static GtkTreeIter *parents[256]; +static gint indent; + +static struct menu *current; // current node for SINGLE view +static struct menu *browsed; // browsed node for SPLIT view + +enum { + COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE, + COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF, + COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD, + COL_NUMBER +}; + +static void display_list(void); +static void display_tree(struct menu *menu); +static void display_tree_part(void); +static void update_tree(struct menu *src, GtkTreeIter * dst); +static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row); +static gchar **fill_row(struct menu *menu); +static void conf_changed(void); + +/* Helping/Debugging Functions */ + +const char *dbg_sym_flags(int val) +{ + static char buf[256]; + + bzero(buf, 256); + + if (val & SYMBOL_CONST) + strcat(buf, "const/"); + if (val & SYMBOL_CHECK) + strcat(buf, "check/"); + if (val & SYMBOL_CHOICE) + strcat(buf, "choice/"); + if (val & SYMBOL_CHOICEVAL) + strcat(buf, "choiceval/"); + if (val & SYMBOL_VALID) + strcat(buf, "valid/"); + if (val & SYMBOL_OPTIONAL) + strcat(buf, "optional/"); + if (val & SYMBOL_WRITE) + strcat(buf, "write/"); + if (val & SYMBOL_CHANGED) + strcat(buf, "changed/"); + if (val & SYMBOL_AUTO) + strcat(buf, "auto/"); + + buf[strlen(buf) - 1] = '\0'; + + return buf; +} + +void replace_button_icon(GladeXML * xml, GdkDrawable * window, + GtkStyle * style, gchar * btn_name, gchar ** xpm) +{ + GdkPixmap *pixmap; + GdkBitmap *mask; + GtkToolButton *button; + GtkWidget *image; + + pixmap = gdk_pixmap_create_from_xpm_d(window, &mask, + &style->bg[GTK_STATE_NORMAL], + xpm); + + button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name)); + image = gtk_image_new_from_pixmap(pixmap, mask); + gtk_widget_show(image); + gtk_tool_button_set_icon_widget(button, image); +} + +/* Main Window Initialization */ +void init_main_window(const gchar * glade_file) +{ + GladeXML *xml; + GtkWidget *widget; + GtkTextBuffer *txtbuf; + GtkStyle *style; + + xml = glade_xml_new(glade_file, "window1", NULL); + if (!xml) + g_error(_("GUI loading failed !\n")); + glade_xml_signal_autoconnect(xml); + + main_wnd = glade_xml_get_widget(xml, "window1"); + hpaned = glade_xml_get_widget(xml, "hpaned1"); + vpaned = glade_xml_get_widget(xml, "vpaned1"); + tree1_w = glade_xml_get_widget(xml, "treeview1"); + tree2_w = glade_xml_get_widget(xml, "treeview2"); + text_w = glade_xml_get_widget(xml, "textview3"); + + back_btn = glade_xml_get_widget(xml, "button1"); + gtk_widget_set_sensitive(back_btn, FALSE); + + widget = glade_xml_get_widget(xml, "show_name1"); + gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, + show_name); + + widget = glade_xml_get_widget(xml, "show_range1"); + gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, + show_range); + + widget = glade_xml_get_widget(xml, "show_data1"); + gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, + show_value); + + save_btn = glade_xml_get_widget(xml, "button3"); + save_menu_item = glade_xml_get_widget(xml, "save1"); + conf_set_changed_callback(conf_changed); + + style = gtk_widget_get_style(main_wnd); + widget = glade_xml_get_widget(xml, "toolbar1"); + +#if 0 /* Use stock Gtk icons instead */ + replace_button_icon(xml, main_wnd->window, style, + "button1", (gchar **) xpm_back); + replace_button_icon(xml, main_wnd->window, style, + "button2", (gchar **) xpm_load); + replace_button_icon(xml, main_wnd->window, style, + "button3", (gchar **) xpm_save); +#endif + replace_button_icon(xml, main_wnd->window, style, + "button4", (gchar **) xpm_single_view); + replace_button_icon(xml, main_wnd->window, style, + "button5", (gchar **) xpm_split_view); + replace_button_icon(xml, main_wnd->window, style, + "button6", (gchar **) xpm_tree_view); + +#if 0 + switch (view_mode) { + case SINGLE_VIEW: + widget = glade_xml_get_widget(xml, "button4"); + g_signal_emit_by_name(widget, "clicked"); + break; + case SPLIT_VIEW: + widget = glade_xml_get_widget(xml, "button5"); + g_signal_emit_by_name(widget, "clicked"); + break; + case FULL_VIEW: + widget = glade_xml_get_widget(xml, "button6"); + g_signal_emit_by_name(widget, "clicked"); + break; + } +#endif + txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); + tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1", + "foreground", "red", + "weight", PANGO_WEIGHT_BOLD, + NULL); + tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2", + /*"style", PANGO_STYLE_OBLIQUE, */ + NULL); + + gtk_window_set_title(GTK_WINDOW(main_wnd), rootmenu.prompt->text); + + gtk_widget_show(main_wnd); +} + +void init_tree_model(void) +{ + gint i; + + tree = tree2 = gtk_tree_store_new(COL_NUMBER, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_POINTER, GDK_TYPE_COLOR, + G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN); + model2 = GTK_TREE_MODEL(tree2); + + for (parents[0] = NULL, i = 1; i < 256; i++) + parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter)); + + tree1 = gtk_tree_store_new(COL_NUMBER, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_POINTER, GDK_TYPE_COLOR, + G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN); + model1 = GTK_TREE_MODEL(tree1); +} + +void init_left_tree(void) +{ + GtkTreeView *view = GTK_TREE_VIEW(tree1_w); + GtkCellRenderer *renderer; + GtkTreeSelection *sel; + GtkTreeViewColumn *column; + + gtk_tree_view_set_model(view, model1); + gtk_tree_view_set_headers_visible(view, TRUE); + gtk_tree_view_set_rules_hint(view, FALSE); + + column = gtk_tree_view_column_new(); + gtk_tree_view_append_column(view, column); + gtk_tree_view_column_set_title(column, _("Options")); + + renderer = gtk_cell_renderer_toggle_new(); + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), + renderer, FALSE); + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), + renderer, + "active", COL_BTNACT, + "inconsistent", COL_BTNINC, + "visible", COL_BTNVIS, + "radio", COL_BTNRAD, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), + renderer, FALSE); + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), + renderer, + "text", COL_OPTION, + "foreground-gdk", + COL_COLOR, NULL); + + sel = gtk_tree_view_get_selection(view); + gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); + gtk_widget_realize(tree1_w); +} + +static void renderer_edited(GtkCellRendererText * cell, + const gchar * path_string, + const gchar * new_text, gpointer user_data); +static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle, + gchar * arg1, gpointer user_data); + +void init_right_tree(void) +{ + GtkTreeView *view = GTK_TREE_VIEW(tree2_w); + GtkCellRenderer *renderer; + GtkTreeSelection *sel; + GtkTreeViewColumn *column; + gint i; + + gtk_tree_view_set_model(view, model2); + gtk_tree_view_set_headers_visible(view, TRUE); + gtk_tree_view_set_rules_hint(view, FALSE); + + column = gtk_tree_view_column_new(); + gtk_tree_view_append_column(view, column); + gtk_tree_view_column_set_title(column, _("Options")); + + renderer = gtk_cell_renderer_pixbuf_new(); + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), + renderer, FALSE); + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), + renderer, + "pixbuf", COL_PIXBUF, + "visible", COL_PIXVIS, NULL); + renderer = gtk_cell_renderer_toggle_new(); + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), + renderer, FALSE); + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), + renderer, + "active", COL_BTNACT, + "inconsistent", COL_BTNINC, + "visible", COL_BTNVIS, + "radio", COL_BTNRAD, NULL); + /*g_signal_connect(G_OBJECT(renderer), "toggled", + G_CALLBACK(renderer_toggled), NULL); */ + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), + renderer, FALSE); + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), + renderer, + "text", COL_OPTION, + "foreground-gdk", + COL_COLOR, NULL); + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(view, -1, + _("Name"), renderer, + "text", COL_NAME, + "foreground-gdk", + COL_COLOR, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(view, -1, + "N", renderer, + "text", COL_NO, + "foreground-gdk", + COL_COLOR, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(view, -1, + "M", renderer, + "text", COL_MOD, + "foreground-gdk", + COL_COLOR, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(view, -1, + "Y", renderer, + "text", COL_YES, + "foreground-gdk", + COL_COLOR, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(view, -1, + _("Value"), renderer, + "text", COL_VALUE, + "editable", + COL_EDIT, + "foreground-gdk", + COL_COLOR, NULL); + g_signal_connect(G_OBJECT(renderer), "edited", + G_CALLBACK(renderer_edited), NULL); + + column = gtk_tree_view_get_column(view, COL_NAME); + gtk_tree_view_column_set_visible(column, show_name); + column = gtk_tree_view_get_column(view, COL_NO); + gtk_tree_view_column_set_visible(column, show_range); + column = gtk_tree_view_get_column(view, COL_MOD); + gtk_tree_view_column_set_visible(column, show_range); + column = gtk_tree_view_get_column(view, COL_YES); + gtk_tree_view_column_set_visible(column, show_range); + column = gtk_tree_view_get_column(view, COL_VALUE); + gtk_tree_view_column_set_visible(column, show_value); + + if (resizeable) { + for (i = 0; i < COL_VALUE; i++) { + column = gtk_tree_view_get_column(view, i); + gtk_tree_view_column_set_resizable(column, TRUE); + } + } + + sel = gtk_tree_view_get_selection(view); + gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); +} + + +/* Utility Functions */ + + +static void text_insert_help(struct menu *menu) +{ + GtkTextBuffer *buffer; + GtkTextIter start, end; + const char *prompt = _(menu_get_prompt(menu)); + struct gstr help = str_new(); + + menu_get_ext_help(menu, &help); + + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); + gtk_text_buffer_get_bounds(buffer, &start, &end); + gtk_text_buffer_delete(buffer, &start, &end); + gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15); + + gtk_text_buffer_get_end_iter(buffer, &end); + gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1, + NULL); + gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2); + gtk_text_buffer_get_end_iter(buffer, &end); + gtk_text_buffer_insert_with_tags(buffer, &end, str_get(&help), -1, tag2, + NULL); + str_free(&help); +} + + +static void text_insert_msg(const char *title, const char *message) +{ + GtkTextBuffer *buffer; + GtkTextIter start, end; + const char *msg = message; + + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); + gtk_text_buffer_get_bounds(buffer, &start, &end); + gtk_text_buffer_delete(buffer, &start, &end); + gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15); + + gtk_text_buffer_get_end_iter(buffer, &end); + gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1, + NULL); + gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2); + gtk_text_buffer_get_end_iter(buffer, &end); + gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2, + NULL); +} + + +/* Main Windows Callbacks */ + +void on_save_activate(GtkMenuItem * menuitem, gpointer user_data); +gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event, + gpointer user_data) +{ + GtkWidget *dialog, *label; + gint result; + + if (!conf_get_changed()) + return FALSE; + + dialog = gtk_dialog_new_with_buttons(_("Warning !"), + GTK_WINDOW(main_wnd), + (GtkDialogFlags) + (GTK_DIALOG_MODAL | + GTK_DIALOG_DESTROY_WITH_PARENT), + GTK_STOCK_OK, + GTK_RESPONSE_YES, + GTK_STOCK_NO, + GTK_RESPONSE_NO, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, NULL); + gtk_dialog_set_default_response(GTK_DIALOG(dialog), + GTK_RESPONSE_CANCEL); + + label = gtk_label_new(_("\nSave configuration ?\n")); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); + gtk_widget_show(label); + + result = gtk_dialog_run(GTK_DIALOG(dialog)); + switch (result) { + case GTK_RESPONSE_YES: + on_save_activate(NULL, NULL); + return FALSE; + case GTK_RESPONSE_NO: + return FALSE; + case GTK_RESPONSE_CANCEL: + case GTK_RESPONSE_DELETE_EVENT: + default: + gtk_widget_destroy(dialog); + return TRUE; + } + + return FALSE; +} + + +void on_window1_destroy(GtkObject * object, gpointer user_data) +{ + gtk_main_quit(); +} + + +void +on_window1_size_request(GtkWidget * widget, + GtkRequisition * requisition, gpointer user_data) +{ + static gint old_h; + gint w, h; + + if (widget->window == NULL) + gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h); + else + gdk_window_get_size(widget->window, &w, &h); + + if (h == old_h) + return; + old_h = h; + + gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3); +} + + +/* Menu & Toolbar Callbacks */ + + +static void +load_filename(GtkFileSelection * file_selector, gpointer user_data) +{ + const gchar *fn; + + fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION + (user_data)); + + if (conf_read(fn)) + text_insert_msg(_("Error"), _("Unable to load configuration !")); + else + display_tree(&rootmenu); +} + +void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkWidget *fs; + + fs = gtk_file_selection_new(_("Load file...")); + g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), + "clicked", + G_CALLBACK(load_filename), (gpointer) fs); + g_signal_connect_swapped(GTK_OBJECT + (GTK_FILE_SELECTION(fs)->ok_button), + "clicked", G_CALLBACK(gtk_widget_destroy), + (gpointer) fs); + g_signal_connect_swapped(GTK_OBJECT + (GTK_FILE_SELECTION(fs)->cancel_button), + "clicked", G_CALLBACK(gtk_widget_destroy), + (gpointer) fs); + gtk_widget_show(fs); +} + + +void on_save_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + if (conf_write(NULL)) + text_insert_msg(_("Error"), _("Unable to save configuration !")); +} + + +static void +store_filename(GtkFileSelection * file_selector, gpointer user_data) +{ + const gchar *fn; + + fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION + (user_data)); + + if (conf_write(fn)) + text_insert_msg(_("Error"), _("Unable to save configuration !")); + + gtk_widget_destroy(GTK_WIDGET(user_data)); +} + +void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkWidget *fs; + + fs = gtk_file_selection_new(_("Save file as...")); + g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), + "clicked", + G_CALLBACK(store_filename), (gpointer) fs); + g_signal_connect_swapped(GTK_OBJECT + (GTK_FILE_SELECTION(fs)->ok_button), + "clicked", G_CALLBACK(gtk_widget_destroy), + (gpointer) fs); + g_signal_connect_swapped(GTK_OBJECT + (GTK_FILE_SELECTION(fs)->cancel_button), + "clicked", G_CALLBACK(gtk_widget_destroy), + (gpointer) fs); + gtk_widget_show(fs); +} + + +void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + if (!on_window1_delete_event(NULL, NULL, NULL)) + gtk_widget_destroy(GTK_WIDGET(main_wnd)); +} + + +void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkTreeViewColumn *col; + + show_name = GTK_CHECK_MENU_ITEM(menuitem)->active; + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME); + if (col) + gtk_tree_view_column_set_visible(col, show_name); +} + + +void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkTreeViewColumn *col; + + show_range = GTK_CHECK_MENU_ITEM(menuitem)->active; + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO); + if (col) + gtk_tree_view_column_set_visible(col, show_range); + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD); + if (col) + gtk_tree_view_column_set_visible(col, show_range); + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES); + if (col) + gtk_tree_view_column_set_visible(col, show_range); + +} + + +void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkTreeViewColumn *col; + + show_value = GTK_CHECK_MENU_ITEM(menuitem)->active; + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE); + if (col) + gtk_tree_view_column_set_visible(col, show_value); +} + + +void +on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data) +{ + opt_mode = OPT_NORMAL; + gtk_tree_store_clear(tree2); + display_tree(&rootmenu); /* instead of update_tree to speed-up */ +} + + +void +on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data) +{ + opt_mode = OPT_ALL; + gtk_tree_store_clear(tree2); + display_tree(&rootmenu); /* instead of update_tree to speed-up */ +} + + +void +on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data) +{ + opt_mode = OPT_PROMPT; + gtk_tree_store_clear(tree2); + display_tree(&rootmenu); /* instead of update_tree to speed-up */ +} + + +void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkWidget *dialog; + const gchar *intro_text = _( + "Welcome to gkc, the GTK+ graphical configuration tool\n" + "For each option, a blank box indicates the feature is disabled, a\n" + "check indicates it is enabled, and a dot indicates that it is to\n" + "be compiled as a module. Clicking on the box will cycle through the three states.\n" + "\n" + "If you do not see an option (e.g., a device driver) that you\n" + "believe should be present, try turning on Show All Options\n" + "under the Options menu.\n" + "Although there is no cross reference yet to help you figure out\n" + "what other options must be enabled to support the option you\n" + "are interested in, you can still view the help of a grayed-out\n" + "option.\n" + "\n" + "Toggling Show Debug Info under the Options menu will show \n" + "the dependencies, which you can then match by examining other options."); + + dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, intro_text); + g_signal_connect_swapped(GTK_OBJECT(dialog), "response", + G_CALLBACK(gtk_widget_destroy), + GTK_OBJECT(dialog)); + gtk_widget_show_all(dialog); +} + + +void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkWidget *dialog; + const gchar *about_text = + _("gkc is copyright (c) 2002 Romain Lievin .\n" + "Based on the source code from Roman Zippel.\n"); + + dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, about_text); + g_signal_connect_swapped(GTK_OBJECT(dialog), "response", + G_CALLBACK(gtk_widget_destroy), + GTK_OBJECT(dialog)); + gtk_widget_show_all(dialog); +} + + +void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkWidget *dialog; + const gchar *license_text = + _("gkc is released under the terms of the GNU GPL v2.\n" + "For more information, please see the source code or\n" + "visit http://www.fsf.org/licenses/licenses.html\n"); + + dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, license_text); + g_signal_connect_swapped(GTK_OBJECT(dialog), "response", + G_CALLBACK(gtk_widget_destroy), + GTK_OBJECT(dialog)); + gtk_widget_show_all(dialog); +} + + +void on_back_clicked(GtkButton * button, gpointer user_data) +{ + enum prop_type ptype; + + current = current->parent; + ptype = current->prompt ? current->prompt->type : P_UNKNOWN; + if (ptype != P_MENU) + current = current->parent; + display_tree_part(); + + if (current == &rootmenu) + gtk_widget_set_sensitive(back_btn, FALSE); +} + + +void on_load_clicked(GtkButton * button, gpointer user_data) +{ + on_load1_activate(NULL, user_data); +} + + +void on_single_clicked(GtkButton * button, gpointer user_data) +{ + view_mode = SINGLE_VIEW; + gtk_paned_set_position(GTK_PANED(hpaned), 0); + gtk_widget_hide(tree1_w); + current = &rootmenu; + display_tree_part(); +} + + +void on_split_clicked(GtkButton * button, gpointer user_data) +{ + gint w, h; + view_mode = SPLIT_VIEW; + gtk_widget_show(tree1_w); + gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h); + gtk_paned_set_position(GTK_PANED(hpaned), w / 2); + if (tree2) + gtk_tree_store_clear(tree2); + display_list(); + + /* Disable back btn, like in full mode. */ + gtk_widget_set_sensitive(back_btn, FALSE); +} + + +void on_full_clicked(GtkButton * button, gpointer user_data) +{ + view_mode = FULL_VIEW; + gtk_paned_set_position(GTK_PANED(hpaned), 0); + gtk_widget_hide(tree1_w); + if (tree2) + gtk_tree_store_clear(tree2); + display_tree(&rootmenu); + gtk_widget_set_sensitive(back_btn, FALSE); +} + + +void on_collapse_clicked(GtkButton * button, gpointer user_data) +{ + gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w)); +} + + +void on_expand_clicked(GtkButton * button, gpointer user_data) +{ + gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w)); +} + + +/* CTree Callbacks */ + +/* Change hex/int/string value in the cell */ +static void renderer_edited(GtkCellRendererText * cell, + const gchar * path_string, + const gchar * new_text, gpointer user_data) +{ + GtkTreePath *path = gtk_tree_path_new_from_string(path_string); + GtkTreeIter iter; + const char *old_def, *new_def; + struct menu *menu; + struct symbol *sym; + + if (!gtk_tree_model_get_iter(model2, &iter, path)) + return; + + gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); + sym = menu->sym; + + gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1); + new_def = new_text; + + sym_set_string_value(sym, new_def); + + update_tree(&rootmenu, NULL); + + gtk_tree_path_free(path); +} + +/* Change the value of a symbol and update the tree */ +static void change_sym_value(struct menu *menu, gint col) +{ + struct symbol *sym = menu->sym; + tristate oldval, newval; + + if (!sym) + return; + + if (col == COL_NO) + newval = no; + else if (col == COL_MOD) + newval = mod; + else if (col == COL_YES) + newval = yes; + else + return; + + switch (sym_get_type(sym)) { + case S_BOOLEAN: + case S_TRISTATE: + oldval = sym_get_tristate_value(sym); + if (!sym_tristate_within_range(sym, newval)) + newval = yes; + sym_set_tristate_value(sym, newval); + if (view_mode == FULL_VIEW) + update_tree(&rootmenu, NULL); + else if (view_mode == SPLIT_VIEW) { + update_tree(browsed, NULL); + display_list(); + } + else if (view_mode == SINGLE_VIEW) + display_tree_part(); //fixme: keep exp/coll + break; + case S_INT: + case S_HEX: + case S_STRING: + default: + break; + } +} + +static void toggle_sym_value(struct menu *menu) +{ + if (!menu->sym) + return; + + sym_toggle_tristate_value(menu->sym); + if (view_mode == FULL_VIEW) + update_tree(&rootmenu, NULL); + else if (view_mode == SPLIT_VIEW) { + update_tree(browsed, NULL); + display_list(); + } + else if (view_mode == SINGLE_VIEW) + display_tree_part(); //fixme: keep exp/coll +} + +static void renderer_toggled(GtkCellRendererToggle * cell, + gchar * path_string, gpointer user_data) +{ + GtkTreePath *path, *sel_path = NULL; + GtkTreeIter iter, sel_iter; + GtkTreeSelection *sel; + struct menu *menu; + + path = gtk_tree_path_new_from_string(path_string); + if (!gtk_tree_model_get_iter(model2, &iter, path)) + return; + + sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w)); + if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter)) + sel_path = gtk_tree_model_get_path(model2, &sel_iter); + if (!sel_path) + goto out1; + if (gtk_tree_path_compare(path, sel_path)) + goto out2; + + gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); + toggle_sym_value(menu); + + out2: + gtk_tree_path_free(sel_path); + out1: + gtk_tree_path_free(path); +} + +static gint column2index(GtkTreeViewColumn * column) +{ + gint i; + + for (i = 0; i < COL_NUMBER; i++) { + GtkTreeViewColumn *col; + + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i); + if (col == column) + return i; + } + + return -1; +} + + +/* User click: update choice (full) or goes down (single) */ +gboolean +on_treeview2_button_press_event(GtkWidget * widget, + GdkEventButton * event, gpointer user_data) +{ + GtkTreeView *view = GTK_TREE_VIEW(widget); + GtkTreePath *path; + GtkTreeViewColumn *column; + GtkTreeIter iter; + struct menu *menu; + gint col; + +#if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK + gint tx = (gint) event->x; + gint ty = (gint) event->y; + gint cx, cy; + + gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx, + &cy); +#else + gtk_tree_view_get_cursor(view, &path, &column); +#endif + if (path == NULL) + return FALSE; + + if (!gtk_tree_model_get_iter(model2, &iter, path)) + return FALSE; + gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); + + col = column2index(column); + if (event->type == GDK_2BUTTON_PRESS) { + enum prop_type ptype; + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + + if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) { + // goes down into menu + current = menu; + display_tree_part(); + gtk_widget_set_sensitive(back_btn, TRUE); + } else if ((col == COL_OPTION)) { + toggle_sym_value(menu); + gtk_tree_view_expand_row(view, path, TRUE); + } + } else { + if (col == COL_VALUE) { + toggle_sym_value(menu); + gtk_tree_view_expand_row(view, path, TRUE); + } else if (col == COL_NO || col == COL_MOD + || col == COL_YES) { + change_sym_value(menu, col); + gtk_tree_view_expand_row(view, path, TRUE); + } + } + + return FALSE; +} + +/* Key pressed: update choice */ +gboolean +on_treeview2_key_press_event(GtkWidget * widget, + GdkEventKey * event, gpointer user_data) +{ + GtkTreeView *view = GTK_TREE_VIEW(widget); + GtkTreePath *path; + GtkTreeViewColumn *column; + GtkTreeIter iter; + struct menu *menu; + gint col; + + gtk_tree_view_get_cursor(view, &path, &column); + if (path == NULL) + return FALSE; + + if (event->keyval == GDK_space) { + if (gtk_tree_view_row_expanded(view, path)) + gtk_tree_view_collapse_row(view, path); + else + gtk_tree_view_expand_row(view, path, FALSE); + return TRUE; + } + if (event->keyval == GDK_KP_Enter) { + } + if (widget == tree1_w) + return FALSE; + + gtk_tree_model_get_iter(model2, &iter, path); + gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); + + if (!strcasecmp(event->string, "n")) + col = COL_NO; + else if (!strcasecmp(event->string, "m")) + col = COL_MOD; + else if (!strcasecmp(event->string, "y")) + col = COL_YES; + else + col = -1; + change_sym_value(menu, col); + + return FALSE; +} + + +/* Row selection changed: update help */ +void +on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data) +{ + GtkTreeSelection *selection; + GtkTreeIter iter; + struct menu *menu; + + selection = gtk_tree_view_get_selection(treeview); + if (gtk_tree_selection_get_selected(selection, &model2, &iter)) { + gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); + text_insert_help(menu); + } +} + + +/* User click: display sub-tree in the right frame. */ +gboolean +on_treeview1_button_press_event(GtkWidget * widget, + GdkEventButton * event, gpointer user_data) +{ + GtkTreeView *view = GTK_TREE_VIEW(widget); + GtkTreePath *path; + GtkTreeViewColumn *column; + GtkTreeIter iter; + struct menu *menu; + + gint tx = (gint) event->x; + gint ty = (gint) event->y; + gint cx, cy; + + gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx, + &cy); + if (path == NULL) + return FALSE; + + gtk_tree_model_get_iter(model1, &iter, path); + gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1); + + if (event->type == GDK_2BUTTON_PRESS) { + toggle_sym_value(menu); + current = menu; + display_tree_part(); + } else { + browsed = menu; + display_tree_part(); + } + + gtk_widget_realize(tree2_w); + gtk_tree_view_set_cursor(view, path, NULL, FALSE); + gtk_widget_grab_focus(tree2_w); + + return FALSE; +} + + +/* Fill a row of strings */ +static gchar **fill_row(struct menu *menu) +{ + static gchar *row[COL_NUMBER]; + struct symbol *sym = menu->sym; + const char *def; + int stype; + tristate val; + enum prop_type ptype; + int i; + + for (i = COL_OPTION; i <= COL_COLOR; i++) + g_free(row[i]); + bzero(row, sizeof(row)); + + row[COL_OPTION] = + g_strdup_printf("%s %s", _(menu_get_prompt(menu)), + sym && !sym_has_value(sym) ? "(NEW)" : ""); + + if (opt_mode == OPT_ALL && !menu_is_visible(menu)) + row[COL_COLOR] = g_strdup("DarkGray"); + else if (opt_mode == OPT_PROMPT && + menu_has_prompt(menu) && !menu_is_visible(menu)) + row[COL_COLOR] = g_strdup("DarkGray"); + else + row[COL_COLOR] = g_strdup("Black"); + + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + switch (ptype) { + case P_MENU: + row[COL_PIXBUF] = (gchar *) xpm_menu; + if (view_mode == SINGLE_VIEW) + row[COL_PIXVIS] = GINT_TO_POINTER(TRUE); + row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); + break; + case P_COMMENT: + row[COL_PIXBUF] = (gchar *) xpm_void; + row[COL_PIXVIS] = GINT_TO_POINTER(FALSE); + row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); + break; + default: + row[COL_PIXBUF] = (gchar *) xpm_void; + row[COL_PIXVIS] = GINT_TO_POINTER(FALSE); + row[COL_BTNVIS] = GINT_TO_POINTER(TRUE); + break; + } + + if (!sym) + return row; + row[COL_NAME] = g_strdup(sym->name); + + sym_calc_value(sym); + sym->flags &= ~SYMBOL_CHANGED; + + if (sym_is_choice(sym)) { // parse childs for getting final value + struct menu *child; + struct symbol *def_sym = sym_get_choice_value(sym); + struct menu *def_menu = NULL; + + row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); + + for (child = menu->list; child; child = child->next) { + if (menu_is_visible(child) + && child->sym == def_sym) + def_menu = child; + } + + if (def_menu) + row[COL_VALUE] = + g_strdup(_(menu_get_prompt(def_menu))); + } + if (sym->flags & SYMBOL_CHOICEVAL) + row[COL_BTNRAD] = GINT_TO_POINTER(TRUE); + + stype = sym_get_type(sym); + switch (stype) { + case S_BOOLEAN: + if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE) + row[COL_BTNVIS] = GINT_TO_POINTER(TRUE); + if (sym_is_choice(sym)) + break; + case S_TRISTATE: + val = sym_get_tristate_value(sym); + switch (val) { + case no: + row[COL_NO] = g_strdup("N"); + row[COL_VALUE] = g_strdup("N"); + row[COL_BTNACT] = GINT_TO_POINTER(FALSE); + row[COL_BTNINC] = GINT_TO_POINTER(FALSE); + break; + case mod: + row[COL_MOD] = g_strdup("M"); + row[COL_VALUE] = g_strdup("M"); + row[COL_BTNINC] = GINT_TO_POINTER(TRUE); + break; + case yes: + row[COL_YES] = g_strdup("Y"); + row[COL_VALUE] = g_strdup("Y"); + row[COL_BTNACT] = GINT_TO_POINTER(TRUE); + row[COL_BTNINC] = GINT_TO_POINTER(FALSE); + break; + } + + if (val != no && sym_tristate_within_range(sym, no)) + row[COL_NO] = g_strdup("_"); + if (val != mod && sym_tristate_within_range(sym, mod)) + row[COL_MOD] = g_strdup("_"); + if (val != yes && sym_tristate_within_range(sym, yes)) + row[COL_YES] = g_strdup("_"); + break; + case S_INT: + case S_HEX: + case S_STRING: + def = sym_get_string_value(sym); + row[COL_VALUE] = g_strdup(def); + row[COL_EDIT] = GINT_TO_POINTER(TRUE); + row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); + break; + } + + return row; +} + + +/* Set the node content with a row of strings */ +static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row) +{ + GdkColor color; + gboolean success; + GdkPixbuf *pix; + + pix = gdk_pixbuf_new_from_xpm_data((const char **) + row[COL_PIXBUF]); + + gdk_color_parse(row[COL_COLOR], &color); + gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1, + FALSE, FALSE, &success); + + gtk_tree_store_set(tree, node, + COL_OPTION, row[COL_OPTION], + COL_NAME, row[COL_NAME], + COL_NO, row[COL_NO], + COL_MOD, row[COL_MOD], + COL_YES, row[COL_YES], + COL_VALUE, row[COL_VALUE], + COL_MENU, (gpointer) menu, + COL_COLOR, &color, + COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]), + COL_PIXBUF, pix, + COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]), + COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]), + COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]), + COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]), + COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]), + -1); + + g_object_unref(pix); +} + + +/* Add a node to the tree */ +static void place_node(struct menu *menu, char **row) +{ + GtkTreeIter *parent = parents[indent - 1]; + GtkTreeIter *node = parents[indent]; + + gtk_tree_store_append(tree, node, parent); + set_node(node, menu, row); +} + + +/* Find a node in the GTK+ tree */ +static GtkTreeIter found; + +/* + * Find a menu in the GtkTree starting at parent. + */ +GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent, + struct menu *tofind) +{ + GtkTreeIter iter; + GtkTreeIter *child = &iter; + gboolean valid; + GtkTreeIter *ret; + + valid = gtk_tree_model_iter_children(model2, child, parent); + while (valid) { + struct menu *menu; + + gtk_tree_model_get(model2, child, 6, &menu, -1); + + if (menu == tofind) { + memcpy(&found, child, sizeof(GtkTreeIter)); + return &found; + } + + ret = gtktree_iter_find_node(child, tofind); + if (ret) + return ret; + + valid = gtk_tree_model_iter_next(model2, child); + } + + return NULL; +} + + +/* + * Update the tree by adding/removing entries + * Does not change other nodes + */ +static void update_tree(struct menu *src, GtkTreeIter * dst) +{ + struct menu *child1; + GtkTreeIter iter, tmp; + GtkTreeIter *child2 = &iter; + gboolean valid; + GtkTreeIter *sibling; + struct symbol *sym; + struct property *prop; + struct menu *menu1, *menu2; + + if (src == &rootmenu) + indent = 1; + + valid = gtk_tree_model_iter_children(model2, child2, dst); + for (child1 = src->list; child1; child1 = child1->next) { + + prop = child1->prompt; + sym = child1->sym; + + reparse: + menu1 = child1; + if (valid) + gtk_tree_model_get(model2, child2, COL_MENU, + &menu2, -1); + else + menu2 = NULL; // force adding of a first child + +#ifdef DEBUG + printf("%*c%s | %s\n", indent, ' ', + menu1 ? menu_get_prompt(menu1) : "nil", + menu2 ? menu_get_prompt(menu2) : "nil"); +#endif + + if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) || + (opt_mode == OPT_PROMPT && !menu_has_prompt(child1)) || + (opt_mode == OPT_ALL && !menu_get_prompt(child1))) { + + /* remove node */ + if (gtktree_iter_find_node(dst, menu1) != NULL) { + memcpy(&tmp, child2, sizeof(GtkTreeIter)); + valid = gtk_tree_model_iter_next(model2, + child2); + gtk_tree_store_remove(tree2, &tmp); + if (!valid) + return; /* next parent */ + else + goto reparse; /* next child */ + } else + continue; + } + + if (menu1 != menu2) { + if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node + if (!valid && !menu2) + sibling = NULL; + else + sibling = child2; + gtk_tree_store_insert_before(tree2, + child2, + dst, sibling); + set_node(child2, menu1, fill_row(menu1)); + if (menu2 == NULL) + valid = TRUE; + } else { // remove node + memcpy(&tmp, child2, sizeof(GtkTreeIter)); + valid = gtk_tree_model_iter_next(model2, + child2); + gtk_tree_store_remove(tree2, &tmp); + if (!valid) + return; // next parent + else + goto reparse; // next child + } + } else if (sym && (sym->flags & SYMBOL_CHANGED)) { + set_node(child2, menu1, fill_row(menu1)); + } + + indent++; + update_tree(child1, child2); + indent--; + + valid = gtk_tree_model_iter_next(model2, child2); + } +} + + +/* Display the whole tree (single/split/full view) */ +static void display_tree(struct menu *menu) +{ + struct symbol *sym; + struct property *prop; + struct menu *child; + enum prop_type ptype; + + if (menu == &rootmenu) { + indent = 1; + current = &rootmenu; + } + + for (child = menu->list; child; child = child->next) { + prop = child->prompt; + sym = child->sym; + ptype = prop ? prop->type : P_UNKNOWN; + + if (sym) + sym->flags &= ~SYMBOL_CHANGED; + + if ((view_mode == SPLIT_VIEW) + && !(child->flags & MENU_ROOT) && (tree == tree1)) + continue; + + if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT) + && (tree == tree2)) + continue; + + if ((opt_mode == OPT_NORMAL && menu_is_visible(child)) || + (opt_mode == OPT_PROMPT && menu_has_prompt(child)) || + (opt_mode == OPT_ALL && menu_get_prompt(child))) + place_node(child, fill_row(child)); +#ifdef DEBUG + printf("%*c%s: ", indent, ' ', menu_get_prompt(child)); + printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : ""); + printf("%s", prop_get_type_name(ptype)); + printf(" | "); + if (sym) { + printf("%s", sym_type_name(sym->type)); + printf(" | "); + printf("%s", dbg_sym_flags(sym->flags)); + printf("\n"); + } else + printf("\n"); +#endif + if ((view_mode != FULL_VIEW) && (ptype == P_MENU) + && (tree == tree2)) + continue; +/* + if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT)) + || (view_mode == FULL_VIEW) + || (view_mode == SPLIT_VIEW))*/ + if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT)) + || (view_mode == FULL_VIEW) + || (view_mode == SPLIT_VIEW)) { + indent++; + display_tree(child); + indent--; + } + } +} + +/* Display a part of the tree starting at current node (single/split view) */ +static void display_tree_part(void) +{ + if (tree2) + gtk_tree_store_clear(tree2); + if (view_mode == SINGLE_VIEW) + display_tree(current); + else if (view_mode == SPLIT_VIEW) + display_tree(browsed); + gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w)); +} + +/* Display the list in the left frame (split view) */ +static void display_list(void) +{ + if (tree1) + gtk_tree_store_clear(tree1); + + tree = tree1; + display_tree(&rootmenu); + gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w)); + tree = tree2; +} + +void fixup_rootmenu(struct menu *menu) +{ + struct menu *child; + static int menu_cnt = 0; + + menu->flags |= MENU_ROOT; + for (child = menu->list; child; child = child->next) { + if (child->prompt && child->prompt->type == P_MENU) { + menu_cnt++; + fixup_rootmenu(child); + menu_cnt--; + } else if (!menu_cnt) + fixup_rootmenu(child); + } +} + + +/* Main */ +int main(int ac, char *av[]) +{ + const char *name; + char *env; + gchar *glade_file; + +#ifndef LKC_DIRECT_LINK + kconfig_load(); +#endif + + bindtextdomain(PACKAGE, LOCALEDIR); + bind_textdomain_codeset(PACKAGE, "UTF-8"); + textdomain(PACKAGE); + + /* GTK stuffs */ + gtk_set_locale(); + gtk_init(&ac, &av); + glade_init(); + + //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps"); + //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps"); + + /* Determine GUI path */ + env = getenv(SRCTREE); + if (env) + glade_file = g_strconcat(env, "/tools/kconfig/gconf.glade", NULL); + else if (av[0][0] == '/') + glade_file = g_strconcat(av[0], ".glade", NULL); + else + glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL); + + /* Conf stuffs */ + if (ac > 1 && av[1][0] == '-') { + switch (av[1][1]) { + case 'a': + //showAll = 1; + break; + case 'h': + case '?': + printf("%s \n", av[0]); + exit(0); + } + name = av[2]; + } else + name = av[1]; + + conf_parse(name); + fixup_rootmenu(&rootmenu); + conf_read(NULL); + + /* Load the interface and connect signals */ + init_main_window(glade_file); + init_tree_model(); + init_left_tree(); + init_right_tree(); + + switch (view_mode) { + case SINGLE_VIEW: + display_tree_part(); + break; + case SPLIT_VIEW: + display_list(); + break; + case FULL_VIEW: + display_tree(&rootmenu); + break; + } + + gtk_main(); + + return 0; +} + +static void conf_changed(void) +{ + bool changed = conf_get_changed(); + gtk_widget_set_sensitive(save_btn, changed); + gtk_widget_set_sensitive(save_menu_item, changed); +} diff --git a/bios/seabios/tools/kconfig/gconf.glade b/bios/seabios/tools/kconfig/gconf.glade new file mode 100644 index 0000000..aa483cb --- /dev/null +++ b/bios/seabios/tools/kconfig/gconf.glade @@ -0,0 +1,661 @@ + + + + + + True + Gtk Kernel Configurator + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 640 + 480 + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + + + + + + + True + False + 0 + + + + True + + + + True + _File + True + + + + + + + True + Load a config file + _Load + True + + + + + + True + gtk-open + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Save the config in .config + _Save + True + + + + + + True + gtk-save + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Save the config in a file + Save _as + True + + + + + True + gtk-save-as + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + + + + + + True + _Quit + True + + + + + + True + gtk-quit + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + + True + _Options + True + + + + + + + True + Show name + Show _name + True + False + + + + + + + True + Show range (Y/M/N) + Show _range + True + False + + + + + + + True + Show value of the option + Show _data + True + False + + + + + + + True + + + + + + True + Show normal options + Show normal options + True + True + + + + + + + True + Show all options + Show all _options + True + False + set_option_mode1 + + + + + + + True + Show all options with prompts + Show all prompt options + True + False + set_option_mode1 + + + + + + + + + + + + True + _Help + True + + + + + + + True + _Introduction + True + + + + + + True + gtk-dialog-question + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + _About + True + + + + + + True + gtk-properties + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + _License + True + + + + + True + gtk-justify-fill + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + 0 + False + False + + + + + + True + GTK_SHADOW_OUT + GTK_POS_LEFT + GTK_POS_TOP + + + + True + GTK_ORIENTATION_HORIZONTAL + GTK_TOOLBAR_BOTH + True + True + + + + True + Goes up of one level (single view) + Back + True + gtk-undo + True + True + False + + + + False + True + + + + + + True + True + True + False + + + + True + + + + + False + False + + + + + + True + Load a config file + Load + True + gtk-open + True + True + False + + + + False + True + + + + + + True + Save a config file + Save + True + gtk-save + True + True + False + + + + False + True + + + + + + True + True + True + False + + + + True + + + + + False + False + + + + + + True + Single view + Single + True + gtk-missing-image + True + True + False + + + + False + True + + + + + + True + Split view + Split + True + gtk-missing-image + True + True + False + + + + False + True + + + + + + True + Full view + Full + True + gtk-missing-image + True + True + False + + + + False + True + + + + + + True + True + True + False + + + + True + + + + + False + False + + + + + + True + Collapse the whole tree in the right frame + Collapse + True + gtk-remove + True + True + False + + + + False + True + + + + + + True + Expand the whole tree in the right frame + Expand + True + gtk-add + True + True + False + + + + False + True + + + + + + + 0 + False + False + + + + + + 1 + True + True + 0 + + + + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + False + False + False + + + + + + + + True + False + + + + + + True + True + 0 + + + + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + True + False + False + False + + + + + + + + True + False + + + + + + True + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + False + False + True + GTK_JUSTIFY_LEFT + GTK_WRAP_WORD + True + 0 + 0 + 0 + 0 + 0 + 0 + Sorry, no help available for this option yet. + + + + + True + True + + + + + True + True + + + + + 0 + True + True + + + + + + + diff --git a/bios/seabios/tools/kconfig/images.c b/bios/seabios/tools/kconfig/images.c new file mode 100644 index 0000000..d4f84bd --- /dev/null +++ b/bios/seabios/tools/kconfig/images.c @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +static const char *xpm_load[] = { +"22 22 5 1", +". c None", +"# c #000000", +"c c #838100", +"a c #ffff00", +"b c #ffffff", +"......................", +"......................", +"......................", +"............####....#.", +"...........#....##.##.", +"..................###.", +".................####.", +".####...........#####.", +"#abab##########.......", +"#babababababab#.......", +"#ababababababa#.......", +"#babababababab#.......", +"#ababab###############", +"#babab##cccccccccccc##", +"#abab##cccccccccccc##.", +"#bab##cccccccccccc##..", +"#ab##cccccccccccc##...", +"#b##cccccccccccc##....", +"###cccccccccccc##.....", +"##cccccccccccc##......", +"###############.......", +"......................"}; + +static const char *xpm_save[] = { +"22 22 5 1", +". c None", +"# c #000000", +"a c #838100", +"b c #c5c2c5", +"c c #cdb6d5", +"......................", +".####################.", +".#aa#bbbbbbbbbbbb#bb#.", +".#aa#bbbbbbbbbbbb#bb#.", +".#aa#bbbbbbbbbcbb####.", +".#aa#bbbccbbbbbbb#aa#.", +".#aa#bbbccbbbbbbb#aa#.", +".#aa#bbbbbbbbbbbb#aa#.", +".#aa#bbbbbbbbbbbb#aa#.", +".#aa#bbbbbbbbbbbb#aa#.", +".#aa#bbbbbbbbbbbb#aa#.", +".#aaa############aaa#.", +".#aaaaaaaaaaaaaaaaaa#.", +".#aaaaaaaaaaaaaaaaaa#.", +".#aaa#############aa#.", +".#aaa#########bbb#aa#.", +".#aaa#########bbb#aa#.", +".#aaa#########bbb#aa#.", +".#aaa#########bbb#aa#.", +".#aaa#########bbb#aa#.", +"..##################..", +"......................"}; + +static const char *xpm_back[] = { +"22 22 3 1", +". c None", +"# c #000083", +"a c #838183", +"......................", +"......................", +"......................", +"......................", +"......................", +"...........######a....", +"..#......##########...", +"..##...####......##a..", +"..###.###.........##..", +"..######..........##..", +"..#####...........##..", +"..######..........##..", +"..#######.........##..", +"..########.......##a..", +"...............a###...", +"...............###....", +"......................", +"......................", +"......................", +"......................", +"......................", +"......................"}; + +static const char *xpm_tree_view[] = { +"22 22 2 1", +". c None", +"# c #000000", +"......................", +"......................", +"......#...............", +"......#...............", +"......#...............", +"......#...............", +"......#...............", +"......########........", +"......#...............", +"......#...............", +"......#...............", +"......#...............", +"......#...............", +"......########........", +"......#...............", +"......#...............", +"......#...............", +"......#...............", +"......#...............", +"......########........", +"......................", +"......................"}; + +static const char *xpm_single_view[] = { +"22 22 2 1", +". c None", +"# c #000000", +"......................", +"......................", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"......................", +"......................"}; + +static const char *xpm_split_view[] = { +"22 22 2 1", +". c None", +"# c #000000", +"......................", +"......................", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......................", +"......................"}; + +static const char *xpm_symbol_no[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .......... ", +" . . ", +" . . ", +" . . ", +" . . ", +" . . ", +" . . ", +" . . ", +" . . ", +" .......... ", +" "}; + +static const char *xpm_symbol_mod[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .......... ", +" . . ", +" . . ", +" . .. . ", +" . .... . ", +" . .... . ", +" . .. . ", +" . . ", +" . . ", +" .......... ", +" "}; + +static const char *xpm_symbol_yes[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .......... ", +" . . ", +" . . ", +" . . . ", +" . .. . ", +" . . .. . ", +" . .... . ", +" . .. . ", +" . . ", +" .......... ", +" "}; + +static const char *xpm_choice_no[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .... ", +" .. .. ", +" . . ", +" . . ", +" . . ", +" . . ", +" . . ", +" . . ", +" .. .. ", +" .... ", +" "}; + +static const char *xpm_choice_yes[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .... ", +" .. .. ", +" . . ", +" . .. . ", +" . .... . ", +" . .... . ", +" . .. . ", +" . . ", +" .. .. ", +" .... ", +" "}; + +static const char *xpm_menu[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .......... ", +" . . ", +" . .. . ", +" . .... . ", +" . ...... . ", +" . ...... . ", +" . .... . ", +" . .. . ", +" . . ", +" .......... ", +" "}; + +static const char *xpm_menu_inv[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .......... ", +" .......... ", +" .. ...... ", +" .. .... ", +" .. .. ", +" .. .. ", +" .. .... ", +" .. ...... ", +" .......... ", +" .......... ", +" "}; + +static const char *xpm_menuback[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .......... ", +" . . ", +" . .. . ", +" . .... . ", +" . ...... . ", +" . ...... . ", +" . .... . ", +" . .. . ", +" . . ", +" .......... ", +" "}; + +static const char *xpm_void[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/bios/seabios/tools/kconfig/kconfig_load.c b/bios/seabios/tools/kconfig/kconfig_load.c new file mode 100644 index 0000000..2d0cff8 --- /dev/null +++ b/bios/seabios/tools/kconfig/kconfig_load.c @@ -0,0 +1,35 @@ +#include +#include +#include + +#include "lkc.h" + +#define P(name,type,arg) type (*name ## _p) arg +#include "lkc_proto.h" +#undef P + +void kconfig_load(void) +{ + void *handle; + char *error; + + handle = dlopen("./libkconfig.so", RTLD_LAZY); + if (!handle) { + handle = dlopen("./tools/kconfig/libkconfig.so", RTLD_LAZY); + if (!handle) { + fprintf(stderr, "%s\n", dlerror()); + exit(1); + } + } + +#define P(name,type,arg) \ +{ \ + name ## _p = dlsym(handle, #name); \ + if ((error = dlerror())) { \ + fprintf(stderr, "%s\n", error); \ + exit(1); \ + } \ +} +#include "lkc_proto.h" +#undef P +} diff --git a/bios/seabios/tools/kconfig/kxgettext.c b/bios/seabios/tools/kconfig/kxgettext.c new file mode 100644 index 0000000..e9d8e79 --- /dev/null +++ b/bios/seabios/tools/kconfig/kxgettext.c @@ -0,0 +1,236 @@ +/* + * Arnaldo Carvalho de Melo , 2005 + * + * Released under the terms of the GNU GPL v2.0 + */ + +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +static char *escape(const char* text, char *bf, int len) +{ + char *bfp = bf; + int multiline = strchr(text, '\n') != NULL; + int eol = 0; + int textlen = strlen(text); + + if ((textlen > 0) && (text[textlen-1] == '\n')) + eol = 1; + + *bfp++ = '"'; + --len; + + if (multiline) { + *bfp++ = '"'; + *bfp++ = '\n'; + *bfp++ = '"'; + len -= 3; + } + + while (*text != '\0' && len > 1) { + if (*text == '"') + *bfp++ = '\\'; + else if (*text == '\n') { + *bfp++ = '\\'; + *bfp++ = 'n'; + *bfp++ = '"'; + *bfp++ = '\n'; + *bfp++ = '"'; + len -= 5; + ++text; + goto next; + } + else if (*text == '\\') { + *bfp++ = '\\'; + len--; + } + *bfp++ = *text++; +next: + --len; + } + + if (multiline && eol) + bfp -= 3; + + *bfp++ = '"'; + *bfp = '\0'; + + return bf; +} + +struct file_line { + struct file_line *next; + const char *file; + int lineno; +}; + +static struct file_line *file_line__new(const char *file, int lineno) +{ + struct file_line *self = malloc(sizeof(*self)); + + if (self == NULL) + goto out; + + self->file = file; + self->lineno = lineno; + self->next = NULL; +out: + return self; +} + +struct message { + const char *msg; + const char *option; + struct message *next; + struct file_line *files; +}; + +static struct message *message__list; + +static struct message *message__new(const char *msg, char *option, + const char *file, int lineno) +{ + struct message *self = malloc(sizeof(*self)); + + if (self == NULL) + goto out; + + self->files = file_line__new(file, lineno); + if (self->files == NULL) + goto out_fail; + + self->msg = strdup(msg); + if (self->msg == NULL) + goto out_fail_msg; + + self->option = option; + self->next = NULL; +out: + return self; +out_fail_msg: + free(self->files); +out_fail: + free(self); + self = NULL; + goto out; +} + +static struct message *mesage__find(const char *msg) +{ + struct message *m = message__list; + + while (m != NULL) { + if (strcmp(m->msg, msg) == 0) + break; + m = m->next; + } + + return m; +} + +static int message__add_file_line(struct message *self, const char *file, + int lineno) +{ + int rc = -1; + struct file_line *fl = file_line__new(file, lineno); + + if (fl == NULL) + goto out; + + fl->next = self->files; + self->files = fl; + rc = 0; +out: + return rc; +} + +static int message__add(const char *msg, char *option, const char *file, + int lineno) +{ + int rc = 0; + char bf[16384]; + char *escaped = escape(msg, bf, sizeof(bf)); + struct message *m = mesage__find(escaped); + + if (m != NULL) + rc = message__add_file_line(m, file, lineno); + else { + m = message__new(escaped, option, file, lineno); + + if (m != NULL) { + m->next = message__list; + message__list = m; + } else + rc = -1; + } + return rc; +} + +static void menu_build_message_list(struct menu *menu) +{ + struct menu *child; + + message__add(menu_get_prompt(menu), NULL, + menu->file == NULL ? "Root Menu" : menu->file->name, + menu->lineno); + + if (menu->sym != NULL && menu_has_help(menu)) + message__add(menu_get_help(menu), menu->sym->name, + menu->file == NULL ? "Root Menu" : menu->file->name, + menu->lineno); + + for (child = menu->list; child != NULL; child = child->next) + if (child->prompt != NULL) + menu_build_message_list(child); +} + +static void message__print_file_lineno(struct message *self) +{ + struct file_line *fl = self->files; + + putchar('\n'); + if (self->option != NULL) + printf("# %s:00000\n", self->option); + + printf("#: %s:%d", fl->file, fl->lineno); + fl = fl->next; + + while (fl != NULL) { + printf(", %s:%d", fl->file, fl->lineno); + fl = fl->next; + } + + putchar('\n'); +} + +static void message__print_gettext_msgid_msgstr(struct message *self) +{ + message__print_file_lineno(self); + + printf("msgid %s\n" + "msgstr \"\"\n", self->msg); +} + +static void menu__xgettext(void) +{ + struct message *m = message__list; + + while (m != NULL) { + /* skip empty lines ("") */ + if (strlen(m->msg) > sizeof("\"\"")) + message__print_gettext_msgid_msgstr(m); + m = m->next; + } +} + +int main(int ac, char **av) +{ + conf_parse(av[1]); + + menu_build_message_list(menu_get_root_menu(NULL)); + menu__xgettext(); + return 0; +} diff --git a/bios/seabios/tools/kconfig/lex.zconf.c_shipped b/bios/seabios/tools/kconfig/lex.zconf.c_shipped new file mode 100644 index 0000000..6eb0397 --- /dev/null +++ b/bios/seabios/tools/kconfig/lex.zconf.c_shipped @@ -0,0 +1,2430 @@ + +#line 3 "scripts/kconfig/lex.zconf.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define yy_create_buffer zconf_create_buffer +#define yy_delete_buffer zconf_delete_buffer +#define yy_flex_debug zconf_flex_debug +#define yy_init_buffer zconf_init_buffer +#define yy_flush_buffer zconf_flush_buffer +#define yy_load_buffer_state zconf_load_buffer_state +#define yy_switch_to_buffer zconf_switch_to_buffer +#define yyin zconfin +#define yyleng zconfleng +#define yylex zconflex +#define yylineno zconflineno +#define yyout zconfout +#define yyrestart zconfrestart +#define yytext zconftext +#define yywrap zconfwrap +#define yyalloc zconfalloc +#define yyrealloc zconfrealloc +#define yyfree zconffree + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE zconfrestart(zconfin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +extern int zconfleng; + +extern FILE *zconfin, *zconfout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up zconftext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up zconftext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, (yytext_ptr) ) + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via zconfrestart()), so that the user can continue scanning by + * just pointing zconfin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when zconftext is formed. */ +static char yy_hold_char; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int zconfleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow zconfwrap()'s to do buffer switches + * instead of setting up a fresh zconfin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void zconfrestart (FILE *input_file ); +void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE zconf_create_buffer (FILE *file,int size ); +void zconf_delete_buffer (YY_BUFFER_STATE b ); +void zconf_flush_buffer (YY_BUFFER_STATE b ); +void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer ); +void zconfpop_buffer_state (void ); + +static void zconfensure_buffer_stack (void ); +static void zconf_load_buffer_state (void ); +static void zconf_init_buffer (YY_BUFFER_STATE b,FILE *file ); + +#define YY_FLUSH_BUFFER zconf_flush_buffer(YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE zconf_scan_buffer (char *base,yy_size_t size ); +YY_BUFFER_STATE zconf_scan_string (yyconst char *yy_str ); +YY_BUFFER_STATE zconf_scan_bytes (yyconst char *bytes,int len ); + +void *zconfalloc (yy_size_t ); +void *zconfrealloc (void *,yy_size_t ); +void zconffree (void * ); + +#define yy_new_buffer zconf_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + zconfensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + zconf_create_buffer(zconfin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + zconfensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + zconf_create_buffer(zconfin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define zconfwrap(n) 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +FILE *zconfin = (FILE *) 0, *zconfout = (FILE *) 0; + +typedef int yy_state_type; + +extern int zconflineno; + +int zconflineno = 1; + +extern char *zconftext; +#define yytext_ptr zconftext +static yyconst flex_int16_t yy_nxt[][17] = + { + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 + }, + + { + 11, 12, 13, 14, 12, 12, 15, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12 + }, + + { + 11, 12, 13, 14, 12, 12, 15, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12 + }, + + { + 11, 16, 16, 17, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 18, 16, 16, 16 + }, + + { + 11, 16, 16, 17, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 18, 16, 16, 16 + + }, + + { + 11, 19, 20, 21, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19 + }, + + { + 11, 19, 20, 21, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19 + }, + + { + 11, 22, 22, 23, 22, 24, 22, 22, 24, 22, + 22, 22, 22, 22, 22, 25, 22 + }, + + { + 11, 22, 22, 23, 22, 24, 22, 22, 24, 22, + 22, 22, 22, 22, 22, 25, 22 + }, + + { + 11, 26, 26, 27, 28, 29, 30, 31, 29, 32, + 33, 34, 35, 35, 36, 37, 38 + + }, + + { + 11, 26, 26, 27, 28, 29, 30, 31, 29, 32, + 33, 34, 35, 35, 36, 37, 38 + }, + + { + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11 + }, + + { + 11, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12 + }, + + { + 11, -13, 39, 40, -13, -13, 41, -13, -13, -13, + -13, -13, -13, -13, -13, -13, -13 + }, + + { + 11, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14 + + }, + + { + 11, 42, 42, 43, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42 + }, + + { + 11, -16, -16, -16, -16, -16, -16, -16, -16, -16, + -16, -16, -16, -16, -16, -16, -16 + }, + + { + 11, -17, -17, -17, -17, -17, -17, -17, -17, -17, + -17, -17, -17, -17, -17, -17, -17 + }, + + { + 11, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, 44, -18, -18, -18 + }, + + { + 11, 45, 45, -19, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45 + + }, + + { + 11, -20, 46, 47, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20 + }, + + { + 11, 48, -21, -21, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48 + }, + + { + 11, 49, 49, 50, 49, -22, 49, 49, -22, 49, + 49, 49, 49, 49, 49, -22, 49 + }, + + { + 11, -23, -23, -23, -23, -23, -23, -23, -23, -23, + -23, -23, -23, -23, -23, -23, -23 + }, + + { + 11, -24, -24, -24, -24, -24, -24, -24, -24, -24, + -24, -24, -24, -24, -24, -24, -24 + + }, + + { + 11, 51, 51, 52, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51 + }, + + { + 11, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26, -26 + }, + + { + 11, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27 + }, + + { + 11, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, 53, -28, -28 + }, + + { + 11, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29 + + }, + + { + 11, 54, 54, -30, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54 + }, + + { + 11, -31, -31, -31, -31, -31, -31, 55, -31, -31, + -31, -31, -31, -31, -31, -31, -31 + }, + + { + 11, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32 + }, + + { + 11, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33 + }, + + { + 11, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, 56, 57, 57, -34, -34, -34 + + }, + + { + 11, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, 57, 57, 57, -35, -35, -35 + }, + + { + 11, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36 + }, + + { + 11, -37, -37, 58, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37 + }, + + { + 11, -38, -38, -38, -38, -38, -38, -38, -38, -38, + -38, -38, -38, -38, -38, -38, 59 + }, + + { + 11, -39, 39, 40, -39, -39, 41, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39 + + }, + + { + 11, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40 + }, + + { + 11, 42, 42, 43, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42 + }, + + { + 11, 42, 42, 43, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42 + }, + + { + 11, -43, -43, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43, -43 + }, + + { + 11, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, 44, -44, -44, -44 + + }, + + { + 11, 45, 45, -45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45 + }, + + { + 11, -46, 46, 47, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46, -46 + }, + + { + 11, 48, -47, -47, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48 + }, + + { + 11, -48, -48, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -48, -48 + }, + + { + 11, 49, 49, 50, 49, -49, 49, 49, -49, 49, + 49, 49, 49, 49, 49, -49, 49 + + }, + + { + 11, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50 + }, + + { + 11, -51, -51, 52, -51, -51, -51, -51, -51, -51, + -51, -51, -51, -51, -51, -51, -51 + }, + + { + 11, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52 + }, + + { + 11, -53, -53, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53 + }, + + { + 11, 54, 54, -54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54 + + }, + + { + 11, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55 + }, + + { + 11, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, 60, 57, 57, -56, -56, -56 + }, + + { + 11, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, 57, 57, 57, -57, -57, -57 + }, + + { + 11, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58 + }, + + { + 11, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59 + + }, + + { + 11, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, 57, 57, 57, -60, -60, -60 + }, + + } ; + +static yy_state_type yy_get_previous_state (void ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); +static int yy_get_next_buffer (void ); +static void yy_fatal_error (yyconst char msg[] ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up zconftext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + zconfleng = (size_t) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; + +#define YY_NUM_RULES 33 +#define YY_END_OF_BUFFER 34 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[61] = + { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 34, 5, 4, 2, 3, 7, 8, 6, 32, 29, + 31, 24, 28, 27, 26, 22, 17, 13, 16, 20, + 22, 11, 12, 19, 19, 14, 22, 22, 4, 2, + 3, 3, 1, 6, 32, 29, 31, 30, 24, 23, + 26, 25, 15, 20, 9, 19, 19, 21, 10, 18 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 4, 5, 6, 1, 1, 7, 8, 9, + 10, 1, 1, 1, 11, 12, 12, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 1, 1, 1, + 14, 1, 1, 1, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 1, 15, 1, 1, 13, 1, 13, 13, 13, 13, + + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 1, 16, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +extern int zconf_flex_debug; +int zconf_flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *zconftext; +#define YY_NO_INPUT 1 + +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +#define START_STRSIZE 16 + +static struct { + struct file *file; + int lineno; +} current_pos; + +static char *text; +static int text_size, text_asize; + +struct buffer { + struct buffer *parent; + YY_BUFFER_STATE state; +}; + +struct buffer *current_buf; + +static int last_ts, first_ts; + +static void zconf_endhelp(void); +static void zconf_endfile(void); + +static void new_string(void) +{ + text = malloc(START_STRSIZE); + text_asize = START_STRSIZE; + text_size = 0; + *text = 0; +} + +static void append_string(const char *str, int size) +{ + int new_size = text_size + size + 1; + if (new_size > text_asize) { + new_size += START_STRSIZE - 1; + new_size &= -START_STRSIZE; + text = realloc(text, new_size); + text_asize = new_size; + } + memcpy(text + text_size, str, size); + text_size += size; + text[text_size] = 0; +} + +static void alloc_string(const char *str, int size) +{ + text = malloc(size + 1); + memcpy(text, str, size); + text[size] = 0; +} + +#define INITIAL 0 +#define COMMAND 1 +#define HELP 2 +#define STRING 3 +#define PARAM 4 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals (void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int zconflex_destroy (void ); + +int zconfget_debug (void ); + +void zconfset_debug (int debug_flag ); + +YY_EXTRA_TYPE zconfget_extra (void ); + +void zconfset_extra (YY_EXTRA_TYPE user_defined ); + +FILE *zconfget_in (void ); + +void zconfset_in (FILE * in_str ); + +FILE *zconfget_out (void ); + +void zconfset_out (FILE * out_str ); + +int zconfget_leng (void ); + +char *zconfget_text (void ); + +int zconfget_lineno (void ); + +void zconfset_lineno (int line_number ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int zconfwrap (void ); +#else +extern int zconfwrap (void ); +#endif +#endif + + static void yyunput (int c,char *buf_ptr ); + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (void ); +#else +static int input (void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( zconftext, zconfleng, 1, zconfout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + errno=0; \ + while ( (result = read( fileno(zconfin), (char *) buf, max_size )) < 0 ) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(zconfin); \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int zconflex (void); + +#define YY_DECL int zconflex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after zconftext and zconfleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + + int str = 0; + int ts, i; + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! zconfin ) + zconfin = stdin; + + if ( ! zconfout ) + zconfout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + zconfensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + zconf_create_buffer(zconfin,YY_BUF_SIZE ); + } + + zconf_load_buffer_state( ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of zconftext. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); +yy_match: + while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)] ]) > 0 ) + ++yy_cp; + + yy_current_state = -yy_current_state; + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ +case 1: +/* rule 1 can match eol */ +case 2: +/* rule 2 can match eol */ +YY_RULE_SETUP +{ + current_file->lineno++; + return T_EOL; +} + YY_BREAK +case 3: +YY_RULE_SETUP + + YY_BREAK +case 4: +YY_RULE_SETUP +{ + BEGIN(COMMAND); +} + YY_BREAK +case 5: +YY_RULE_SETUP +{ + unput(zconftext[0]); + BEGIN(COMMAND); +} + YY_BREAK + +case 6: +YY_RULE_SETUP +{ + struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng); + BEGIN(PARAM); + current_pos.file = current_file; + current_pos.lineno = current_file->lineno; + if (id && id->flags & TF_COMMAND) { + zconflval.id = id; + return id->token; + } + alloc_string(zconftext, zconfleng); + zconflval.string = text; + return T_WORD; + } + YY_BREAK +case 7: +YY_RULE_SETUP + + YY_BREAK +case 8: +/* rule 8 can match eol */ +YY_RULE_SETUP +{ + BEGIN(INITIAL); + current_file->lineno++; + return T_EOL; + } + YY_BREAK + +case 9: +YY_RULE_SETUP +return T_AND; + YY_BREAK +case 10: +YY_RULE_SETUP +return T_OR; + YY_BREAK +case 11: +YY_RULE_SETUP +return T_OPEN_PAREN; + YY_BREAK +case 12: +YY_RULE_SETUP +return T_CLOSE_PAREN; + YY_BREAK +case 13: +YY_RULE_SETUP +return T_NOT; + YY_BREAK +case 14: +YY_RULE_SETUP +return T_EQUAL; + YY_BREAK +case 15: +YY_RULE_SETUP +return T_UNEQUAL; + YY_BREAK +case 16: +YY_RULE_SETUP +{ + str = zconftext[0]; + new_string(); + BEGIN(STRING); + } + YY_BREAK +case 17: +/* rule 17 can match eol */ +YY_RULE_SETUP +BEGIN(INITIAL); current_file->lineno++; return T_EOL; + YY_BREAK +case 18: +YY_RULE_SETUP +/* ignore */ + YY_BREAK +case 19: +YY_RULE_SETUP +{ + struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng); + if (id && id->flags & TF_PARAM) { + zconflval.id = id; + return id->token; + } + alloc_string(zconftext, zconfleng); + zconflval.string = text; + return T_WORD; + } + YY_BREAK +case 20: +YY_RULE_SETUP +/* comment */ + YY_BREAK +case 21: +/* rule 21 can match eol */ +YY_RULE_SETUP +current_file->lineno++; + YY_BREAK +case 22: +YY_RULE_SETUP + + YY_BREAK +case YY_STATE_EOF(PARAM): +{ + BEGIN(INITIAL); + } + YY_BREAK + +case 23: +/* rule 23 can match eol */ +*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ +(yy_c_buf_p) = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up zconftext again */ +YY_RULE_SETUP +{ + append_string(zconftext, zconfleng); + zconflval.string = text; + return T_WORD_QUOTE; + } + YY_BREAK +case 24: +YY_RULE_SETUP +{ + append_string(zconftext, zconfleng); + } + YY_BREAK +case 25: +/* rule 25 can match eol */ +*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ +(yy_c_buf_p) = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up zconftext again */ +YY_RULE_SETUP +{ + append_string(zconftext + 1, zconfleng - 1); + zconflval.string = text; + return T_WORD_QUOTE; + } + YY_BREAK +case 26: +YY_RULE_SETUP +{ + append_string(zconftext + 1, zconfleng - 1); + } + YY_BREAK +case 27: +YY_RULE_SETUP +{ + if (str == zconftext[0]) { + BEGIN(PARAM); + zconflval.string = text; + return T_WORD_QUOTE; + } else + append_string(zconftext, 1); + } + YY_BREAK +case 28: +/* rule 28 can match eol */ +YY_RULE_SETUP +{ + printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno()); + current_file->lineno++; + BEGIN(INITIAL); + return T_EOL; + } + YY_BREAK +case YY_STATE_EOF(STRING): +{ + BEGIN(INITIAL); + } + YY_BREAK + +case 29: +YY_RULE_SETUP +{ + ts = 0; + for (i = 0; i < zconfleng; i++) { + if (zconftext[i] == '\t') + ts = (ts & ~7) + 8; + else + ts++; + } + last_ts = ts; + if (first_ts) { + if (ts < first_ts) { + zconf_endhelp(); + return T_HELPTEXT; + } + ts -= first_ts; + while (ts > 8) { + append_string(" ", 8); + ts -= 8; + } + append_string(" ", ts); + } + } + YY_BREAK +case 30: +/* rule 30 can match eol */ +*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ +(yy_c_buf_p) = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up zconftext again */ +YY_RULE_SETUP +{ + current_file->lineno++; + zconf_endhelp(); + return T_HELPTEXT; + } + YY_BREAK +case 31: +/* rule 31 can match eol */ +YY_RULE_SETUP +{ + current_file->lineno++; + append_string("\n", 1); + } + YY_BREAK +case 32: +YY_RULE_SETUP +{ + while (zconfleng) { + if ((zconftext[zconfleng-1] != ' ') && (zconftext[zconfleng-1] != '\t')) + break; + zconfleng--; + } + append_string(zconftext, zconfleng); + if (!first_ts) + first_ts = last_ts; + } + YY_BREAK +case YY_STATE_EOF(HELP): +{ + zconf_endhelp(); + return T_HELPTEXT; + } + YY_BREAK + +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(COMMAND): +{ + if (current_file) { + zconf_endfile(); + return T_EOL; + } + fclose(zconfin); + yyterminate(); +} + YY_BREAK +case 33: +YY_RULE_SETUP +YY_FATAL_ERROR( "flex scanner jammed" ); + YY_BREAK + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed zconfin at a new source and called + * zconflex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = zconfin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_c_buf_p); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( zconfwrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * zconftext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of zconflex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = (yytext_ptr); + register int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + zconfrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), (size_t) num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + zconfrestart(zconfin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) zconfrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = (yy_start); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + register int yy_is_jam; + + yy_current_state = yy_nxt[yy_current_state][1]; + yy_is_jam = (yy_current_state <= 0); + + return yy_is_jam ? 0 : yy_current_state; +} + + static void yyunput (int c, register char * yy_bp ) +{ + register char *yy_cp; + + yy_cp = (yy_c_buf_p); + + /* undo effects of setting up zconftext */ + *yy_cp = (yy_hold_char); + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = (yy_n_chars) + 2; + register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + register char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + (yytext_ptr) = yy_bp; + (yy_hold_char) = *yy_cp; + (yy_c_buf_p) = yy_cp; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + int offset = (yy_c_buf_p) - (yytext_ptr); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + zconfrestart(zconfin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( zconfwrap( ) ) + return EOF; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve zconftext */ + (yy_hold_char) = *++(yy_c_buf_p); + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void zconfrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + zconfensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + zconf_create_buffer(zconfin,YY_BUF_SIZE ); + } + + zconf_init_buffer(YY_CURRENT_BUFFER,input_file ); + zconf_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * zconfpop_buffer_state(); + * zconfpush_buffer_state(new_buffer); + */ + zconfensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + zconf_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (zconfwrap()) processing, but the only time this flag + * is looked at is after zconfwrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void zconf_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + zconfin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE zconf_create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) zconfalloc(b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + zconf_init_buffer(b,file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with zconf_create_buffer() + * + */ + void zconf_delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + zconffree((void *) b->yy_ch_buf ); + + zconffree((void *) b ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a zconfrestart() or at EOF. + */ + static void zconf_init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + zconf_flush_buffer(b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then zconf_init_buffer was _probably_ + * called from zconfrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void zconf_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + zconf_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + zconfensure_buffer_stack(); + + /* This block is copied from zconf_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from zconf_switch_to_buffer. */ + zconf_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void zconfpop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + zconf_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + zconf_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void zconfensure_buffer_stack (void) +{ + int num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + (yy_buffer_stack) = (struct yy_buffer_state**)zconfalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)zconfrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE zconf_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + zconf_switch_to_buffer(b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to zconflex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * zconf_scan_bytes() instead. + */ +YY_BUFFER_STATE zconf_scan_string (yyconst char * yystr ) +{ + + return zconf_scan_bytes(yystr,strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to zconflex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE zconf_scan_bytes (yyconst char * yybytes, int _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) zconfalloc(n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = zconf_scan_buffer(buf,n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in zconf_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg ) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up zconftext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + zconftext[zconfleng] = (yy_hold_char); \ + (yy_c_buf_p) = zconftext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + zconfleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int zconfget_lineno (void) +{ + + return zconflineno; +} + +/** Get the input stream. + * + */ +FILE *zconfget_in (void) +{ + return zconfin; +} + +/** Get the output stream. + * + */ +FILE *zconfget_out (void) +{ + return zconfout; +} + +/** Get the length of the current token. + * + */ +int zconfget_leng (void) +{ + return zconfleng; +} + +/** Get the current token. + * + */ + +char *zconfget_text (void) +{ + return zconftext; +} + +/** Set the current line number. + * @param line_number + * + */ +void zconfset_lineno (int line_number ) +{ + + zconflineno = line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * + * @see zconf_switch_to_buffer + */ +void zconfset_in (FILE * in_str ) +{ + zconfin = in_str ; +} + +void zconfset_out (FILE * out_str ) +{ + zconfout = out_str ; +} + +int zconfget_debug (void) +{ + return zconf_flex_debug; +} + +void zconfset_debug (int bdebug ) +{ + zconf_flex_debug = bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from zconflex_destroy(), so don't allocate here. + */ + + (yy_buffer_stack) = 0; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = (char *) 0; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + zconfin = stdin; + zconfout = stdout; +#else + zconfin = (FILE *) 0; + zconfout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * zconflex_init() + */ + return 0; +} + +/* zconflex_destroy is for both reentrant and non-reentrant scanners. */ +int zconflex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + zconf_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + zconfpop_buffer_state(); + } + + /* Destroy the stack itself. */ + zconffree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * zconflex() is called, initialization will occur. */ + yy_init_globals( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s ) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *zconfalloc (yy_size_t size ) +{ + return (void *) malloc( size ); +} + +void *zconfrealloc (void * ptr, yy_size_t size ) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void zconffree (void * ptr ) +{ + free( (char *) ptr ); /* see zconfrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +void zconf_starthelp(void) +{ + new_string(); + last_ts = first_ts = 0; + BEGIN(HELP); +} + +static void zconf_endhelp(void) +{ + zconflval.string = text; + BEGIN(INITIAL); +} + +/* + * Try to open specified file with following names: + * ./name + * $(srctree)/name + * The latter is used when srctree is separate from objtree + * when compiling the kernel. + * Return NULL if file is not found. + */ +FILE *zconf_fopen(const char *name) +{ + char *env, fullname[PATH_MAX+1]; + FILE *f; + + f = fopen(name, "r"); + if (!f && name != NULL && name[0] != '/') { + env = getenv(SRCTREE); + if (env) { + sprintf(fullname, "%s/%s", env, name); + f = fopen(fullname, "r"); + } + } + return f; +} + +void zconf_initscan(const char *name) +{ + zconfin = zconf_fopen(name); + if (!zconfin) { + printf("can't find file %s\n", name); + exit(1); + } + + current_buf = malloc(sizeof(*current_buf)); + memset(current_buf, 0, sizeof(*current_buf)); + + current_file = file_lookup(name); + current_file->lineno = 1; + current_file->flags = FILE_BUSY; +} + +void zconf_nextfile(const char *name) +{ + struct file *file = file_lookup(name); + struct buffer *buf = malloc(sizeof(*buf)); + memset(buf, 0, sizeof(*buf)); + + current_buf->state = YY_CURRENT_BUFFER; + zconfin = zconf_fopen(file->name); + if (!zconfin) { + printf("%s:%d: can't open file \"%s\"\n", + zconf_curname(), zconf_lineno(), file->name); + exit(1); + } + zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE)); + buf->parent = current_buf; + current_buf = buf; + + if (file->flags & FILE_BUSY) { + printf("%s:%d: do not source '%s' from itself\n", + zconf_curname(), zconf_lineno(), name); + exit(1); + } + if (file->flags & FILE_SCANNED) { + printf("%s:%d: file '%s' is already sourced from '%s'\n", + zconf_curname(), zconf_lineno(), name, + file->parent->name); + exit(1); + } + file->flags |= FILE_BUSY; + file->lineno = 1; + file->parent = current_file; + current_file = file; +} + +static void zconf_endfile(void) +{ + struct buffer *parent; + + current_file->flags |= FILE_SCANNED; + current_file->flags &= ~FILE_BUSY; + current_file = current_file->parent; + + parent = current_buf->parent; + if (parent) { + fclose(zconfin); + zconf_delete_buffer(YY_CURRENT_BUFFER); + zconf_switch_to_buffer(parent->state); + } + free(current_buf); + current_buf = parent; +} + +int zconf_lineno(void) +{ + return current_pos.lineno; +} + +const char *zconf_curname(void) +{ + return current_pos.file ? current_pos.file->name : ""; +} + diff --git a/bios/seabios/tools/kconfig/lkc.h b/bios/seabios/tools/kconfig/lkc.h new file mode 100644 index 0000000..febf0c9 --- /dev/null +++ b/bios/seabios/tools/kconfig/lkc.h @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#ifndef LKC_H +#define LKC_H + +#include "expr.h" + +#ifndef KBUILD_NO_NLS +# include +#else +static inline const char *gettext(const char *txt) { return txt; } +static inline void textdomain(const char *domainname) {} +static inline void bindtextdomain(const char *name, const char *dir) {} +static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; } +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef LKC_DIRECT_LINK +#define P(name,type,arg) extern type name arg +#else +#include "lkc_defs.h" +#define P(name,type,arg) extern type (*name ## _p) arg +#endif +#include "lkc_proto.h" +#undef P + +#define SRCTREE "srctree" + +#ifndef PACKAGE +#define PACKAGE "linux" +#endif + +#define LOCALEDIR "/usr/share/locale" + +#define _(text) gettext(text) +#define N_(text) (text) + +#ifndef CONFIG_ +#define CONFIG_ "CONFIG_" +#endif + +#define TF_COMMAND 0x0001 +#define TF_PARAM 0x0002 +#define TF_OPTION 0x0004 + +enum conf_def_mode { + def_default, + def_yes, + def_mod, + def_no, + def_random +}; + +#define T_OPT_MODULES 1 +#define T_OPT_DEFCONFIG_LIST 2 +#define T_OPT_ENV 3 + +struct kconf_id { + int name; + int token; + unsigned int flags; + enum symbol_type stype; +}; + +#ifdef YYDEBUG +extern int zconfdebug; +#endif + +int zconfparse(void); +void zconfdump(FILE *out); +void zconf_starthelp(void); +FILE *zconf_fopen(const char *name); +void zconf_initscan(const char *name); +void zconf_nextfile(const char *name); +int zconf_lineno(void); +const char *zconf_curname(void); + +/* conf.c */ +void xfgets(char *str, int size, FILE *in); + +/* confdata.c */ +const char *conf_get_configname(void); +const char *conf_get_autoconfig_name(void); +char *conf_get_default_confname(void); +void sym_set_change_count(int count); +void sym_add_change_count(int count); +void conf_set_all_new_symbols(enum conf_def_mode mode); + +/* confdata.c and expr.c */ +static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out) +{ + if (fwrite(str, len, count, out) < count) + fprintf(stderr, "\nError in writing or end of file.\n"); +} + +/* kconfig_load.c */ +void kconfig_load(void); + +/* menu.c */ +void _menu_init(void); +void menu_warn(struct menu *menu, const char *fmt, ...); +struct menu *menu_add_menu(void); +void menu_end_menu(void); +void menu_add_entry(struct symbol *sym); +void menu_end_entry(void); +void menu_add_dep(struct expr *dep); +void menu_add_visibility(struct expr *dep); +struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep); +struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep); +void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); +void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep); +void menu_add_option(int token, char *arg); +void menu_finalize(struct menu *parent); +void menu_set_type(int type); + +/* util.c */ +struct file *file_lookup(const char *name); +int file_write_dep(const char *name); + +struct gstr { + size_t len; + char *s; + /* + * when max_width is not zero long lines in string s (if any) get + * wrapped not to exceed the max_width value + */ + int max_width; +}; +struct gstr str_new(void); +struct gstr str_assign(const char *s); +void str_free(struct gstr *gs); +void str_append(struct gstr *gs, const char *s); +void str_printf(struct gstr *gs, const char *fmt, ...); +const char *str_get(struct gstr *gs); + +/* symbol.c */ +extern struct expr *sym_env_list; + +void sym_init(void); +void sym_clear_all_valid(void); +void sym_set_all_changed(void); +void sym_set_changed(struct symbol *sym); +struct symbol *sym_choice_default(struct symbol *sym); +const char *sym_get_string_default(struct symbol *sym); +struct symbol *sym_check_deps(struct symbol *sym); +struct property *prop_alloc(enum prop_type type, struct symbol *sym); +struct symbol *prop_get_symbol(struct property *prop); +struct property *sym_get_env_prop(struct symbol *sym); + +static inline tristate sym_get_tristate_value(struct symbol *sym) +{ + return sym->curr.tri; +} + + +static inline struct symbol *sym_get_choice_value(struct symbol *sym) +{ + return (struct symbol *)sym->curr.val; +} + +static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval) +{ + return sym_set_tristate_value(chval, yes); +} + +static inline bool sym_is_choice(struct symbol *sym) +{ + return sym->flags & SYMBOL_CHOICE ? true : false; +} + +static inline bool sym_is_choice_value(struct symbol *sym) +{ + return sym->flags & SYMBOL_CHOICEVAL ? true : false; +} + +static inline bool sym_is_optional(struct symbol *sym) +{ + return sym->flags & SYMBOL_OPTIONAL ? true : false; +} + +static inline bool sym_has_value(struct symbol *sym) +{ + return sym->flags & SYMBOL_DEF_USER ? true : false; +} + +#ifdef __cplusplus +} +#endif + +#endif /* LKC_H */ diff --git a/bios/seabios/tools/kconfig/lkc_proto.h b/bios/seabios/tools/kconfig/lkc_proto.h new file mode 100644 index 0000000..17342fe --- /dev/null +++ b/bios/seabios/tools/kconfig/lkc_proto.h @@ -0,0 +1,53 @@ +#include + +/* confdata.c */ +P(conf_parse,void,(const char *name)); +P(conf_read,int,(const char *name)); +P(conf_read_simple,int,(const char *name, int)); +P(conf_write_defconfig,int,(const char *name)); +P(conf_write,int,(const char *name)); +P(conf_write_autoconf,int,(void)); +P(conf_get_changed,bool,(void)); +P(conf_set_changed_callback, void,(void (*fn)(void))); +P(conf_set_message_callback, void,(void (*fn)(const char *fmt, va_list ap))); + +/* menu.c */ +P(rootmenu,struct menu,); + +P(menu_is_visible, bool, (struct menu *menu)); +P(menu_has_prompt, bool, (struct menu *menu)); +P(menu_get_prompt,const char *,(struct menu *menu)); +P(menu_get_root_menu,struct menu *,(struct menu *menu)); +P(menu_get_parent_menu,struct menu *,(struct menu *menu)); +P(menu_has_help,bool,(struct menu *menu)); +P(menu_get_help,const char *,(struct menu *menu)); +P(get_symbol_str, void, (struct gstr *r, struct symbol *sym)); +P(get_relations_str, struct gstr, (struct symbol **sym_arr)); +P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help)); + +/* symbol.c */ +P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]); + +P(sym_lookup,struct symbol *,(const char *name, int flags)); +P(sym_find,struct symbol *,(const char *name)); +P(sym_expand_string_value,const char *,(const char *in)); +P(sym_re_search,struct symbol **,(const char *pattern)); +P(sym_type_name,const char *,(enum symbol_type type)); +P(sym_calc_value,void,(struct symbol *sym)); +P(sym_get_type,enum symbol_type,(struct symbol *sym)); +P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri)); +P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri)); +P(sym_toggle_tristate_value,tristate,(struct symbol *sym)); +P(sym_string_valid,bool,(struct symbol *sym, const char *newval)); +P(sym_string_within_range,bool,(struct symbol *sym, const char *str)); +P(sym_set_string_value,bool,(struct symbol *sym, const char *newval)); +P(sym_is_changable,bool,(struct symbol *sym)); +P(sym_get_choice_prop,struct property *,(struct symbol *sym)); +P(sym_get_default_prop,struct property *,(struct symbol *sym)); +P(sym_get_string_value,const char *,(struct symbol *sym)); + +P(prop_get_type_name,const char *,(enum prop_type type)); + +/* expr.c */ +P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2)); +P(expr_print,void,(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)); diff --git a/bios/seabios/tools/kconfig/lxdialog/.gitignore b/bios/seabios/tools/kconfig/lxdialog/.gitignore new file mode 100644 index 0000000..90b08ff --- /dev/null +++ b/bios/seabios/tools/kconfig/lxdialog/.gitignore @@ -0,0 +1,4 @@ +# +# Generated files +# +lxdialog diff --git a/bios/seabios/tools/kconfig/lxdialog/BIG.FAT.WARNING b/bios/seabios/tools/kconfig/lxdialog/BIG.FAT.WARNING new file mode 100644 index 0000000..a8999d8 --- /dev/null +++ b/bios/seabios/tools/kconfig/lxdialog/BIG.FAT.WARNING @@ -0,0 +1,4 @@ +This is NOT the official version of dialog. This version has been +significantly modified from the original. It is for use by the Linux +kernel configuration script. Please do not bother Savio Lam with +questions about this program. diff --git a/bios/seabios/tools/kconfig/lxdialog/check-lxdialog.sh b/bios/seabios/tools/kconfig/lxdialog/check-lxdialog.sh new file mode 100644 index 0000000..82cc3a8 --- /dev/null +++ b/bios/seabios/tools/kconfig/lxdialog/check-lxdialog.sh @@ -0,0 +1,84 @@ +#!/bin/sh +# Check ncurses compatibility + +# What library to link +ldflags() +{ + for ext in so a dylib ; do + for lib in ncursesw ncurses curses ; do + $cc -print-file-name=lib${lib}.${ext} | grep -q / + if [ $? -eq 0 ]; then + echo "-l${lib}" + exit + fi + done + done + exit 1 +} + +# Where is ncurses.h? +ccflags() +{ + if [ -f /usr/include/ncurses/ncurses.h ]; then + echo '-I/usr/include/ncurses -DCURSES_LOC=""' + elif [ -f /usr/include/ncurses/curses.h ]; then + echo '-I/usr/include/ncurses -DCURSES_LOC=""' + elif [ -f /usr/include/ncursesw/curses.h ]; then + echo '-I/usr/include/ncursesw -DCURSES_LOC=""' + elif [ -f /usr/include/ncurses.h ]; then + echo '-DCURSES_LOC=""' + else + echo '-DCURSES_LOC=""' + fi +} + +# Temp file, try to clean up after us +tmp=.lxdialog.tmp +trap "rm -f $tmp" 0 1 2 3 15 + +# Check if we can link to ncurses +check() { + $cc -xc - -o $tmp 2>/dev/null <<'EOF' +#include CURSES_LOC +main() {} +EOF + if [ $? != 0 ]; then + echo " *** Unable to find the ncurses libraries or the" 1>&2 + echo " *** required header files." 1>&2 + echo " *** 'make menuconfig' requires the ncurses libraries." 1>&2 + echo " *** " 1>&2 + echo " *** Install ncurses (ncurses-devel) and try again." 1>&2 + echo " *** " 1>&2 + exit 1 + fi +} + +usage() { + printf "Usage: $0 [-check compiler options|-ccflags|-ldflags compiler options]\n" +} + +if [ $# -eq 0 ]; then + usage + exit 1 +fi + +cc="" +case "$1" in + "-check") + shift + cc="$@" + check + ;; + "-ccflags") + ccflags + ;; + "-ldflags") + shift + cc="$@" + ldflags + ;; + "*") + usage + exit 1 + ;; +esac diff --git a/bios/seabios/tools/kconfig/lxdialog/checklist.c b/bios/seabios/tools/kconfig/lxdialog/checklist.c new file mode 100644 index 0000000..a2eb80f --- /dev/null +++ b/bios/seabios/tools/kconfig/lxdialog/checklist.c @@ -0,0 +1,332 @@ +/* + * checklist.c -- implements the checklist box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension + * Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "dialog.h" + +static int list_width, check_x, item_x; + +/* + * Print list item + */ +static void print_item(WINDOW * win, int choice, int selected) +{ + int i; + char *list_item = malloc(list_width + 1); + + strncpy(list_item, item_str(), list_width - item_x); + list_item[list_width - item_x] = '\0'; + + /* Clear 'residue' of last item */ + wattrset(win, dlg.menubox.atr); + wmove(win, choice, 0); + for (i = 0; i < list_width; i++) + waddch(win, ' '); + + wmove(win, choice, check_x); + wattrset(win, selected ? dlg.check_selected.atr + : dlg.check.atr); + if (!item_is_tag(':')) + wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' '); + + wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr); + mvwaddch(win, choice, item_x, list_item[0]); + wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr); + waddstr(win, list_item + 1); + if (selected) { + wmove(win, choice, check_x + 1); + wrefresh(win); + } + free(list_item); +} + +/* + * Print the scroll indicators. + */ +static void print_arrows(WINDOW * win, int choice, int item_no, int scroll, + int y, int x, int height) +{ + wmove(win, y, x); + + if (scroll > 0) { + wattrset(win, dlg.uarrow.atr); + waddch(win, ACS_UARROW); + waddstr(win, "(-)"); + } else { + wattrset(win, dlg.menubox.atr); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + } + + y = y + height + 1; + wmove(win, y, x); + + if ((height < item_no) && (scroll + choice < item_no - 1)) { + wattrset(win, dlg.darrow.atr); + waddch(win, ACS_DARROW); + waddstr(win, "(+)"); + } else { + wattrset(win, dlg.menubox_border.atr); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + } +} + +/* + * Display the termination buttons + */ +static void print_buttons(WINDOW * dialog, int height, int width, int selected) +{ + int x = width / 2 - 11; + int y = height - 2; + + print_button(dialog, gettext("Select"), y, x, selected == 0); + print_button(dialog, gettext(" Help "), y, x + 14, selected == 1); + + wmove(dialog, y, x + 1 + 14 * selected); + wrefresh(dialog); +} + +/* + * Display a dialog box with a list of options that can be turned on or off + * in the style of radiolist (only one option turned on at a time). + */ +int dialog_checklist(const char *title, const char *prompt, int height, + int width, int list_height) +{ + int i, x, y, box_x, box_y; + int key = 0, button = 0, choice = 0, scroll = 0, max_choice; + WINDOW *dialog, *list; + + /* which item to highlight */ + item_foreach() { + if (item_is_tag('X')) + choice = item_n(); + if (item_is_selected()) { + choice = item_n(); + break; + } + } + +do_resize: + if (getmaxy(stdscr) < (height + 6)) + return -ERRDISPLAYTOOSMALL; + if (getmaxx(stdscr) < (width + 6)) + return -ERRDISPLAYTOOSMALL; + + max_choice = MIN(list_height, item_count()); + + /* center dialog box on screen */ + x = (COLS - width) / 2; + y = (LINES - height) / 2; + + draw_shadow(stdscr, y, x, height, width); + + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + draw_box(dialog, 0, 0, height, width, + dlg.dialog.atr, dlg.border.atr); + wattrset(dialog, dlg.border.atr); + mvwaddch(dialog, height - 3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dlg.dialog.atr); + waddch(dialog, ACS_RTEE); + + print_title(dialog, title, width); + + wattrset(dialog, dlg.dialog.atr); + print_autowrap(dialog, prompt, width - 2, 1, 3); + + list_width = width - 6; + box_y = height - list_height - 5; + box_x = (width - list_width) / 2 - 1; + + /* create new window for the list */ + list = subwin(dialog, list_height, list_width, y + box_y + 1, + x + box_x + 1); + + keypad(list, TRUE); + + /* draw a box around the list items */ + draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2, + dlg.menubox_border.atr, dlg.menubox.atr); + + /* Find length of longest item in order to center checklist */ + check_x = 0; + item_foreach() + check_x = MAX(check_x, strlen(item_str()) + 4); + check_x = MIN(check_x, list_width); + + check_x = (list_width - check_x) / 2; + item_x = check_x + 4; + + if (choice >= list_height) { + scroll = choice - list_height + 1; + choice -= scroll; + } + + /* Print the list */ + for (i = 0; i < max_choice; i++) { + item_set(scroll + i); + print_item(list, i, i == choice); + } + + print_arrows(dialog, choice, item_count(), scroll, + box_y, box_x + check_x + 5, list_height); + + print_buttons(dialog, height, width, 0); + + wnoutrefresh(dialog); + wnoutrefresh(list); + doupdate(); + + while (key != KEY_ESC) { + key = wgetch(dialog); + + for (i = 0; i < max_choice; i++) { + item_set(i + scroll); + if (toupper(key) == toupper(item_str()[0])) + break; + } + + if (i < max_choice || key == KEY_UP || key == KEY_DOWN || + key == '+' || key == '-') { + if (key == KEY_UP || key == '-') { + if (!choice) { + if (!scroll) + continue; + /* Scroll list down */ + if (list_height > 1) { + /* De-highlight current first item */ + item_set(scroll); + print_item(list, 0, FALSE); + scrollok(list, TRUE); + wscrl(list, -1); + scrollok(list, FALSE); + } + scroll--; + item_set(scroll); + print_item(list, 0, TRUE); + print_arrows(dialog, choice, item_count(), + scroll, box_y, box_x + check_x + 5, list_height); + + wnoutrefresh(dialog); + wrefresh(list); + + continue; /* wait for another key press */ + } else + i = choice - 1; + } else if (key == KEY_DOWN || key == '+') { + if (choice == max_choice - 1) { + if (scroll + choice >= item_count() - 1) + continue; + /* Scroll list up */ + if (list_height > 1) { + /* De-highlight current last item before scrolling up */ + item_set(scroll + max_choice - 1); + print_item(list, + max_choice - 1, + FALSE); + scrollok(list, TRUE); + wscrl(list, 1); + scrollok(list, FALSE); + } + scroll++; + item_set(scroll + max_choice - 1); + print_item(list, max_choice - 1, TRUE); + + print_arrows(dialog, choice, item_count(), + scroll, box_y, box_x + check_x + 5, list_height); + + wnoutrefresh(dialog); + wrefresh(list); + + continue; /* wait for another key press */ + } else + i = choice + 1; + } + if (i != choice) { + /* De-highlight current item */ + item_set(scroll + choice); + print_item(list, choice, FALSE); + /* Highlight new item */ + choice = i; + item_set(scroll + choice); + print_item(list, choice, TRUE); + wnoutrefresh(dialog); + wrefresh(list); + } + continue; /* wait for another key press */ + } + switch (key) { + case 'H': + case 'h': + case '?': + button = 1; + /* fall-through */ + case 'S': + case 's': + case ' ': + case '\n': + item_foreach() + item_set_selected(0); + item_set(scroll + choice); + item_set_selected(1); + delwin(list); + delwin(dialog); + return button; + case TAB: + case KEY_LEFT: + case KEY_RIGHT: + button = ((key == KEY_LEFT ? --button : ++button) < 0) + ? 1 : (button > 1 ? 0 : button); + + print_buttons(dialog, height, width, button); + wrefresh(dialog); + break; + case 'X': + case 'x': + key = KEY_ESC; + break; + case KEY_ESC: + key = on_key_esc(dialog); + break; + case KEY_RESIZE: + delwin(list); + delwin(dialog); + on_key_resize(); + goto do_resize; + } + + /* Now, update everything... */ + doupdate(); + } + delwin(list); + delwin(dialog); + return key; /* ESC pressed */ +} diff --git a/bios/seabios/tools/kconfig/lxdialog/dialog.h b/bios/seabios/tools/kconfig/lxdialog/dialog.h new file mode 100644 index 0000000..b5211fc --- /dev/null +++ b/bios/seabios/tools/kconfig/lxdialog/dialog.h @@ -0,0 +1,230 @@ +/* + * dialog.h -- common declarations for all dialog modules + * + * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef KBUILD_NO_NLS +# include +#else +# define gettext(Msgid) ((const char *) (Msgid)) +#endif + +#ifdef __sun__ +#define CURS_MACROS +#endif +#include CURSES_LOC + +/* + * Colors in ncurses 1.9.9e do not work properly since foreground and + * background colors are OR'd rather than separately masked. This version + * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible + * with standard curses. The simplest fix (to make this work with standard + * curses) uses the wbkgdset() function, not used in the original hack. + * Turn it off if we're building with 1.9.9e, since it just confuses things. + */ +#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE) +#define OLD_NCURSES 1 +#undef wbkgdset +#define wbkgdset(w,p) /*nothing */ +#else +#define OLD_NCURSES 0 +#endif + +#define TR(params) _tracef params + +#define KEY_ESC 27 +#define TAB 9 +#define MAX_LEN 2048 +#define BUF_SIZE (10*1024) +#define MIN(x,y) (x < y ? x : y) +#define MAX(x,y) (x > y ? x : y) + +#ifndef ACS_ULCORNER +#define ACS_ULCORNER '+' +#endif +#ifndef ACS_LLCORNER +#define ACS_LLCORNER '+' +#endif +#ifndef ACS_URCORNER +#define ACS_URCORNER '+' +#endif +#ifndef ACS_LRCORNER +#define ACS_LRCORNER '+' +#endif +#ifndef ACS_HLINE +#define ACS_HLINE '-' +#endif +#ifndef ACS_VLINE +#define ACS_VLINE '|' +#endif +#ifndef ACS_LTEE +#define ACS_LTEE '+' +#endif +#ifndef ACS_RTEE +#define ACS_RTEE '+' +#endif +#ifndef ACS_UARROW +#define ACS_UARROW '^' +#endif +#ifndef ACS_DARROW +#define ACS_DARROW 'v' +#endif + +/* error return codes */ +#define ERRDISPLAYTOOSMALL (KEY_MAX + 1) + +/* + * Color definitions + */ +struct dialog_color { + chtype atr; /* Color attribute */ + int fg; /* foreground */ + int bg; /* background */ + int hl; /* highlight this item */ +}; + +struct dialog_info { + const char *backtitle; + struct dialog_color screen; + struct dialog_color shadow; + struct dialog_color dialog; + struct dialog_color title; + struct dialog_color border; + struct dialog_color button_active; + struct dialog_color button_inactive; + struct dialog_color button_key_active; + struct dialog_color button_key_inactive; + struct dialog_color button_label_active; + struct dialog_color button_label_inactive; + struct dialog_color inputbox; + struct dialog_color inputbox_border; + struct dialog_color searchbox; + struct dialog_color searchbox_title; + struct dialog_color searchbox_border; + struct dialog_color position_indicator; + struct dialog_color menubox; + struct dialog_color menubox_border; + struct dialog_color item; + struct dialog_color item_selected; + struct dialog_color tag; + struct dialog_color tag_selected; + struct dialog_color tag_key; + struct dialog_color tag_key_selected; + struct dialog_color check; + struct dialog_color check_selected; + struct dialog_color uarrow; + struct dialog_color darrow; +}; + +/* + * Global variables + */ +extern struct dialog_info dlg; +extern char dialog_input_result[]; + +/* + * Function prototypes + */ + +/* item list as used by checklist and menubox */ +void item_reset(void); +void item_make(const char *fmt, ...); +void item_add_str(const char *fmt, ...); +void item_set_tag(char tag); +void item_set_data(void *p); +void item_set_selected(int val); +int item_activate_selected(void); +void *item_data(void); +char item_tag(void); + +/* item list manipulation for lxdialog use */ +#define MAXITEMSTR 200 +struct dialog_item { + char str[MAXITEMSTR]; /* promtp displayed */ + char tag; + void *data; /* pointer to menu item - used by menubox+checklist */ + int selected; /* Set to 1 by dialog_*() function if selected. */ +}; + +/* list of lialog_items */ +struct dialog_list { + struct dialog_item node; + struct dialog_list *next; +}; + +extern struct dialog_list *item_cur; +extern struct dialog_list item_nil; +extern struct dialog_list *item_head; + +int item_count(void); +void item_set(int n); +int item_n(void); +const char *item_str(void); +int item_is_selected(void); +int item_is_tag(char tag); +#define item_foreach() \ + for (item_cur = item_head ? item_head: item_cur; \ + item_cur && (item_cur != &item_nil); item_cur = item_cur->next) + +/* generic key handlers */ +int on_key_esc(WINDOW *win); +int on_key_resize(void); + +int init_dialog(const char *backtitle); +void set_dialog_backtitle(const char *backtitle); +void end_dialog(int x, int y); +void attr_clear(WINDOW * win, int height, int width, chtype attr); +void dialog_clear(void); +void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x); +void print_button(WINDOW * win, const char *label, int y, int x, int selected); +void print_title(WINDOW *dialog, const char *title, int width); +void draw_box(WINDOW * win, int y, int x, int height, int width, chtype box, + chtype border); +void draw_shadow(WINDOW * win, int y, int x, int height, int width); + +int first_alpha(const char *string, const char *exempt); +int dialog_yesno(const char *title, const char *prompt, int height, int width); +int dialog_msgbox(const char *title, const char *prompt, int height, + int width, int pause); +int dialog_textbox(const char *title, const char *file, int height, int width); +int dialog_menu(const char *title, const char *prompt, + const void *selected, int *s_scroll); +int dialog_checklist(const char *title, const char *prompt, int height, + int width, int list_height); +extern char dialog_input_result[]; +int dialog_inputbox(const char *title, const char *prompt, int height, + int width, const char *init); + +/* + * This is the base for fictitious keys, which activate + * the buttons. + * + * Mouse-generated keys are the following: + * -- the first 32 are used as numbers, in addition to '0'-'9' + * -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o') + * -- uppercase chars are used to invoke the button (M_EVENT + 'O') + */ +#define M_EVENT (KEY_MAX+1) diff --git a/bios/seabios/tools/kconfig/lxdialog/inputbox.c b/bios/seabios/tools/kconfig/lxdialog/inputbox.c new file mode 100644 index 0000000..dd8e587 --- /dev/null +++ b/bios/seabios/tools/kconfig/lxdialog/inputbox.c @@ -0,0 +1,238 @@ +/* + * inputbox.c -- implements the input box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "dialog.h" + +char dialog_input_result[MAX_LEN + 1]; + +/* + * Print the termination buttons + */ +static void print_buttons(WINDOW * dialog, int height, int width, int selected) +{ + int x = width / 2 - 11; + int y = height - 2; + + print_button(dialog, gettext(" Ok "), y, x, selected == 0); + print_button(dialog, gettext(" Help "), y, x + 14, selected == 1); + + wmove(dialog, y, x + 1 + 14 * selected); + wrefresh(dialog); +} + +/* + * Display a dialog box for inputing a string + */ +int dialog_inputbox(const char *title, const char *prompt, int height, int width, + const char *init) +{ + int i, x, y, box_y, box_x, box_width; + int input_x = 0, scroll = 0, key = 0, button = -1; + char *instr = dialog_input_result; + WINDOW *dialog; + + if (!init) + instr[0] = '\0'; + else + strcpy(instr, init); + +do_resize: + if (getmaxy(stdscr) <= (height - 2)) + return -ERRDISPLAYTOOSMALL; + if (getmaxx(stdscr) <= (width - 2)) + return -ERRDISPLAYTOOSMALL; + + /* center dialog box on screen */ + x = (COLS - width) / 2; + y = (LINES - height) / 2; + + draw_shadow(stdscr, y, x, height, width); + + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + draw_box(dialog, 0, 0, height, width, + dlg.dialog.atr, dlg.border.atr); + wattrset(dialog, dlg.border.atr); + mvwaddch(dialog, height - 3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dlg.dialog.atr); + waddch(dialog, ACS_RTEE); + + print_title(dialog, title, width); + + wattrset(dialog, dlg.dialog.atr); + print_autowrap(dialog, prompt, width - 2, 1, 3); + + /* Draw the input field box */ + box_width = width - 6; + getyx(dialog, y, x); + box_y = y + 2; + box_x = (width - box_width) / 2; + draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2, + dlg.dialog.atr, dlg.border.atr); + + print_buttons(dialog, height, width, 0); + + /* Set up the initial value */ + wmove(dialog, box_y, box_x); + wattrset(dialog, dlg.inputbox.atr); + + input_x = strlen(instr); + + if (input_x >= box_width) { + scroll = input_x - box_width + 1; + input_x = box_width - 1; + for (i = 0; i < box_width - 1; i++) + waddch(dialog, instr[scroll + i]); + } else { + waddstr(dialog, instr); + } + + wmove(dialog, box_y, box_x + input_x); + + wrefresh(dialog); + + while (key != KEY_ESC) { + key = wgetch(dialog); + + if (button == -1) { /* Input box selected */ + switch (key) { + case TAB: + case KEY_UP: + case KEY_DOWN: + break; + case KEY_LEFT: + continue; + case KEY_RIGHT: + continue; + case KEY_BACKSPACE: + case 127: + if (input_x || scroll) { + wattrset(dialog, dlg.inputbox.atr); + if (!input_x) { + scroll = scroll < box_width - 1 ? 0 : scroll - (box_width - 1); + wmove(dialog, box_y, box_x); + for (i = 0; i < box_width; i++) + waddch(dialog, + instr[scroll + input_x + i] ? + instr[scroll + input_x + i] : ' '); + input_x = strlen(instr) - scroll; + } else + input_x--; + instr[scroll + input_x] = '\0'; + mvwaddch(dialog, box_y, input_x + box_x, ' '); + wmove(dialog, box_y, input_x + box_x); + wrefresh(dialog); + } + continue; + default: + if (key < 0x100 && isprint(key)) { + if (scroll + input_x < MAX_LEN) { + wattrset(dialog, dlg.inputbox.atr); + instr[scroll + input_x] = key; + instr[scroll + input_x + 1] = '\0'; + if (input_x == box_width - 1) { + scroll++; + wmove(dialog, box_y, box_x); + for (i = 0; i < box_width - 1; i++) + waddch(dialog, instr [scroll + i]); + } else { + wmove(dialog, box_y, input_x++ + box_x); + waddch(dialog, key); + } + wrefresh(dialog); + } else + flash(); /* Alarm user about overflow */ + continue; + } + } + } + switch (key) { + case 'O': + case 'o': + delwin(dialog); + return 0; + case 'H': + case 'h': + delwin(dialog); + return 1; + case KEY_UP: + case KEY_LEFT: + switch (button) { + case -1: + button = 1; /* Indicates "Help" button is selected */ + print_buttons(dialog, height, width, 1); + break; + case 0: + button = -1; /* Indicates input box is selected */ + print_buttons(dialog, height, width, 0); + wmove(dialog, box_y, box_x + input_x); + wrefresh(dialog); + break; + case 1: + button = 0; /* Indicates "OK" button is selected */ + print_buttons(dialog, height, width, 0); + break; + } + break; + case TAB: + case KEY_DOWN: + case KEY_RIGHT: + switch (button) { + case -1: + button = 0; /* Indicates "OK" button is selected */ + print_buttons(dialog, height, width, 0); + break; + case 0: + button = 1; /* Indicates "Help" button is selected */ + print_buttons(dialog, height, width, 1); + break; + case 1: + button = -1; /* Indicates input box is selected */ + print_buttons(dialog, height, width, 0); + wmove(dialog, box_y, box_x + input_x); + wrefresh(dialog); + break; + } + break; + case ' ': + case '\n': + delwin(dialog); + return (button == -1 ? 0 : button); + case 'X': + case 'x': + key = KEY_ESC; + break; + case KEY_ESC: + key = on_key_esc(dialog); + break; + case KEY_RESIZE: + delwin(dialog); + on_key_resize(); + goto do_resize; + } + } + + delwin(dialog); + return KEY_ESC; /* ESC pressed */ +} diff --git a/bios/seabios/tools/kconfig/lxdialog/menubox.c b/bios/seabios/tools/kconfig/lxdialog/menubox.c new file mode 100644 index 0000000..1d60473 --- /dev/null +++ b/bios/seabios/tools/kconfig/lxdialog/menubox.c @@ -0,0 +1,434 @@ +/* + * menubox.c -- implements the menu box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Changes by Clifford Wolf (god@clifford.at) + * + * [ 1998-06-13 ] + * + * *) A bugfix for the Page-Down problem + * + * *) Formerly when I used Page Down and Page Up, the cursor would be set + * to the first position in the menu box. Now lxdialog is a bit + * smarter and works more like other menu systems (just have a look at + * it). + * + * *) Formerly if I selected something my scrolling would be broken because + * lxdialog is re-invoked by the Menuconfig shell script, can't + * remember the last scrolling position, and just sets it so that the + * cursor is at the bottom of the box. Now it writes the temporary file + * lxdialog.scrltmp which contains this information. The file is + * deleted by lxdialog if the user leaves a submenu or enters a new + * one, but it would be nice if Menuconfig could make another "rm -f" + * just to be sure. Just try it out - you will recognise a difference! + * + * [ 1998-06-14 ] + * + * *) Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files + * and menus change their size on the fly. + * + * *) If for some reason the last scrolling position is not saved by + * lxdialog, it sets the scrolling so that the selected item is in the + * middle of the menu box, not at the bottom. + * + * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net) + * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus. + * This fixes a bug in Menuconfig where using ' ' to descend into menus + * would leave mis-synchronized lxdialog.scrltmp files lying around, + * fscanf would read in 'scroll', and eventually that value would get used. + */ + +#include "dialog.h" + +static int menu_width, item_x; + +/* + * Print menu item + */ +static void do_print_item(WINDOW * win, const char *item, int line_y, + int selected, int hotkey) +{ + int j; + char *menu_item = malloc(menu_width + 1); + + strncpy(menu_item, item, menu_width - item_x); + menu_item[menu_width - item_x] = '\0'; + j = first_alpha(menu_item, "YyNnMmHh"); + + /* Clear 'residue' of last item */ + wattrset(win, dlg.menubox.atr); + wmove(win, line_y, 0); +#if OLD_NCURSES + { + int i; + for (i = 0; i < menu_width; i++) + waddch(win, ' '); + } +#else + wclrtoeol(win); +#endif + wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr); + mvwaddstr(win, line_y, item_x, menu_item); + if (hotkey) { + wattrset(win, selected ? dlg.tag_key_selected.atr + : dlg.tag_key.atr); + mvwaddch(win, line_y, item_x + j, menu_item[j]); + } + if (selected) { + wmove(win, line_y, item_x + 1); + } + free(menu_item); + wrefresh(win); +} + +#define print_item(index, choice, selected) \ +do { \ + item_set(index); \ + do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \ +} while (0) + +/* + * Print the scroll indicators. + */ +static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x, + int height) +{ + int cur_y, cur_x; + + getyx(win, cur_y, cur_x); + + wmove(win, y, x); + + if (scroll > 0) { + wattrset(win, dlg.uarrow.atr); + waddch(win, ACS_UARROW); + waddstr(win, "(-)"); + } else { + wattrset(win, dlg.menubox.atr); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + } + + y = y + height + 1; + wmove(win, y, x); + wrefresh(win); + + if ((height < item_no) && (scroll + height < item_no)) { + wattrset(win, dlg.darrow.atr); + waddch(win, ACS_DARROW); + waddstr(win, "(+)"); + } else { + wattrset(win, dlg.menubox_border.atr); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + } + + wmove(win, cur_y, cur_x); + wrefresh(win); +} + +/* + * Display the termination buttons. + */ +static void print_buttons(WINDOW * win, int height, int width, int selected) +{ + int x = width / 2 - 16; + int y = height - 2; + + print_button(win, gettext("Select"), y, x, selected == 0); + print_button(win, gettext(" Exit "), y, x + 12, selected == 1); + print_button(win, gettext(" Help "), y, x + 24, selected == 2); + + wmove(win, y, x + 1 + 12 * selected); + wrefresh(win); +} + +/* scroll up n lines (n may be negative) */ +static void do_scroll(WINDOW *win, int *scroll, int n) +{ + /* Scroll menu up */ + scrollok(win, TRUE); + wscrl(win, n); + scrollok(win, FALSE); + *scroll = *scroll + n; + wrefresh(win); +} + +/* + * Display a menu for choosing among a number of options + */ +int dialog_menu(const char *title, const char *prompt, + const void *selected, int *s_scroll) +{ + int i, j, x, y, box_x, box_y; + int height, width, menu_height; + int key = 0, button = 0, scroll = 0, choice = 0; + int first_item = 0, max_choice; + WINDOW *dialog, *menu; + +do_resize: + height = getmaxy(stdscr); + width = getmaxx(stdscr); + if (height < 15 || width < 65) + return -ERRDISPLAYTOOSMALL; + + height -= 4; + width -= 5; + menu_height = height - 10; + + max_choice = MIN(menu_height, item_count()); + + /* center dialog box on screen */ + x = (COLS - width) / 2; + y = (LINES - height) / 2; + + draw_shadow(stdscr, y, x, height, width); + + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + draw_box(dialog, 0, 0, height, width, + dlg.dialog.atr, dlg.border.atr); + wattrset(dialog, dlg.border.atr); + mvwaddch(dialog, height - 3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dlg.dialog.atr); + wbkgdset(dialog, dlg.dialog.atr & A_COLOR); + waddch(dialog, ACS_RTEE); + + print_title(dialog, title, width); + + wattrset(dialog, dlg.dialog.atr); + print_autowrap(dialog, prompt, width - 2, 1, 3); + + menu_width = width - 6; + box_y = height - menu_height - 5; + box_x = (width - menu_width) / 2 - 1; + + /* create new window for the menu */ + menu = subwin(dialog, menu_height, menu_width, + y + box_y + 1, x + box_x + 1); + keypad(menu, TRUE); + + /* draw a box around the menu items */ + draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2, + dlg.menubox_border.atr, dlg.menubox.atr); + + if (menu_width >= 80) + item_x = (menu_width - 70) / 2; + else + item_x = 4; + + /* Set choice to default item */ + item_foreach() + if (selected && (selected == item_data())) + choice = item_n(); + /* get the saved scroll info */ + scroll = *s_scroll; + if ((scroll <= choice) && (scroll + max_choice > choice) && + (scroll >= 0) && (scroll + max_choice <= item_count())) { + first_item = scroll; + choice = choice - scroll; + } else { + scroll = 0; + } + if ((choice >= max_choice)) { + if (choice >= item_count() - max_choice / 2) + scroll = first_item = item_count() - max_choice; + else + scroll = first_item = choice - max_choice / 2; + choice = choice - scroll; + } + + /* Print the menu */ + for (i = 0; i < max_choice; i++) { + print_item(first_item + i, i, i == choice); + } + + wnoutrefresh(menu); + + print_arrows(dialog, item_count(), scroll, + box_y, box_x + item_x + 1, menu_height); + + print_buttons(dialog, height, width, 0); + wmove(menu, choice, item_x + 1); + wrefresh(menu); + + while (key != KEY_ESC) { + key = wgetch(menu); + + if (key < 256 && isalpha(key)) + key = tolower(key); + + if (strchr("ynmh", key)) + i = max_choice; + else { + for (i = choice + 1; i < max_choice; i++) { + item_set(scroll + i); + j = first_alpha(item_str(), "YyNnMmHh"); + if (key == tolower(item_str()[j])) + break; + } + if (i == max_choice) + for (i = 0; i < max_choice; i++) { + item_set(scroll + i); + j = first_alpha(item_str(), "YyNnMmHh"); + if (key == tolower(item_str()[j])) + break; + } + } + + if (i < max_choice || + key == KEY_UP || key == KEY_DOWN || + key == '-' || key == '+' || + key == KEY_PPAGE || key == KEY_NPAGE) { + /* Remove highligt of current item */ + print_item(scroll + choice, choice, FALSE); + + if (key == KEY_UP || key == '-') { + if (choice < 2 && scroll) { + /* Scroll menu down */ + do_scroll(menu, &scroll, -1); + + print_item(scroll, 0, FALSE); + } else + choice = MAX(choice - 1, 0); + + } else if (key == KEY_DOWN || key == '+') { + print_item(scroll+choice, choice, FALSE); + + if ((choice > max_choice - 3) && + (scroll + max_choice < item_count())) { + /* Scroll menu up */ + do_scroll(menu, &scroll, 1); + + print_item(scroll+max_choice - 1, + max_choice - 1, FALSE); + } else + choice = MIN(choice + 1, max_choice - 1); + + } else if (key == KEY_PPAGE) { + scrollok(menu, TRUE); + for (i = 0; (i < max_choice); i++) { + if (scroll > 0) { + do_scroll(menu, &scroll, -1); + print_item(scroll, 0, FALSE); + } else { + if (choice > 0) + choice--; + } + } + + } else if (key == KEY_NPAGE) { + for (i = 0; (i < max_choice); i++) { + if (scroll + max_choice < item_count()) { + do_scroll(menu, &scroll, 1); + print_item(scroll+max_choice-1, + max_choice - 1, FALSE); + } else { + if (choice + 1 < max_choice) + choice++; + } + } + } else + choice = i; + + print_item(scroll + choice, choice, TRUE); + + print_arrows(dialog, item_count(), scroll, + box_y, box_x + item_x + 1, menu_height); + + wnoutrefresh(dialog); + wrefresh(menu); + + continue; /* wait for another key press */ + } + + switch (key) { + case KEY_LEFT: + case TAB: + case KEY_RIGHT: + button = ((key == KEY_LEFT ? --button : ++button) < 0) + ? 2 : (button > 2 ? 0 : button); + + print_buttons(dialog, height, width, button); + wrefresh(menu); + break; + case ' ': + case 's': + case 'y': + case 'n': + case 'm': + case '/': + case 'h': + case '?': + case 'z': + case '\n': + /* save scroll info */ + *s_scroll = scroll; + delwin(menu); + delwin(dialog); + item_set(scroll + choice); + item_set_selected(1); + switch (key) { + case 'h': + case '?': + return 2; + case 's': + case 'y': + return 3; + case 'n': + return 4; + case 'm': + return 5; + case ' ': + return 6; + case '/': + return 7; + case 'z': + return 8; + case '\n': + return button; + } + return 0; + case 'e': + case 'x': + key = KEY_ESC; + break; + case KEY_ESC: + key = on_key_esc(menu); + break; + case KEY_RESIZE: + on_key_resize(); + delwin(menu); + delwin(dialog); + goto do_resize; + } + } + delwin(menu); + delwin(dialog); + return key; /* ESC pressed */ +} diff --git a/bios/seabios/tools/kconfig/lxdialog/textbox.c b/bios/seabios/tools/kconfig/lxdialog/textbox.c new file mode 100644 index 0000000..c704712 --- /dev/null +++ b/bios/seabios/tools/kconfig/lxdialog/textbox.c @@ -0,0 +1,391 @@ +/* + * textbox.c -- implements the text box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "dialog.h" + +static void back_lines(int n); +static void print_page(WINDOW * win, int height, int width); +static void print_line(WINDOW * win, int row, int width); +static char *get_line(void); +static void print_position(WINDOW * win); + +static int hscroll; +static int begin_reached, end_reached, page_length; +static const char *buf; +static const char *page; + +/* + * refresh window content + */ +static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw, + int cur_y, int cur_x) +{ + print_page(box, boxh, boxw); + print_position(dialog); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); +} + + +/* + * Display text from a file in a dialog box. + */ +int dialog_textbox(const char *title, const char *tbuf, + int initial_height, int initial_width) +{ + int i, x, y, cur_x, cur_y, key = 0; + int height, width, boxh, boxw; + int passed_end; + WINDOW *dialog, *box; + + begin_reached = 1; + end_reached = 0; + page_length = 0; + hscroll = 0; + buf = tbuf; + page = buf; /* page is pointer to start of page to be displayed */ + +do_resize: + getmaxyx(stdscr, height, width); + if (height < 8 || width < 8) + return -ERRDISPLAYTOOSMALL; + if (initial_height != 0) + height = initial_height; + else + if (height > 4) + height -= 4; + else + height = 0; + if (initial_width != 0) + width = initial_width; + else + if (width > 5) + width -= 5; + else + width = 0; + + /* center dialog box on screen */ + x = (COLS - width) / 2; + y = (LINES - height) / 2; + + draw_shadow(stdscr, y, x, height, width); + + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + /* Create window for box region, used for scrolling text */ + boxh = height - 4; + boxw = width - 2; + box = subwin(dialog, boxh, boxw, y + 1, x + 1); + wattrset(box, dlg.dialog.atr); + wbkgdset(box, dlg.dialog.atr & A_COLOR); + + keypad(box, TRUE); + + /* register the new window, along with its borders */ + draw_box(dialog, 0, 0, height, width, + dlg.dialog.atr, dlg.border.atr); + + wattrset(dialog, dlg.border.atr); + mvwaddch(dialog, height - 3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dlg.dialog.atr); + wbkgdset(dialog, dlg.dialog.atr & A_COLOR); + waddch(dialog, ACS_RTEE); + + print_title(dialog, title, width); + + print_button(dialog, gettext(" Exit "), height - 2, width / 2 - 4, TRUE); + wnoutrefresh(dialog); + getyx(dialog, cur_y, cur_x); /* Save cursor position */ + + /* Print first page of text */ + attr_clear(box, boxh, boxw, dlg.dialog.atr); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); + + while ((key != KEY_ESC) && (key != '\n')) { + key = wgetch(dialog); + switch (key) { + case 'E': /* Exit */ + case 'e': + case 'X': + case 'x': + delwin(box); + delwin(dialog); + return 0; + case 'g': /* First page */ + case KEY_HOME: + if (!begin_reached) { + begin_reached = 1; + page = buf; + refresh_text_box(dialog, box, boxh, boxw, + cur_y, cur_x); + } + break; + case 'G': /* Last page */ + case KEY_END: + + end_reached = 1; + /* point to last char in buf */ + page = buf + strlen(buf); + back_lines(boxh); + refresh_text_box(dialog, box, boxh, boxw, + cur_y, cur_x); + break; + case 'K': /* Previous line */ + case 'k': + case KEY_UP: + if (!begin_reached) { + back_lines(page_length + 1); + + /* We don't call print_page() here but use + * scrolling to ensure faster screen update. + * However, 'end_reached' and 'page_length' + * should still be updated, and 'page' should + * point to start of next page. This is done + * by calling get_line() in the following + * 'for' loop. */ + scrollok(box, TRUE); + wscrl(box, -1); /* Scroll box region down one line */ + scrollok(box, FALSE); + page_length = 0; + passed_end = 0; + for (i = 0; i < boxh; i++) { + if (!i) { + /* print first line of page */ + print_line(box, 0, boxw); + wnoutrefresh(box); + } else + /* Called to update 'end_reached' and 'page' */ + get_line(); + if (!passed_end) + page_length++; + if (end_reached && !passed_end) + passed_end = 1; + } + + print_position(dialog); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); + } + break; + case 'B': /* Previous page */ + case 'b': + case KEY_PPAGE: + if (begin_reached) + break; + back_lines(page_length + boxh); + refresh_text_box(dialog, box, boxh, boxw, + cur_y, cur_x); + break; + case 'J': /* Next line */ + case 'j': + case KEY_DOWN: + if (!end_reached) { + begin_reached = 0; + scrollok(box, TRUE); + scroll(box); /* Scroll box region up one line */ + scrollok(box, FALSE); + print_line(box, boxh - 1, boxw); + wnoutrefresh(box); + print_position(dialog); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); + } + break; + case KEY_NPAGE: /* Next page */ + case ' ': + if (end_reached) + break; + + begin_reached = 0; + refresh_text_box(dialog, box, boxh, boxw, + cur_y, cur_x); + break; + case '0': /* Beginning of line */ + case 'H': /* Scroll left */ + case 'h': + case KEY_LEFT: + if (hscroll <= 0) + break; + + if (key == '0') + hscroll = 0; + else + hscroll--; + /* Reprint current page to scroll horizontally */ + back_lines(page_length); + refresh_text_box(dialog, box, boxh, boxw, + cur_y, cur_x); + break; + case 'L': /* Scroll right */ + case 'l': + case KEY_RIGHT: + if (hscroll >= MAX_LEN) + break; + hscroll++; + /* Reprint current page to scroll horizontally */ + back_lines(page_length); + refresh_text_box(dialog, box, boxh, boxw, + cur_y, cur_x); + break; + case KEY_ESC: + key = on_key_esc(dialog); + break; + case KEY_RESIZE: + back_lines(height); + delwin(box); + delwin(dialog); + on_key_resize(); + goto do_resize; + } + } + delwin(box); + delwin(dialog); + return key; /* ESC pressed */ +} + +/* + * Go back 'n' lines in text. Called by dialog_textbox(). + * 'page' will be updated to point to the desired line in 'buf'. + */ +static void back_lines(int n) +{ + int i; + + begin_reached = 0; + /* Go back 'n' lines */ + for (i = 0; i < n; i++) { + if (*page == '\0') { + if (end_reached) { + end_reached = 0; + continue; + } + } + if (page == buf) { + begin_reached = 1; + return; + } + page--; + do { + if (page == buf) { + begin_reached = 1; + return; + } + page--; + } while (*page != '\n'); + page++; + } +} + +/* + * Print a new page of text. Called by dialog_textbox(). + */ +static void print_page(WINDOW * win, int height, int width) +{ + int i, passed_end = 0; + + page_length = 0; + for (i = 0; i < height; i++) { + print_line(win, i, width); + if (!passed_end) + page_length++; + if (end_reached && !passed_end) + passed_end = 1; + } + wnoutrefresh(win); +} + +/* + * Print a new line of text. Called by dialog_textbox() and print_page(). + */ +static void print_line(WINDOW * win, int row, int width) +{ + int y, x; + char *line; + + line = get_line(); + line += MIN(strlen(line), hscroll); /* Scroll horizontally */ + wmove(win, row, 0); /* move cursor to correct line */ + waddch(win, ' '); + waddnstr(win, line, MIN(strlen(line), width - 2)); + + getyx(win, y, x); + /* Clear 'residue' of previous line */ +#if OLD_NCURSES + { + int i; + for (i = 0; i < width - x; i++) + waddch(win, ' '); + } +#else + wclrtoeol(win); +#endif +} + +/* + * Return current line of text. Called by dialog_textbox() and print_line(). + * 'page' should point to start of current line before calling, and will be + * updated to point to start of next line. + */ +static char *get_line(void) +{ + int i = 0; + static char line[MAX_LEN + 1]; + + end_reached = 0; + while (*page != '\n') { + if (*page == '\0') { + if (!end_reached) { + end_reached = 1; + break; + } + } else if (i < MAX_LEN) + line[i++] = *(page++); + else { + /* Truncate lines longer than MAX_LEN characters */ + if (i == MAX_LEN) + line[i++] = '\0'; + page++; + } + } + if (i <= MAX_LEN) + line[i] = '\0'; + if (!end_reached) + page++; /* move pass '\n' */ + + return line; +} + +/* + * Print current position + */ +static void print_position(WINDOW * win) +{ + int percent; + + wattrset(win, dlg.position_indicator.atr); + wbkgdset(win, dlg.position_indicator.atr & A_COLOR); + percent = (page - buf) * 100 / strlen(buf); + wmove(win, getmaxy(win) - 3, getmaxx(win) - 9); + wprintw(win, "(%3d%%)", percent); +} diff --git a/bios/seabios/tools/kconfig/lxdialog/util.c b/bios/seabios/tools/kconfig/lxdialog/util.c new file mode 100644 index 0000000..f2375ad --- /dev/null +++ b/bios/seabios/tools/kconfig/lxdialog/util.c @@ -0,0 +1,657 @@ +/* + * util.c + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include "dialog.h" + +struct dialog_info dlg; + +static void set_mono_theme(void) +{ + dlg.screen.atr = A_NORMAL; + dlg.shadow.atr = A_NORMAL; + dlg.dialog.atr = A_NORMAL; + dlg.title.atr = A_BOLD; + dlg.border.atr = A_NORMAL; + dlg.button_active.atr = A_REVERSE; + dlg.button_inactive.atr = A_DIM; + dlg.button_key_active.atr = A_REVERSE; + dlg.button_key_inactive.atr = A_BOLD; + dlg.button_label_active.atr = A_REVERSE; + dlg.button_label_inactive.atr = A_NORMAL; + dlg.inputbox.atr = A_NORMAL; + dlg.inputbox_border.atr = A_NORMAL; + dlg.searchbox.atr = A_NORMAL; + dlg.searchbox_title.atr = A_BOLD; + dlg.searchbox_border.atr = A_NORMAL; + dlg.position_indicator.atr = A_BOLD; + dlg.menubox.atr = A_NORMAL; + dlg.menubox_border.atr = A_NORMAL; + dlg.item.atr = A_NORMAL; + dlg.item_selected.atr = A_REVERSE; + dlg.tag.atr = A_BOLD; + dlg.tag_selected.atr = A_REVERSE; + dlg.tag_key.atr = A_BOLD; + dlg.tag_key_selected.atr = A_REVERSE; + dlg.check.atr = A_BOLD; + dlg.check_selected.atr = A_REVERSE; + dlg.uarrow.atr = A_BOLD; + dlg.darrow.atr = A_BOLD; +} + +#define DLG_COLOR(dialog, f, b, h) \ +do { \ + dlg.dialog.fg = (f); \ + dlg.dialog.bg = (b); \ + dlg.dialog.hl = (h); \ +} while (0) + +static void set_classic_theme(void) +{ + DLG_COLOR(screen, COLOR_CYAN, COLOR_BLUE, true); + DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, true); + DLG_COLOR(dialog, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(title, COLOR_YELLOW, COLOR_WHITE, true); + DLG_COLOR(border, COLOR_WHITE, COLOR_WHITE, true); + DLG_COLOR(button_active, COLOR_WHITE, COLOR_BLUE, true); + DLG_COLOR(button_inactive, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(button_key_active, COLOR_WHITE, COLOR_BLUE, true); + DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_WHITE, false); + DLG_COLOR(button_label_active, COLOR_YELLOW, COLOR_BLUE, true); + DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_WHITE, true); + DLG_COLOR(inputbox, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(inputbox_border, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(searchbox, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_WHITE, true); + DLG_COLOR(searchbox_border, COLOR_WHITE, COLOR_WHITE, true); + DLG_COLOR(position_indicator, COLOR_YELLOW, COLOR_WHITE, true); + DLG_COLOR(menubox, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(menubox_border, COLOR_WHITE, COLOR_WHITE, true); + DLG_COLOR(item, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(item_selected, COLOR_WHITE, COLOR_BLUE, true); + DLG_COLOR(tag, COLOR_YELLOW, COLOR_WHITE, true); + DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_BLUE, true); + DLG_COLOR(tag_key, COLOR_YELLOW, COLOR_WHITE, true); + DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_BLUE, true); + DLG_COLOR(check, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(check_selected, COLOR_WHITE, COLOR_BLUE, true); + DLG_COLOR(uarrow, COLOR_GREEN, COLOR_WHITE, true); + DLG_COLOR(darrow, COLOR_GREEN, COLOR_WHITE, true); +} + +static void set_blackbg_theme(void) +{ + DLG_COLOR(screen, COLOR_RED, COLOR_BLACK, true); + DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false); + DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false); + DLG_COLOR(title, COLOR_RED, COLOR_BLACK, false); + DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true); + + DLG_COLOR(button_active, COLOR_YELLOW, COLOR_RED, false); + DLG_COLOR(button_inactive, COLOR_YELLOW, COLOR_BLACK, false); + DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_RED, true); + DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_BLACK, false); + DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_RED, false); + DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_BLACK, true); + + DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false); + DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false); + + DLG_COLOR(searchbox, COLOR_YELLOW, COLOR_BLACK, false); + DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_BLACK, true); + DLG_COLOR(searchbox_border, COLOR_BLACK, COLOR_BLACK, true); + + DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK, false); + + DLG_COLOR(menubox, COLOR_YELLOW, COLOR_BLACK, false); + DLG_COLOR(menubox_border, COLOR_BLACK, COLOR_BLACK, true); + + DLG_COLOR(item, COLOR_WHITE, COLOR_BLACK, false); + DLG_COLOR(item_selected, COLOR_WHITE, COLOR_RED, false); + + DLG_COLOR(tag, COLOR_RED, COLOR_BLACK, false); + DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_RED, true); + DLG_COLOR(tag_key, COLOR_RED, COLOR_BLACK, false); + DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED, true); + + DLG_COLOR(check, COLOR_YELLOW, COLOR_BLACK, false); + DLG_COLOR(check_selected, COLOR_YELLOW, COLOR_RED, true); + + DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false); + DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false); +} + +static void set_bluetitle_theme(void) +{ + set_classic_theme(); + DLG_COLOR(title, COLOR_BLUE, COLOR_WHITE, true); + DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_BLUE, true); + DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_BLUE, true); + DLG_COLOR(searchbox_title, COLOR_BLUE, COLOR_WHITE, true); + DLG_COLOR(position_indicator, COLOR_BLUE, COLOR_WHITE, true); + DLG_COLOR(tag, COLOR_BLUE, COLOR_WHITE, true); + DLG_COLOR(tag_key, COLOR_BLUE, COLOR_WHITE, true); + +} + +/* + * Select color theme + */ +static int set_theme(const char *theme) +{ + int use_color = 1; + if (!theme) + set_bluetitle_theme(); + else if (strcmp(theme, "classic") == 0) + set_classic_theme(); + else if (strcmp(theme, "bluetitle") == 0) + set_bluetitle_theme(); + else if (strcmp(theme, "blackbg") == 0) + set_blackbg_theme(); + else if (strcmp(theme, "mono") == 0) + use_color = 0; + + return use_color; +} + +static void init_one_color(struct dialog_color *color) +{ + static int pair = 0; + + pair++; + init_pair(pair, color->fg, color->bg); + if (color->hl) + color->atr = A_BOLD | COLOR_PAIR(pair); + else + color->atr = COLOR_PAIR(pair); +} + +static void init_dialog_colors(void) +{ + init_one_color(&dlg.screen); + init_one_color(&dlg.shadow); + init_one_color(&dlg.dialog); + init_one_color(&dlg.title); + init_one_color(&dlg.border); + init_one_color(&dlg.button_active); + init_one_color(&dlg.button_inactive); + init_one_color(&dlg.button_key_active); + init_one_color(&dlg.button_key_inactive); + init_one_color(&dlg.button_label_active); + init_one_color(&dlg.button_label_inactive); + init_one_color(&dlg.inputbox); + init_one_color(&dlg.inputbox_border); + init_one_color(&dlg.searchbox); + init_one_color(&dlg.searchbox_title); + init_one_color(&dlg.searchbox_border); + init_one_color(&dlg.position_indicator); + init_one_color(&dlg.menubox); + init_one_color(&dlg.menubox_border); + init_one_color(&dlg.item); + init_one_color(&dlg.item_selected); + init_one_color(&dlg.tag); + init_one_color(&dlg.tag_selected); + init_one_color(&dlg.tag_key); + init_one_color(&dlg.tag_key_selected); + init_one_color(&dlg.check); + init_one_color(&dlg.check_selected); + init_one_color(&dlg.uarrow); + init_one_color(&dlg.darrow); +} + +/* + * Setup for color display + */ +static void color_setup(const char *theme) +{ + int use_color; + + use_color = set_theme(theme); + if (use_color && has_colors()) { + start_color(); + init_dialog_colors(); + } else + set_mono_theme(); +} + +/* + * Set window to attribute 'attr' + */ +void attr_clear(WINDOW * win, int height, int width, chtype attr) +{ + int i, j; + + wattrset(win, attr); + for (i = 0; i < height; i++) { + wmove(win, i, 0); + for (j = 0; j < width; j++) + waddch(win, ' '); + } + touchwin(win); +} + +void dialog_clear(void) +{ + attr_clear(stdscr, LINES, COLS, dlg.screen.atr); + /* Display background title if it exists ... - SLH */ + if (dlg.backtitle != NULL) { + int i; + + wattrset(stdscr, dlg.screen.atr); + mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle); + wmove(stdscr, 1, 1); + for (i = 1; i < COLS - 1; i++) + waddch(stdscr, ACS_HLINE); + } + wnoutrefresh(stdscr); +} + +/* + * Do some initialization for dialog + */ +int init_dialog(const char *backtitle) +{ + int height, width; + + initscr(); /* Init curses */ + getmaxyx(stdscr, height, width); + if (height < 19 || width < 80) { + endwin(); + return -ERRDISPLAYTOOSMALL; + } + + dlg.backtitle = backtitle; + color_setup(getenv("MENUCONFIG_COLOR")); + + keypad(stdscr, TRUE); + cbreak(); + noecho(); + dialog_clear(); + + return 0; +} + +void set_dialog_backtitle(const char *backtitle) +{ + dlg.backtitle = backtitle; +} + +/* + * End using dialog functions. + */ +void end_dialog(int x, int y) +{ + /* move cursor back to original position */ + move(y, x); + refresh(); + endwin(); +} + +/* Print the title of the dialog. Center the title and truncate + * tile if wider than dialog (- 2 chars). + **/ +void print_title(WINDOW *dialog, const char *title, int width) +{ + if (title) { + int tlen = MIN(width - 2, strlen(title)); + wattrset(dialog, dlg.title.atr); + mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' '); + mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen); + waddch(dialog, ' '); + } +} + +/* + * Print a string of text in a window, automatically wrap around to the + * next line if the string is too long to fit on one line. Newline + * characters '\n' are replaced by spaces. We start on a new line + * if there is no room for at least 4 nonblanks following a double-space. + */ +void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x) +{ + int newl, cur_x, cur_y; + int i, prompt_len, room, wlen; + char tempstr[MAX_LEN + 1], *word, *sp, *sp2; + + strcpy(tempstr, prompt); + + prompt_len = strlen(tempstr); + + /* + * Remove newlines + */ + for (i = 0; i < prompt_len; i++) { + if (tempstr[i] == '\n') + tempstr[i] = ' '; + } + + if (prompt_len <= width - x * 2) { /* If prompt is short */ + wmove(win, y, (width - prompt_len) / 2); + waddstr(win, tempstr); + } else { + cur_x = x; + cur_y = y; + newl = 1; + word = tempstr; + while (word && *word) { + sp = strchr(word, ' '); + if (sp) + *sp++ = 0; + + /* Wrap to next line if either the word does not fit, + or it is the first word of a new sentence, and it is + short, and the next word does not fit. */ + room = width - cur_x; + wlen = strlen(word); + if (wlen > room || + (newl && wlen < 4 && sp + && wlen + 1 + strlen(sp) > room + && (!(sp2 = strchr(sp, ' ')) + || wlen + 1 + (sp2 - sp) > room))) { + cur_y++; + cur_x = x; + } + wmove(win, cur_y, cur_x); + waddstr(win, word); + getyx(win, cur_y, cur_x); + cur_x++; + if (sp && *sp == ' ') { + cur_x++; /* double space */ + while (*++sp == ' ') ; + newl = 1; + } else + newl = 0; + word = sp; + } + } +} + +/* + * Print a button + */ +void print_button(WINDOW * win, const char *label, int y, int x, int selected) +{ + int i, temp; + + wmove(win, y, x); + wattrset(win, selected ? dlg.button_active.atr + : dlg.button_inactive.atr); + waddstr(win, "<"); + temp = strspn(label, " "); + label += temp; + wattrset(win, selected ? dlg.button_label_active.atr + : dlg.button_label_inactive.atr); + for (i = 0; i < temp; i++) + waddch(win, ' '); + wattrset(win, selected ? dlg.button_key_active.atr + : dlg.button_key_inactive.atr); + waddch(win, label[0]); + wattrset(win, selected ? dlg.button_label_active.atr + : dlg.button_label_inactive.atr); + waddstr(win, (char *)label + 1); + wattrset(win, selected ? dlg.button_active.atr + : dlg.button_inactive.atr); + waddstr(win, ">"); + wmove(win, y, x + temp + 1); +} + +/* + * Draw a rectangular box with line drawing characters + */ +void +draw_box(WINDOW * win, int y, int x, int height, int width, + chtype box, chtype border) +{ + int i, j; + + wattrset(win, 0); + for (i = 0; i < height; i++) { + wmove(win, y + i, x); + for (j = 0; j < width; j++) + if (!i && !j) + waddch(win, border | ACS_ULCORNER); + else if (i == height - 1 && !j) + waddch(win, border | ACS_LLCORNER); + else if (!i && j == width - 1) + waddch(win, box | ACS_URCORNER); + else if (i == height - 1 && j == width - 1) + waddch(win, box | ACS_LRCORNER); + else if (!i) + waddch(win, border | ACS_HLINE); + else if (i == height - 1) + waddch(win, box | ACS_HLINE); + else if (!j) + waddch(win, border | ACS_VLINE); + else if (j == width - 1) + waddch(win, box | ACS_VLINE); + else + waddch(win, box | ' '); + } +} + +/* + * Draw shadows along the right and bottom edge to give a more 3D look + * to the boxes + */ +void draw_shadow(WINDOW * win, int y, int x, int height, int width) +{ + int i; + + if (has_colors()) { /* Whether terminal supports color? */ + wattrset(win, dlg.shadow.atr); + wmove(win, y + height, x + 2); + for (i = 0; i < width; i++) + waddch(win, winch(win) & A_CHARTEXT); + for (i = y + 1; i < y + height + 1; i++) { + wmove(win, i, x + width); + waddch(win, winch(win) & A_CHARTEXT); + waddch(win, winch(win) & A_CHARTEXT); + } + wnoutrefresh(win); + } +} + +/* + * Return the position of the first alphabetic character in a string. + */ +int first_alpha(const char *string, const char *exempt) +{ + int i, in_paren = 0, c; + + for (i = 0; i < strlen(string); i++) { + c = tolower(string[i]); + + if (strchr("<[(", c)) + ++in_paren; + if (strchr(">])", c) && in_paren > 0) + --in_paren; + + if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0) + return i; + } + + return 0; +} + +/* + * ncurses uses ESC to detect escaped char sequences. This resutl in + * a small timeout before ESC is actually delivered to the application. + * lxdialog suggest which is correctly translated to two + * times esc. But then we need to ignore the second esc to avoid stepping + * out one menu too much. Filter away all escaped key sequences since + * keypad(FALSE) turn off ncurses support for escape sequences - and thats + * needed to make notimeout() do as expected. + */ +int on_key_esc(WINDOW *win) +{ + int key; + int key2; + int key3; + + nodelay(win, TRUE); + keypad(win, FALSE); + key = wgetch(win); + key2 = wgetch(win); + do { + key3 = wgetch(win); + } while (key3 != ERR); + nodelay(win, FALSE); + keypad(win, TRUE); + if (key == KEY_ESC && key2 == ERR) + return KEY_ESC; + else if (key != ERR && key != KEY_ESC && key2 == ERR) + ungetch(key); + + return -1; +} + +/* redraw screen in new size */ +int on_key_resize(void) +{ + dialog_clear(); + return KEY_RESIZE; +} + +struct dialog_list *item_cur; +struct dialog_list item_nil; +struct dialog_list *item_head; + +void item_reset(void) +{ + struct dialog_list *p, *next; + + for (p = item_head; p; p = next) { + next = p->next; + free(p); + } + item_head = NULL; + item_cur = &item_nil; +} + +void item_make(const char *fmt, ...) +{ + va_list ap; + struct dialog_list *p = malloc(sizeof(*p)); + + if (item_head) + item_cur->next = p; + else + item_head = p; + item_cur = p; + memset(p, 0, sizeof(*p)); + + va_start(ap, fmt); + vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap); + va_end(ap); +} + +void item_add_str(const char *fmt, ...) +{ + va_list ap; + size_t avail; + + avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str); + + va_start(ap, fmt); + vsnprintf(item_cur->node.str + strlen(item_cur->node.str), + avail, fmt, ap); + item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0'; + va_end(ap); +} + +void item_set_tag(char tag) +{ + item_cur->node.tag = tag; +} +void item_set_data(void *ptr) +{ + item_cur->node.data = ptr; +} + +void item_set_selected(int val) +{ + item_cur->node.selected = val; +} + +int item_activate_selected(void) +{ + item_foreach() + if (item_is_selected()) + return 1; + return 0; +} + +void *item_data(void) +{ + return item_cur->node.data; +} + +char item_tag(void) +{ + return item_cur->node.tag; +} + +int item_count(void) +{ + int n = 0; + struct dialog_list *p; + + for (p = item_head; p; p = p->next) + n++; + return n; +} + +void item_set(int n) +{ + int i = 0; + item_foreach() + if (i++ == n) + return; +} + +int item_n(void) +{ + int n = 0; + struct dialog_list *p; + + for (p = item_head; p; p = p->next) { + if (p == item_cur) + return n; + n++; + } + return 0; +} + +const char *item_str(void) +{ + return item_cur->node.str; +} + +int item_is_selected(void) +{ + return (item_cur->node.selected != 0); +} + +int item_is_tag(char tag) +{ + return (item_cur->node.tag == tag); +} diff --git a/bios/seabios/tools/kconfig/lxdialog/yesno.c b/bios/seabios/tools/kconfig/lxdialog/yesno.c new file mode 100644 index 0000000..4e6e809 --- /dev/null +++ b/bios/seabios/tools/kconfig/lxdialog/yesno.c @@ -0,0 +1,114 @@ +/* + * yesno.c -- implements the yes/no box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "dialog.h" + +/* + * Display termination buttons + */ +static void print_buttons(WINDOW * dialog, int height, int width, int selected) +{ + int x = width / 2 - 10; + int y = height - 2; + + print_button(dialog, gettext(" Yes "), y, x, selected == 0); + print_button(dialog, gettext(" No "), y, x + 13, selected == 1); + + wmove(dialog, y, x + 1 + 13 * selected); + wrefresh(dialog); +} + +/* + * Display a dialog box with two buttons - Yes and No + */ +int dialog_yesno(const char *title, const char *prompt, int height, int width) +{ + int i, x, y, key = 0, button = 0; + WINDOW *dialog; + +do_resize: + if (getmaxy(stdscr) < (height + 4)) + return -ERRDISPLAYTOOSMALL; + if (getmaxx(stdscr) < (width + 4)) + return -ERRDISPLAYTOOSMALL; + + /* center dialog box on screen */ + x = (COLS - width) / 2; + y = (LINES - height) / 2; + + draw_shadow(stdscr, y, x, height, width); + + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + draw_box(dialog, 0, 0, height, width, + dlg.dialog.atr, dlg.border.atr); + wattrset(dialog, dlg.border.atr); + mvwaddch(dialog, height - 3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dlg.dialog.atr); + waddch(dialog, ACS_RTEE); + + print_title(dialog, title, width); + + wattrset(dialog, dlg.dialog.atr); + print_autowrap(dialog, prompt, width - 2, 1, 3); + + print_buttons(dialog, height, width, 0); + + while (key != KEY_ESC) { + key = wgetch(dialog); + switch (key) { + case 'Y': + case 'y': + delwin(dialog); + return 0; + case 'N': + case 'n': + delwin(dialog); + return 1; + + case TAB: + case KEY_LEFT: + case KEY_RIGHT: + button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button); + + print_buttons(dialog, height, width, button); + wrefresh(dialog); + break; + case ' ': + case '\n': + delwin(dialog); + return button; + case KEY_ESC: + key = on_key_esc(dialog); + break; + case KEY_RESIZE: + delwin(dialog); + on_key_resize(); + goto do_resize; + } + } + + delwin(dialog); + return key; /* ESC pressed */ +} diff --git a/bios/seabios/tools/kconfig/mconf.c b/bios/seabios/tools/kconfig/mconf.c new file mode 100644 index 0000000..d433c7a --- /dev/null +++ b/bios/seabios/tools/kconfig/mconf.c @@ -0,0 +1,862 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + * + * Introduced single menu mode (show all sub-menus in one large tree). + * 2002-11-06 Petr Baudis + * + * i18n, 2005, Arnaldo Carvalho de Melo + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" +#include "lxdialog/dialog.h" + +static const char mconf_readme[] = N_( +"Overview\n" +"--------\n" +"This interface let you select features and parameters for the build.\n" +"Features can either be built-in, modularized, or ignored. Parameters\n" +"must be entered in as decimal or hexadecimal numbers or text.\n" +"\n" +"Menu items beginning with following braces represent features that\n" +" [ ] can be built in or removed\n" +" < > can be built in, modularized or removed\n" +" { } can be built in or modularized (selected by other feature)\n" +" - - are selected by other feature,\n" +"while *, M or whitespace inside braces means to build in, build as\n" +"a module or to exclude the feature respectively.\n" +"\n" +"To change any of these features, highlight it with the cursor\n" +"keys and press to build it in, to make it a module or\n" +" to removed it. You may also press the to cycle\n" +"through the available options (ie. Y->N->M->Y).\n" +"\n" +"Some additional keyboard hints:\n" +"\n" +"Menus\n" +"----------\n" +"o Use the Up/Down arrow keys (cursor keys) to highlight the item\n" +" you wish to change or submenu wish to select and press .\n" +" Submenus are designated by \"--->\".\n" +"\n" +" Shortcut: Press the option's highlighted letter (hotkey).\n" +" Pressing a hotkey more than once will sequence\n" +" through all visible items which use that hotkey.\n" +"\n" +" You may also use the and keys to scroll\n" +" unseen options into view.\n" +"\n" +"o To exit a menu use the cursor keys to highlight the button\n" +" and press .\n" +"\n" +" Shortcut: Press or or if there is no hotkey\n" +" using those letters. You may press a single , but\n" +" there is a delayed response which you may find annoying.\n" +"\n" +" Also, the and cursor keys will cycle between and\n" +" \n" +"\n" +"\n" +"Data Entry\n" +"-----------\n" +"o Enter the requested information and press \n" +" If you are entering hexadecimal values, it is not necessary to\n" +" add the '0x' prefix to the entry.\n" +"\n" +"o For help, use the or cursor keys to highlight the help option\n" +" and press . You can try as well.\n" +"\n" +"\n" +"Text Box (Help Window)\n" +"--------\n" +"o Use the cursor keys to scroll up/down/left/right. The VI editor\n" +" keys h,j,k,l function here as do and for those\n" +" who are familiar with less and lynx.\n" +"\n" +"o Press , , or to exit.\n" +"\n" +"\n" +"Alternate Configuration Files\n" +"-----------------------------\n" +"Menuconfig supports the use of alternate configuration files for\n" +"those who, for various reasons, find it necessary to switch\n" +"between different configurations.\n" +"\n" +"At the end of the main menu you will find two options. One is\n" +"for saving the current configuration to a file of your choosing.\n" +"The other option is for loading a previously saved alternate\n" +"configuration.\n" +"\n" +"Even if you don't use alternate configuration files, but you\n" +"find during a Menuconfig session that you have completely messed\n" +"up your settings, you may use the \"Load Alternate...\" option to\n" +"restore your previously saved settings from \".config\" without\n" +"restarting Menuconfig.\n" +"\n" +"Other information\n" +"-----------------\n" +"If you use Menuconfig in an XTERM window make sure you have your\n" +"$TERM variable set to point to a xterm definition which supports color.\n" +"Otherwise, Menuconfig will look rather bad. Menuconfig will not\n" +"display correctly in a RXVT window because rxvt displays only one\n" +"intensity of color, bright.\n" +"\n" +"Menuconfig will display larger menus on screens or xterms which are\n" +"set to display more than the standard 25 row by 80 column geometry.\n" +"In order for this to work, the \"stty size\" command must be able to\n" +"display the screen's current row and column geometry. I STRONGLY\n" +"RECOMMEND that you make sure you do NOT have the shell variables\n" +"LINES and COLUMNS exported into your environment. Some distributions\n" +"export those variables via /etc/profile. Some ncurses programs can\n" +"become confused when those variables (LINES & COLUMNS) don't reflect\n" +"the true screen size.\n" +"\n" +"Optional personality available\n" +"------------------------------\n" +"If you prefer to have all of the options listed in a single menu, rather\n" +"than the default multimenu hierarchy, run the menuconfig with\n" +"MENUCONFIG_MODE environment variable set to single_menu. Example:\n" +"\n" +"make MENUCONFIG_MODE=single_menu menuconfig\n" +"\n" +" will then unroll the appropriate category, or enfold it if it\n" +"is already unrolled.\n" +"\n" +"Note that this mode can eventually be a little more CPU expensive\n" +"(especially with a larger number of unrolled categories) than the\n" +"default mode.\n" +"\n" +"Different color themes available\n" +"--------------------------------\n" +"It is possible to select different color themes using the variable\n" +"MENUCONFIG_COLOR. To select a theme use:\n" +"\n" +"make MENUCONFIG_COLOR= menuconfig\n" +"\n" +"Available themes are\n" +" mono => selects colors suitable for monochrome displays\n" +" blackbg => selects a color scheme with black background\n" +" classic => theme with blue background. The classic look\n" +" bluetitle => a LCD friendly version of classic. (default)\n" +"\n"), +menu_instructions[] = N_( + "Arrow keys navigate the menu. " + " selects submenus --->. " + "Highlighted letters are hotkeys. " + "Pressing includes, excludes, modularizes features. " + "Press to exit, for Help, for Search. " + "Legend: [*] built-in [ ] excluded module < > module capable"), +radiolist_instructions[] = N_( + "Use the arrow keys to navigate this window or " + "press the hotkey of the item you wish to select " + "followed by the . " + "Press for additional information about this option."), +inputbox_instructions_int[] = N_( + "Please enter a decimal value. " + "Fractions will not be accepted. " + "Use the key to move from the input field to the buttons below it."), +inputbox_instructions_hex[] = N_( + "Please enter a hexadecimal value. " + "Use the key to move from the input field to the buttons below it."), +inputbox_instructions_string[] = N_( + "Please enter a string value. " + "Use the key to move from the input field to the buttons below it."), +setmod_text[] = N_( + "This feature depends on another which has been configured as a module.\n" + "As a result, this feature will be built as a module."), +load_config_text[] = N_( + "Enter the name of the configuration file you wish to load. " + "Accept the name shown to restore the configuration you " + "last retrieved. Leave blank to abort."), +load_config_help[] = N_( + "\n" + "For various reasons, one may wish to keep several different\n" + "configurations available on a single machine.\n" + "\n" + "If you have saved a previous configuration in a file other than the\n" + "default one, entering its name here will allow you to modify that\n" + "configuration.\n" + "\n" + "If you are uncertain, then you have probably never used alternate\n" + "configuration files. You should therefore leave this blank to abort.\n"), +save_config_text[] = N_( + "Enter a filename to which this configuration should be saved " + "as an alternate. Leave blank to abort."), +save_config_help[] = N_( + "\n" + "For various reasons, one may wish to keep different configurations\n" + "available on a single machine.\n" + "\n" + "Entering a file name here will allow you to later retrieve, modify\n" + "and use the current configuration as an alternate to whatever\n" + "configuration options you have selected at that time.\n" + "\n" + "If you are uncertain what all this means then you should probably\n" + "leave this blank.\n"), +search_help[] = N_( + "\n" + "Search for symbols and display their relations.\n" + "Regular expressions are allowed.\n" + "Example: search for \"^FOO\"\n" + "Result:\n" + "-----------------------------------------------------------------\n" + "Symbol: FOO [=m]\n" + "Prompt: Foo bus is used to drive the bar HW\n" + "Defined at drivers/pci/Kconfig:47\n" + "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" + "Location:\n" + " -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n" + " -> PCI support (PCI [=y])\n" + " -> PCI access mode ( [=y])\n" + "Selects: LIBCRC32\n" + "Selected by: BAR\n" + "-----------------------------------------------------------------\n" + "o The line 'Prompt:' shows the text used in the menu structure for\n" + " this symbol\n" + "o The 'Defined at' line tell at what file / line number the symbol\n" + " is defined\n" + "o The 'Depends on:' line tell what symbols needs to be defined for\n" + " this symbol to be visible in the menu (selectable)\n" + "o The 'Location:' lines tell where in the menu structure this symbol\n" + " is located\n" + " A location followed by a [=y] indicate that this is a selectable\n" + " menu item - and current value is displayed inside brackets.\n" + "o The 'Selects:' line tell what symbol will be automatically\n" + " selected if this symbol is selected (y or m)\n" + "o The 'Selected by' line tell what symbol has selected this symbol\n" + "\n" + "Only relevant lines are shown.\n" + "\n\n" + "Search examples:\n" + "Examples: USB => find all symbols containing USB\n" + " ^USB => find all symbols starting with USB\n" + " USB$ => find all symbols ending with USB\n" + "\n"); + +static int indent; +static struct menu *current_menu; +static int child_count; +static int single_menu_mode; +static int show_all_options; + +static void conf(struct menu *menu); +static void conf_choice(struct menu *menu); +static void conf_string(struct menu *menu); +static void conf_load(void); +static void conf_save(void); +static void show_textbox(const char *title, const char *text, int r, int c); +static void show_helptext(const char *title, const char *text); +static void show_help(struct menu *menu); + +static char filename[PATH_MAX+1]; +static void set_config_filename(const char *config_filename) +{ + static char menu_backtitle[PATH_MAX+128]; + int size; + + size = snprintf(menu_backtitle, sizeof(menu_backtitle), + "%s - %s", config_filename, rootmenu.prompt->text); + if (size >= sizeof(menu_backtitle)) + menu_backtitle[sizeof(menu_backtitle)-1] = '\0'; + set_dialog_backtitle(menu_backtitle); + + size = snprintf(filename, sizeof(filename), "%s", config_filename); + if (size >= sizeof(filename)) + filename[sizeof(filename)-1] = '\0'; +} + + +static void search_conf(void) +{ + struct symbol **sym_arr; + struct gstr res; + char *dialog_input; + int dres; +again: + dialog_clear(); + dres = dialog_inputbox(_("Search Configuration Parameter"), + _("Enter " CONFIG_ " (sub)string to search for " + "(with or without \"" CONFIG_ "\")"), + 10, 75, ""); + switch (dres) { + case 0: + break; + case 1: + show_helptext(_("Search Configuration"), search_help); + goto again; + default: + return; + } + + /* strip the prefix if necessary */ + dialog_input = dialog_input_result; + if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0) + dialog_input += strlen(CONFIG_); + + sym_arr = sym_re_search(dialog_input); + res = get_relations_str(sym_arr); + free(sym_arr); + show_textbox(_("Search Results"), str_get(&res), 0, 0); + str_free(&res); +} + +static void build_conf(struct menu *menu) +{ + struct symbol *sym; + struct property *prop; + struct menu *child; + int type, tmp, doint = 2; + tristate val; + char ch; + bool visible; + + /* + * note: menu_is_visible() has side effect that it will + * recalc the value of the symbol. + */ + visible = menu_is_visible(menu); + if (show_all_options && !menu_has_prompt(menu)) + return; + else if (!show_all_options && !visible) + return; + + sym = menu->sym; + prop = menu->prompt; + if (!sym) { + if (prop && menu != current_menu) { + const char *prompt = menu_get_prompt(menu); + switch (prop->type) { + case P_MENU: + child_count++; + prompt = _(prompt); + if (single_menu_mode) { + item_make("%s%*c%s", + menu->data ? "-->" : "++>", + indent + 1, ' ', prompt); + } else + item_make(" %*c%s --->", indent + 1, ' ', prompt); + + item_set_tag('m'); + item_set_data(menu); + if (single_menu_mode && menu->data) + goto conf_childs; + return; + case P_COMMENT: + if (prompt) { + child_count++; + item_make(" %*c*** %s ***", indent + 1, ' ', _(prompt)); + item_set_tag(':'); + item_set_data(menu); + } + break; + default: + if (prompt) { + child_count++; + item_make("---%*c%s", indent + 1, ' ', _(prompt)); + item_set_tag(':'); + item_set_data(menu); + } + } + } else + doint = 0; + goto conf_childs; + } + + type = sym_get_type(sym); + if (sym_is_choice(sym)) { + struct symbol *def_sym = sym_get_choice_value(sym); + struct menu *def_menu = NULL; + + child_count++; + for (child = menu->list; child; child = child->next) { + if (menu_is_visible(child) && child->sym == def_sym) + def_menu = child; + } + + val = sym_get_tristate_value(sym); + if (sym_is_changable(sym)) { + switch (type) { + case S_BOOLEAN: + item_make("[%c]", val == no ? ' ' : '*'); + break; + case S_TRISTATE: + switch (val) { + case yes: ch = '*'; break; + case mod: ch = 'M'; break; + default: ch = ' '; break; + } + item_make("<%c>", ch); + break; + } + item_set_tag('t'); + item_set_data(menu); + } else { + item_make(" "); + item_set_tag(def_menu ? 't' : ':'); + item_set_data(menu); + } + + item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu))); + if (val == yes) { + if (def_menu) { + item_add_str(" (%s)", _(menu_get_prompt(def_menu))); + item_add_str(" --->"); + if (def_menu->list) { + indent += 2; + build_conf(def_menu); + indent -= 2; + } + } + return; + } + } else { + if (menu == current_menu) { + item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu))); + item_set_tag(':'); + item_set_data(menu); + goto conf_childs; + } + child_count++; + val = sym_get_tristate_value(sym); + if (sym_is_choice_value(sym) && val == yes) { + item_make(" "); + item_set_tag(':'); + item_set_data(menu); + } else { + switch (type) { + case S_BOOLEAN: + if (sym_is_changable(sym)) + item_make("[%c]", val == no ? ' ' : '*'); + else + item_make("-%c-", val == no ? ' ' : '*'); + item_set_tag('t'); + item_set_data(menu); + break; + case S_TRISTATE: + switch (val) { + case yes: ch = '*'; break; + case mod: ch = 'M'; break; + default: ch = ' '; break; + } + if (sym_is_changable(sym)) { + if (sym->rev_dep.tri == mod) + item_make("{%c}", ch); + else + item_make("<%c>", ch); + } else + item_make("-%c-", ch); + item_set_tag('t'); + item_set_data(menu); + break; + default: + tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */ + item_make("(%s)", sym_get_string_value(sym)); + tmp = indent - tmp + 4; + if (tmp < 0) + tmp = 0; + item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)), + (sym_has_value(sym) || !sym_is_changable(sym)) ? + "" : _(" (NEW)")); + item_set_tag('s'); + item_set_data(menu); + goto conf_childs; + } + } + item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)), + (sym_has_value(sym) || !sym_is_changable(sym)) ? + "" : _(" (NEW)")); + if (menu->prompt->type == P_MENU) { + item_add_str(" --->"); + return; + } + } + +conf_childs: + indent += doint; + for (child = menu->list; child; child = child->next) + build_conf(child); + indent -= doint; +} + +static void conf(struct menu *menu) +{ + struct menu *submenu; + const char *prompt = menu_get_prompt(menu); + struct symbol *sym; + struct menu *active_menu = NULL; + int res; + int s_scroll = 0; + + while (1) { + item_reset(); + current_menu = menu; + build_conf(menu); + if (!child_count) + break; + if (menu == &rootmenu) { + item_make("--- "); + item_set_tag(':'); + item_make(_(" Load an Alternate Configuration File")); + item_set_tag('L'); + item_make(_(" Save an Alternate Configuration File")); + item_set_tag('S'); + } + dialog_clear(); + res = dialog_menu(prompt ? _(prompt) : _("Main Menu"), + _(menu_instructions), + active_menu, &s_scroll); + if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL) + break; + if (!item_activate_selected()) + continue; + if (!item_tag()) + continue; + + submenu = item_data(); + active_menu = item_data(); + if (submenu) + sym = submenu->sym; + else + sym = NULL; + + switch (res) { + case 0: + switch (item_tag()) { + case 'm': + if (single_menu_mode) + submenu->data = (void *) (long) !submenu->data; + else + conf(submenu); + break; + case 't': + if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) + conf_choice(submenu); + else if (submenu->prompt->type == P_MENU) + conf(submenu); + break; + case 's': + conf_string(submenu); + break; + case 'L': + conf_load(); + break; + case 'S': + conf_save(); + break; + } + break; + case 2: + if (sym) + show_help(submenu); + else + show_helptext(_("README"), _(mconf_readme)); + break; + case 3: + if (item_is_tag('t')) { + if (sym_set_tristate_value(sym, yes)) + break; + if (sym_set_tristate_value(sym, mod)) + show_textbox(NULL, setmod_text, 6, 74); + } + break; + case 4: + if (item_is_tag('t')) + sym_set_tristate_value(sym, no); + break; + case 5: + if (item_is_tag('t')) + sym_set_tristate_value(sym, mod); + break; + case 6: + if (item_is_tag('t')) + sym_toggle_tristate_value(sym); + else if (item_is_tag('m')) + conf(submenu); + break; + case 7: + search_conf(); + break; + case 8: + show_all_options = !show_all_options; + break; + } + } +} + +static void show_textbox(const char *title, const char *text, int r, int c) +{ + dialog_clear(); + dialog_textbox(title, text, r, c); +} + +static void show_helptext(const char *title, const char *text) +{ + show_textbox(title, text, 0, 0); +} + +static void show_help(struct menu *menu) +{ + struct gstr help = str_new(); + + help.max_width = getmaxx(stdscr) - 10; + menu_get_ext_help(menu, &help); + + show_helptext(_(menu_get_prompt(menu)), str_get(&help)); + str_free(&help); +} + +static void conf_choice(struct menu *menu) +{ + const char *prompt = _(menu_get_prompt(menu)); + struct menu *child; + struct symbol *active; + + active = sym_get_choice_value(menu->sym); + while (1) { + int res; + int selected; + item_reset(); + + current_menu = menu; + for (child = menu->list; child; child = child->next) { + if (!menu_is_visible(child)) + continue; + if (child->sym) + item_make("%s", _(menu_get_prompt(child))); + else { + item_make("*** %s ***", _(menu_get_prompt(child))); + item_set_tag(':'); + } + item_set_data(child); + if (child->sym == active) + item_set_selected(1); + if (child->sym == sym_get_choice_value(menu->sym)) + item_set_tag('X'); + } + dialog_clear(); + res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"), + _(radiolist_instructions), + 15, 70, 6); + selected = item_activate_selected(); + switch (res) { + case 0: + if (selected) { + child = item_data(); + if (!child->sym) + break; + + sym_set_tristate_value(child->sym, yes); + } + return; + case 1: + if (selected) { + child = item_data(); + show_help(child); + active = child->sym; + } else + show_help(menu); + break; + case KEY_ESC: + return; + case -ERRDISPLAYTOOSMALL: + return; + } + } +} + +static void conf_string(struct menu *menu) +{ + const char *prompt = menu_get_prompt(menu); + + while (1) { + int res; + const char *heading; + + switch (sym_get_type(menu->sym)) { + case S_INT: + heading = _(inputbox_instructions_int); + break; + case S_HEX: + heading = _(inputbox_instructions_hex); + break; + case S_STRING: + heading = _(inputbox_instructions_string); + break; + default: + heading = _("Internal mconf error!"); + } + dialog_clear(); + res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"), + heading, 10, 75, + sym_get_string_value(menu->sym)); + switch (res) { + case 0: + if (sym_set_string_value(menu->sym, dialog_input_result)) + return; + show_textbox(NULL, _("You have made an invalid entry."), 5, 43); + break; + case 1: + show_help(menu); + break; + case KEY_ESC: + return; + } + } +} + +static void conf_load(void) +{ + + while (1) { + int res; + dialog_clear(); + res = dialog_inputbox(NULL, load_config_text, + 11, 55, filename); + switch(res) { + case 0: + if (!dialog_input_result[0]) + return; + if (!conf_read(dialog_input_result)) { + set_config_filename(dialog_input_result); + sym_set_change_count(1); + return; + } + show_textbox(NULL, _("File does not exist!"), 5, 38); + break; + case 1: + show_helptext(_("Load Alternate Configuration"), load_config_help); + break; + case KEY_ESC: + return; + } + } +} + +static void conf_save(void) +{ + while (1) { + int res; + dialog_clear(); + res = dialog_inputbox(NULL, save_config_text, + 11, 55, filename); + switch(res) { + case 0: + if (!dialog_input_result[0]) + return; + if (!conf_write(dialog_input_result)) { + set_config_filename(dialog_input_result); + return; + } + show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60); + break; + case 1: + show_helptext(_("Save Alternate Configuration"), save_config_help); + break; + case KEY_ESC: + return; + } + } +} + +int main(int ac, char **av) +{ + int saved_x, saved_y; + char *mode; + int res; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + conf_parse(av[1]); + conf_read(NULL); + + mode = getenv("MENUCONFIG_MODE"); + if (mode) { + if (!strcasecmp(mode, "single_menu")) + single_menu_mode = 1; + } + + initscr(); + + getyx(stdscr, saved_y, saved_x); + if (init_dialog(NULL)) { + fprintf(stderr, N_("Your display is too small to run Menuconfig!\n")); + fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n")); + return 1; + } + + set_config_filename(conf_get_configname()); + do { + conf(&rootmenu); + dialog_clear(); + if (conf_get_changed()) + res = dialog_yesno(NULL, + _("Do you wish to save your " + "new configuration?\n" + " to continue."), + 6, 60); + else + res = -1; + } while (res == KEY_ESC); + end_dialog(saved_x, saved_y); + + switch (res) { + case 0: + if (conf_write(filename)) { + fprintf(stderr, _("\n\n" + "Error while writing of the configuration.\n" + "Your configuration changes were NOT saved." + "\n\n")); + return 1; + } + case -1: + printf(_("\n\n" + "*** End of the configuration.\n" + "*** Execute 'make' to start the build or try 'make help'." + "\n\n")); + break; + default: + fprintf(stderr, _("\n\n" + "Your configuration changes were NOT saved." + "\n\n")); + } + + return 0; +} + diff --git a/bios/seabios/tools/kconfig/menu.c b/bios/seabios/tools/kconfig/menu.c new file mode 100644 index 0000000..5fdf10d --- /dev/null +++ b/bios/seabios/tools/kconfig/menu.c @@ -0,0 +1,609 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +static const char nohelp_text[] = N_( + "There is no help available for this option.\n"); + +struct menu rootmenu; +static struct menu **last_entry_ptr; + +struct file *file_list; +struct file *current_file; + +void menu_warn(struct menu *menu, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +static void prop_warn(struct property *prop, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +void _menu_init(void) +{ + current_entry = current_menu = &rootmenu; + last_entry_ptr = &rootmenu.list; +} + +void menu_add_entry(struct symbol *sym) +{ + struct menu *menu; + + menu = malloc(sizeof(*menu)); + memset(menu, 0, sizeof(*menu)); + menu->sym = sym; + menu->parent = current_menu; + menu->file = current_file; + menu->lineno = zconf_lineno(); + + *last_entry_ptr = menu; + last_entry_ptr = &menu->next; + current_entry = menu; + if (sym) + menu_add_symbol(P_SYMBOL, sym, NULL); +} + +void menu_end_entry(void) +{ +} + +struct menu *menu_add_menu(void) +{ + menu_end_entry(); + last_entry_ptr = ¤t_entry->list; + return current_menu = current_entry; +} + +void menu_end_menu(void) +{ + last_entry_ptr = ¤t_menu->next; + current_menu = current_menu->parent; +} + +static struct expr *menu_check_dep(struct expr *e) +{ + if (!e) + return e; + + switch (e->type) { + case E_NOT: + e->left.expr = menu_check_dep(e->left.expr); + break; + case E_OR: + case E_AND: + e->left.expr = menu_check_dep(e->left.expr); + e->right.expr = menu_check_dep(e->right.expr); + break; + case E_SYMBOL: + /* change 'm' into 'm' && MODULES */ + if (e->left.sym == &symbol_mod) + return expr_alloc_and(e, expr_alloc_symbol(modules_sym)); + break; + default: + break; + } + return e; +} + +void menu_add_dep(struct expr *dep) +{ + current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep)); +} + +void menu_set_type(int type) +{ + struct symbol *sym = current_entry->sym; + + if (sym->type == type) + return; + if (sym->type == S_UNKNOWN) { + sym->type = type; + return; + } + menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'", + sym->name ? sym->name : "", + sym_type_name(sym->type), sym_type_name(type)); +} + +struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep) +{ + struct property *prop = prop_alloc(type, current_entry->sym); + + prop->menu = current_entry; + prop->expr = expr; + prop->visible.expr = menu_check_dep(dep); + + if (prompt) { + if (isspace(*prompt)) { + prop_warn(prop, "leading whitespace ignored"); + while (isspace(*prompt)) + prompt++; + } + if (current_entry->prompt && current_entry != &rootmenu) + prop_warn(prop, "prompt redefined"); + + /* Apply all upper menus' visibilities to actual prompts. */ + if(type == P_PROMPT) { + struct menu *menu = current_entry; + + while ((menu = menu->parent) != NULL) { + if (!menu->visibility) + continue; + prop->visible.expr + = expr_alloc_and(prop->visible.expr, + menu->visibility); + } + } + + current_entry->prompt = prop; + } + prop->text = prompt; + + return prop; +} + +struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep) +{ + return menu_add_prop(type, prompt, NULL, dep); +} + +void menu_add_visibility(struct expr *expr) +{ + current_entry->visibility = expr_alloc_and(current_entry->visibility, + expr); +} + +void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep) +{ + menu_add_prop(type, NULL, expr, dep); +} + +void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep) +{ + menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep); +} + +void menu_add_option(int token, char *arg) +{ + struct property *prop; + + switch (token) { + case T_OPT_MODULES: + prop = prop_alloc(P_DEFAULT, modules_sym); + prop->expr = expr_alloc_symbol(current_entry->sym); + break; + case T_OPT_DEFCONFIG_LIST: + if (!sym_defconfig_list) + sym_defconfig_list = current_entry->sym; + else if (sym_defconfig_list != current_entry->sym) + zconf_error("trying to redefine defconfig symbol"); + break; + case T_OPT_ENV: + prop_add_env(arg); + break; + } +} + +static int menu_validate_number(struct symbol *sym, struct symbol *sym2) +{ + return sym2->type == S_INT || sym2->type == S_HEX || + (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name)); +} + +static void sym_check_prop(struct symbol *sym) +{ + struct property *prop; + struct symbol *sym2; + for (prop = sym->prop; prop; prop = prop->next) { + switch (prop->type) { + case P_DEFAULT: + if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) && + prop->expr->type != E_SYMBOL) + prop_warn(prop, + "default for config symbol '%s'" + " must be a single symbol", sym->name); + if (prop->expr->type != E_SYMBOL) + break; + sym2 = prop_get_symbol(prop); + if (sym->type == S_HEX || sym->type == S_INT) { + if (!menu_validate_number(sym, sym2)) + prop_warn(prop, + "'%s': number is invalid", + sym->name); + } + break; + case P_SELECT: + sym2 = prop_get_symbol(prop); + if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE) + prop_warn(prop, + "config symbol '%s' uses select, but is " + "not boolean or tristate", sym->name); + else if (sym2->type != S_UNKNOWN && + sym2->type != S_BOOLEAN && + sym2->type != S_TRISTATE) + prop_warn(prop, + "'%s' has wrong type. 'select' only " + "accept arguments of boolean and " + "tristate type", sym2->name); + break; + case P_RANGE: + if (sym->type != S_INT && sym->type != S_HEX) + prop_warn(prop, "range is only allowed " + "for int or hex symbols"); + if (!menu_validate_number(sym, prop->expr->left.sym) || + !menu_validate_number(sym, prop->expr->right.sym)) + prop_warn(prop, "range is invalid"); + break; + default: + ; + } + } +} + +void menu_finalize(struct menu *parent) +{ + struct menu *menu, *last_menu; + struct symbol *sym; + struct property *prop; + struct expr *parentdep, *basedep, *dep, *dep2, **ep; + + sym = parent->sym; + if (parent->list) { + if (sym && sym_is_choice(sym)) { + if (sym->type == S_UNKNOWN) { + /* find the first choice value to find out choice type */ + current_entry = parent; + for (menu = parent->list; menu; menu = menu->next) { + if (menu->sym && menu->sym->type != S_UNKNOWN) { + menu_set_type(menu->sym->type); + break; + } + } + } + /* set the type of the remaining choice values */ + for (menu = parent->list; menu; menu = menu->next) { + current_entry = menu; + if (menu->sym && menu->sym->type == S_UNKNOWN) + menu_set_type(sym->type); + } + parentdep = expr_alloc_symbol(sym); + } else if (parent->prompt) + parentdep = parent->prompt->visible.expr; + else + parentdep = parent->dep; + + for (menu = parent->list; menu; menu = menu->next) { + basedep = expr_transform(menu->dep); + basedep = expr_alloc_and(expr_copy(parentdep), basedep); + basedep = expr_eliminate_dups(basedep); + menu->dep = basedep; + if (menu->sym) + prop = menu->sym->prop; + else + prop = menu->prompt; + for (; prop; prop = prop->next) { + if (prop->menu != menu) + continue; + dep = expr_transform(prop->visible.expr); + dep = expr_alloc_and(expr_copy(basedep), dep); + dep = expr_eliminate_dups(dep); + if (menu->sym && menu->sym->type != S_TRISTATE) + dep = expr_trans_bool(dep); + prop->visible.expr = dep; + if (prop->type == P_SELECT) { + struct symbol *es = prop_get_symbol(prop); + es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, + expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); + } + } + } + for (menu = parent->list; menu; menu = menu->next) + menu_finalize(menu); + } else if (sym) { + basedep = parent->prompt ? parent->prompt->visible.expr : NULL; + basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); + basedep = expr_eliminate_dups(expr_transform(basedep)); + last_menu = NULL; + for (menu = parent->next; menu; menu = menu->next) { + dep = menu->prompt ? menu->prompt->visible.expr : menu->dep; + if (!expr_contains_symbol(dep, sym)) + break; + if (expr_depends_symbol(dep, sym)) + goto next; + dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no); + dep = expr_eliminate_dups(expr_transform(dep)); + dep2 = expr_copy(basedep); + expr_eliminate_eq(&dep, &dep2); + expr_free(dep); + if (!expr_is_yes(dep2)) { + expr_free(dep2); + break; + } + expr_free(dep2); + next: + menu_finalize(menu); + menu->parent = parent; + last_menu = menu; + } + if (last_menu) { + parent->list = parent->next; + parent->next = last_menu->next; + last_menu->next = NULL; + } + + sym->dir_dep.expr = parent->dep; + } + for (menu = parent->list; menu; menu = menu->next) { + if (sym && sym_is_choice(sym) && + menu->sym && !sym_is_choice_value(menu->sym)) { + current_entry = menu; + menu->sym->flags |= SYMBOL_CHOICEVAL; + if (!menu->prompt) + menu_warn(menu, "choice value must have a prompt"); + for (prop = menu->sym->prop; prop; prop = prop->next) { + if (prop->type == P_DEFAULT) + prop_warn(prop, "defaults for choice " + "values not supported"); + if (prop->menu == menu) + continue; + if (prop->type == P_PROMPT && + prop->menu->parent->sym != sym) + prop_warn(prop, "choice value used outside its choice group"); + } + /* Non-tristate choice values of tristate choices must + * depend on the choice being set to Y. The choice + * values' dependencies were propagated to their + * properties above, so the change here must be re- + * propagated. + */ + if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) { + basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes); + menu->dep = expr_alloc_and(basedep, menu->dep); + for (prop = menu->sym->prop; prop; prop = prop->next) { + if (prop->menu != menu) + continue; + prop->visible.expr = expr_alloc_and(expr_copy(basedep), + prop->visible.expr); + } + } + menu_add_symbol(P_CHOICE, sym, NULL); + prop = sym_get_choice_prop(sym); + for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr) + ; + *ep = expr_alloc_one(E_LIST, NULL); + (*ep)->right.sym = menu->sym; + } + if (menu->list && (!menu->prompt || !menu->prompt->text)) { + for (last_menu = menu->list; ; last_menu = last_menu->next) { + last_menu->parent = parent; + if (!last_menu->next) + break; + } + last_menu->next = menu->next; + menu->next = menu->list; + menu->list = NULL; + } + } + + if (sym && !(sym->flags & SYMBOL_WARNED)) { + if (sym->type == S_UNKNOWN) + menu_warn(parent, "config symbol defined without type"); + + if (sym_is_choice(sym) && !parent->prompt) + menu_warn(parent, "choice must have a prompt"); + + /* Check properties connected to this symbol */ + sym_check_prop(sym); + sym->flags |= SYMBOL_WARNED; + } + + if (sym && !sym_is_optional(sym) && parent->prompt) { + sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr, + expr_alloc_and(parent->prompt->visible.expr, + expr_alloc_symbol(&symbol_mod))); + } +} + +bool menu_has_prompt(struct menu *menu) +{ + if (!menu->prompt) + return false; + return true; +} + +bool menu_is_visible(struct menu *menu) +{ + struct menu *child; + struct symbol *sym; + tristate visible; + + if (!menu->prompt) + return false; + + if (menu->visibility) { + if (expr_calc_value(menu->visibility) == no) + return no; + } + + sym = menu->sym; + if (sym) { + sym_calc_value(sym); + visible = menu->prompt->visible.tri; + } else + visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr); + + if (visible != no) + return true; + + if (!sym || sym_get_tristate_value(menu->sym) == no) + return false; + + for (child = menu->list; child; child = child->next) { + if (menu_is_visible(child)) { + if (sym) + sym->flags |= SYMBOL_DEF_USER; + return true; + } + } + + return false; +} + +const char *menu_get_prompt(struct menu *menu) +{ + if (menu->prompt) + return menu->prompt->text; + else if (menu->sym) + return menu->sym->name; + return NULL; +} + +struct menu *menu_get_root_menu(struct menu *menu) +{ + return &rootmenu; +} + +struct menu *menu_get_parent_menu(struct menu *menu) +{ + enum prop_type type; + + for (; menu != &rootmenu; menu = menu->parent) { + type = menu->prompt ? menu->prompt->type : 0; + if (type == P_MENU) + break; + } + return menu; +} + +bool menu_has_help(struct menu *menu) +{ + return menu->help != NULL; +} + +const char *menu_get_help(struct menu *menu) +{ + if (menu->help) + return menu->help; + else + return ""; +} + +static void get_prompt_str(struct gstr *r, struct property *prop) +{ + int i, j; + struct menu *submenu[8], *menu; + + str_printf(r, _("Prompt: %s\n"), _(prop->text)); + str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name, + prop->menu->lineno); + if (!expr_is_yes(prop->visible.expr)) { + str_append(r, _(" Depends on: ")); + expr_gstr_print(prop->visible.expr, r); + str_append(r, "\n"); + } + menu = prop->menu->parent; + for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) + submenu[i++] = menu; + if (i > 0) { + str_printf(r, _(" Location:\n")); + for (j = 4; --i >= 0; j += 2) { + menu = submenu[i]; + str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu))); + if (menu->sym) { + str_printf(r, " (%s [=%s])", menu->sym->name ? + menu->sym->name : _(""), + sym_get_string_value(menu->sym)); + } + str_append(r, "\n"); + } + } +} + +void get_symbol_str(struct gstr *r, struct symbol *sym) +{ + bool hit; + struct property *prop; + + if (sym && sym->name) { + str_printf(r, "Symbol: %s [=%s]\n", sym->name, + sym_get_string_value(sym)); + str_printf(r, "Type : %s\n", sym_type_name(sym->type)); + if (sym->type == S_INT || sym->type == S_HEX) { + prop = sym_get_range_prop(sym); + if (prop) { + str_printf(r, "Range : "); + expr_gstr_print(prop->expr, r); + str_append(r, "\n"); + } + } + } + for_all_prompts(sym, prop) + get_prompt_str(r, prop); + hit = false; + for_all_properties(sym, prop, P_SELECT) { + if (!hit) { + str_append(r, " Selects: "); + hit = true; + } else + str_printf(r, " && "); + expr_gstr_print(prop->expr, r); + } + if (hit) + str_append(r, "\n"); + if (sym->rev_dep.expr) { + str_append(r, _(" Selected by: ")); + expr_gstr_print(sym->rev_dep.expr, r); + str_append(r, "\n"); + } + str_append(r, "\n\n"); +} + +struct gstr get_relations_str(struct symbol **sym_arr) +{ + struct symbol *sym; + struct gstr res = str_new(); + int i; + + for (i = 0; sym_arr && (sym = sym_arr[i]); i++) + get_symbol_str(&res, sym); + if (!i) + str_append(&res, _("No matches found.\n")); + return res; +} + + +void menu_get_ext_help(struct menu *menu, struct gstr *help) +{ + struct symbol *sym = menu->sym; + + if (menu_has_help(menu)) { + if (sym->name) { + str_printf(help, "%s%s:\n\n", CONFIG_, sym->name); + str_append(help, _(menu_get_help(menu))); + str_append(help, "\n"); + } + } else { + str_append(help, nohelp_text); + } + if (sym) + get_symbol_str(help, sym); +} diff --git a/bios/seabios/tools/kconfig/nconf.c b/bios/seabios/tools/kconfig/nconf.c new file mode 100644 index 0000000..db56377 --- /dev/null +++ b/bios/seabios/tools/kconfig/nconf.c @@ -0,0 +1,1561 @@ +/* + * Copyright (C) 2008 Nir Tzachar +#define LKC_DIRECT_LINK +#include "lkc.h" +#include "nconf.h" +#include + +static const char nconf_readme[] = N_( +"Overview\n" +"--------\n" +"This interface let you select features and parameters for the build.\n" +"Features can either be built-in, modularized, or ignored. Parameters\n" +"must be entered in as decimal or hexadecimal numbers or text.\n" +"\n" +"Menu items beginning with following braces represent features that\n" +" [ ] can be built in or removed\n" +" < > can be built in, modularized or removed\n" +" { } can be built in or modularized (selected by other feature)\n" +" - - are selected by other feature,\n" +" XXX cannot be selected. Use Symbol Info to find out why,\n" +"while *, M or whitespace inside braces means to build in, build as\n" +"a module or to exclude the feature respectively.\n" +"\n" +"To change any of these features, highlight it with the cursor\n" +"keys and press to build it in, to make it a module or\n" +" to removed it. You may also press the to cycle\n" +"through the available options (ie. Y->N->M->Y).\n" +"\n" +"Some additional keyboard hints:\n" +"\n" +"Menus\n" +"----------\n" +"o Use the Up/Down arrow keys (cursor keys) to highlight the item\n" +" you wish to change use or . Goto submenu by \n" +" pressing of . Use or to go back.\n" +" Submenus are designated by \"--->\".\n" +"\n" +" Searching: pressing '/' triggers interactive search mode.\n" +" nconfig performs a case insensitive search for the string\n" +" in the menu prompts (no regex support).\n" +" Pressing the up/down keys highlights the previous/next\n" +" matching item. Backspace removes one character from the\n" +" match string. Pressing either '/' again or ESC exits\n" +" search mode. All other keys behave normally.\n" +"\n" +" You may also use the and keys to scroll\n" +" unseen options into view.\n" +"\n" +"o To exit a menu use the just press or .\n" +"\n" +"o To get help with an item, press \n" +" Shortcut: Press or .\n" +"\n" +"\n" +"Radiolists (Choice lists)\n" +"-----------\n" +"o Use the cursor keys to select the option you wish to set and press\n" +" or the .\n" +"\n" +" Shortcut: Press the first letter of the option you wish to set then\n" +" press or .\n" +"\n" +"o To see available help for the item, press \n" +" Shortcut: Press or .\n" +"\n" +"\n" +"Data Entry\n" +"-----------\n" +"o Enter the requested information and press \n" +" If you are entering hexadecimal values, it is not necessary to\n" +" add the '0x' prefix to the entry.\n" +"\n" +"o For help, press .\n" +"\n" +"\n" +"Text Box (Help Window)\n" +"--------\n" +"o Use the cursor keys to scroll up/down/left/right. The VI editor\n" +" keys h,j,k,l function here as do for those\n" +" who are familiar with less and lynx.\n" +"\n" +"o Press , , , or to exit.\n" +"\n" +"\n" +"Alternate Configuration Files\n" +"-----------------------------\n" +"nconfig supports the use of alternate configuration files for\n" +"those who, for various reasons, find it necessary to switch\n" +"between different configurations.\n" +"\n" +"At the end of the main menu you will find two options. One is\n" +"for saving the current configuration to a file of your choosing.\n" +"The other option is for loading a previously saved alternate\n" +"configuration.\n" +"\n" +"Even if you don't use alternate configuration files, but you\n" +"find during a nconfig session that you have completely messed\n" +"up your settings, you may use the \"Load Alternate...\" option to\n" +"restore your previously saved settings from \".config\" without\n" +"restarting nconfig.\n" +"\n" +"Other information\n" +"-----------------\n" +"If you use nconfig in an XTERM window make sure you have your\n" +"$TERM variable set to point to a xterm definition which supports color.\n" +"Otherwise, nconfig will look rather bad. nconfig will not\n" +"display correctly in a RXVT window because rxvt displays only one\n" +"intensity of color, bright.\n" +"\n" +"nconfig will display larger menus on screens or xterms which are\n" +"set to display more than the standard 25 row by 80 column geometry.\n" +"In order for this to work, the \"stty size\" command must be able to\n" +"display the screen's current row and column geometry. I STRONGLY\n" +"RECOMMEND that you make sure you do NOT have the shell variables\n" +"LINES and COLUMNS exported into your environment. Some distributions\n" +"export those variables via /etc/profile. Some ncurses programs can\n" +"become confused when those variables (LINES & COLUMNS) don't reflect\n" +"the true screen size.\n" +"\n" +"Optional personality available\n" +"------------------------------\n" +"If you prefer to have all of the options listed in a single menu, rather\n" +"than the default multimenu hierarchy, run the nconfig with NCONFIG_MODE\n" +"environment variable set to single_menu. Example:\n" +"\n" +"make NCONFIG_MODE=single_menu nconfig\n" +"\n" +" will then unroll the appropriate category, or enfold it if it\n" +"is already unrolled.\n" +"\n" +"Note that this mode can eventually be a little more CPU expensive\n" +"(especially with a larger number of unrolled categories) than the\n" +"default mode.\n" +"\n"), +menu_no_f_instructions[] = N_( +" You do not have function keys support. Please follow the\n" +" following instructions:\n" +" Arrow keys navigate the menu.\n" +" or selects submenus --->.\n" +" Capital Letters are hotkeys.\n" +" Pressing includes, excludes, modularizes features.\n" +" Pressing SpaceBar toggles between the above options.\n" +" Press or to go back one menu,\n" +" or for Help, for Search.\n" +" <1> is interchangeable with , <2> with , etc.\n" +" Legend: [*] built-in [ ] excluded module < > module capable.\n" +" always leaves the current window.\n"), +menu_instructions[] = N_( +" Arrow keys navigate the menu.\n" +" or selects submenus --->.\n" +" Capital Letters are hotkeys.\n" +" Pressing includes, excludes, modularizes features.\n" +" Pressing SpaceBar toggles between the above options\n" +" Press , or to go back one menu,\n" +" , or for Help, for Search.\n" +" <1> is interchangeable with , <2> with , etc.\n" +" Legend: [*] built-in [ ] excluded module < > module capable.\n" +" always leaves the current window\n"), +radiolist_instructions[] = N_( +" Use the arrow keys to navigate this window or\n" +" press the hotkey of the item you wish to select\n" +" followed by the .\n" +" Press , or for additional information about this option.\n"), +inputbox_instructions_int[] = N_( +"Please enter a decimal value.\n" +"Fractions will not be accepted.\n" +"Press to accept, to cancel."), +inputbox_instructions_hex[] = N_( +"Please enter a hexadecimal value.\n" +"Press to accept, to cancel."), +inputbox_instructions_string[] = N_( +"Please enter a string value.\n" +"Press to accept, to cancel."), +setmod_text[] = N_( +"This feature depends on another which\n" +"has been configured as a module.\n" +"As a result, this feature will be built as a module."), +nohelp_text[] = N_( +"There is no help available for this option.\n"), +load_config_text[] = N_( +"Enter the name of the configuration file you wish to load.\n" +"Accept the name shown to restore the configuration you\n" +"last retrieved. Leave blank to abort."), +load_config_help[] = N_( +"\n" +"For various reasons, one may wish to keep several different\n" +"configurations available on a single machine.\n" +"\n" +"If you have saved a previous configuration in a file other than the\n" +"default one, entering its name here will allow you to modify that\n" +"configuration.\n" +"\n" +"If you are uncertain, then you have probably never used alternate\n" +"configuration files. You should therefor leave this blank to abort.\n"), +save_config_text[] = N_( +"Enter a filename to which this configuration should be saved\n" +"as an alternate. Leave blank to abort."), +save_config_help[] = N_( +"\n" +"For various reasons, one may wish to keep different configurations\n" +"available on a single machine.\n" +"\n" +"Entering a file name here will allow you to later retrieve, modify\n" +"and use the current configuration as an alternate to whatever\n" +"configuration options you have selected at that time.\n" +"\n" +"If you are uncertain what all this means then you should probably\n" +"leave this blank.\n"), +search_help[] = N_( +"\n" +"Search for symbols and display their relations. Regular expressions\n" +"are allowed.\n" +"Example: search for \"^FOO\"\n" +"Result:\n" +"-----------------------------------------------------------------\n" +"Symbol: FOO [ = m]\n" +"Prompt: Foo bus is used to drive the bar HW\n" +"Defined at drivers/pci/Kconfig:47\n" +"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" +"Location:\n" +" -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n" +" -> PCI support (PCI [ = y])\n" +" -> PCI access mode ( [ = y])\n" +"Selects: LIBCRC32\n" +"Selected by: BAR\n" +"-----------------------------------------------------------------\n" +"o The line 'Prompt:' shows the text used in the menu structure for\n" +" this symbol\n" +"o The 'Defined at' line tell at what file / line number the symbol\n" +" is defined\n" +"o The 'Depends on:' line tell what symbols needs to be defined for\n" +" this symbol to be visible in the menu (selectable)\n" +"o The 'Location:' lines tell where in the menu structure this symbol\n" +" is located\n" +" A location followed by a [ = y] indicate that this is a selectable\n" +" menu item - and current value is displayed inside brackets.\n" +"o The 'Selects:' line tell what symbol will be automatically\n" +" selected if this symbol is selected (y or m)\n" +"o The 'Selected by' line tell what symbol has selected this symbol\n" +"\n" +"Only relevant lines are shown.\n" +"\n\n" +"Search examples:\n" +"Examples: USB => find all symbols containing USB\n" +" ^USB => find all symbols starting with USB\n" +" USB$ => find all symbols ending with USB\n" +"\n"); + +struct mitem { + char str[256]; + char tag; + void *usrptr; + int is_visible; +}; + +#define MAX_MENU_ITEMS 4096 +static int show_all_items; +static int indent; +static struct menu *current_menu; +static int child_count; +static int single_menu_mode; +/* the window in which all information appears */ +static WINDOW *main_window; +/* the largest size of the menu window */ +static int mwin_max_lines; +static int mwin_max_cols; +/* the window in which we show option buttons */ +static MENU *curses_menu; +static ITEM *curses_menu_items[MAX_MENU_ITEMS]; +static struct mitem k_menu_items[MAX_MENU_ITEMS]; +static int items_num; +static int global_exit; +/* the currently selected button */ +const char *current_instructions = menu_instructions; + +static void conf(struct menu *menu); +static void conf_choice(struct menu *menu); +static void conf_string(struct menu *menu); +static void conf_load(void); +static void conf_save(void); +static void show_help(struct menu *menu); +static int do_exit(void); +static void setup_windows(void); +static void search_conf(void); + +typedef void (*function_key_handler_t)(int *key, struct menu *menu); +static void handle_f1(int *key, struct menu *current_item); +static void handle_f2(int *key, struct menu *current_item); +static void handle_f3(int *key, struct menu *current_item); +static void handle_f4(int *key, struct menu *current_item); +static void handle_f5(int *key, struct menu *current_item); +static void handle_f6(int *key, struct menu *current_item); +static void handle_f7(int *key, struct menu *current_item); +static void handle_f8(int *key, struct menu *current_item); +static void handle_f9(int *key, struct menu *current_item); + +struct function_keys { + const char *key_str; + const char *func; + function_key key; + function_key_handler_t handler; +}; + +static const int function_keys_num = 9; +struct function_keys function_keys[] = { + { + .key_str = "F1", + .func = "Help", + .key = F_HELP, + .handler = handle_f1, + }, + { + .key_str = "F2", + .func = "Sym Info", + .key = F_SYMBOL, + .handler = handle_f2, + }, + { + .key_str = "F3", + .func = "Insts", + .key = F_INSTS, + .handler = handle_f3, + }, + { + .key_str = "F4", + .func = "Config", + .key = F_CONF, + .handler = handle_f4, + }, + { + .key_str = "F5", + .func = "Back", + .key = F_BACK, + .handler = handle_f5, + }, + { + .key_str = "F6", + .func = "Save", + .key = F_SAVE, + .handler = handle_f6, + }, + { + .key_str = "F7", + .func = "Load", + .key = F_LOAD, + .handler = handle_f7, + }, + { + .key_str = "F8", + .func = "Sym Search", + .key = F_SEARCH, + .handler = handle_f8, + }, + { + .key_str = "F9", + .func = "Exit", + .key = F_EXIT, + .handler = handle_f9, + }, +}; + +static void print_function_line(void) +{ + int i; + int offset = 1; + const int skip = 1; + + for (i = 0; i < function_keys_num; i++) { + wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]); + mvwprintw(main_window, LINES-3, offset, + "%s", + function_keys[i].key_str); + wattrset(main_window, attributes[FUNCTION_TEXT]); + offset += strlen(function_keys[i].key_str); + mvwprintw(main_window, LINES-3, + offset, "%s", + function_keys[i].func); + offset += strlen(function_keys[i].func) + skip; + } + wattrset(main_window, attributes[NORMAL]); +} + +/* help */ +static void handle_f1(int *key, struct menu *current_item) +{ + show_scroll_win(main_window, + _("README"), _(nconf_readme)); + return; +} + +/* symbole help */ +static void handle_f2(int *key, struct menu *current_item) +{ + show_help(current_item); + return; +} + +/* instructions */ +static void handle_f3(int *key, struct menu *current_item) +{ + show_scroll_win(main_window, + _("Instructions"), + _(current_instructions)); + return; +} + +/* config */ +static void handle_f4(int *key, struct menu *current_item) +{ + int res = btn_dialog(main_window, + _("Show all symbols?"), + 2, + " ", + ""); + if (res == 0) + show_all_items = 1; + else if (res == 1) + show_all_items = 0; + + return; +} + +/* back */ +static void handle_f5(int *key, struct menu *current_item) +{ + *key = KEY_LEFT; + return; +} + +/* save */ +static void handle_f6(int *key, struct menu *current_item) +{ + conf_save(); + return; +} + +/* load */ +static void handle_f7(int *key, struct menu *current_item) +{ + conf_load(); + return; +} + +/* search */ +static void handle_f8(int *key, struct menu *current_item) +{ + search_conf(); + return; +} + +/* exit */ +static void handle_f9(int *key, struct menu *current_item) +{ + do_exit(); + return; +} + +/* return != 0 to indicate the key was handles */ +static int process_special_keys(int *key, struct menu *menu) +{ + int i; + + if (*key == KEY_RESIZE) { + setup_windows(); + return 1; + } + + for (i = 0; i < function_keys_num; i++) { + if (*key == KEY_F(function_keys[i].key) || + *key == '0' + function_keys[i].key){ + function_keys[i].handler(key, menu); + return 1; + } + } + + return 0; +} + +static void clean_items(void) +{ + int i; + for (i = 0; curses_menu_items[i]; i++) + free_item(curses_menu_items[i]); + bzero(curses_menu_items, sizeof(curses_menu_items)); + bzero(k_menu_items, sizeof(k_menu_items)); + items_num = 0; +} + +typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN, + FIND_NEXT_MATCH_DOWN, FIND_NEXT_MATCH_UP} match_f; + +/* return the index of the matched item, or -1 if no such item exists */ +static int get_mext_match(const char *match_str, match_f flag) +{ + int match_start = item_index(current_item(curses_menu)); + int index; + + if (flag == FIND_NEXT_MATCH_DOWN) + ++match_start; + else if (flag == FIND_NEXT_MATCH_UP) + --match_start; + + index = match_start; + index = (index + items_num) % items_num; + while (true) { + char *str = k_menu_items[index].str; + if (strcasestr(str, match_str) != 0) + return index; + if (flag == FIND_NEXT_MATCH_UP || + flag == MATCH_TINKER_PATTERN_UP) + --index; + else + ++index; + index = (index + items_num) % items_num; + if (index == match_start) + return -1; + } +} + +/* Make a new item. */ +static void item_make(struct menu *menu, char tag, const char *fmt, ...) +{ + va_list ap; + + if (items_num > MAX_MENU_ITEMS-1) + return; + + bzero(&k_menu_items[items_num], sizeof(k_menu_items[0])); + k_menu_items[items_num].tag = tag; + k_menu_items[items_num].usrptr = menu; + if (menu != NULL) + k_menu_items[items_num].is_visible = + menu_is_visible(menu); + else + k_menu_items[items_num].is_visible = 1; + + va_start(ap, fmt); + vsnprintf(k_menu_items[items_num].str, + sizeof(k_menu_items[items_num].str), + fmt, ap); + va_end(ap); + + if (!k_menu_items[items_num].is_visible) + memcpy(k_menu_items[items_num].str, "XXX", 3); + + curses_menu_items[items_num] = new_item( + k_menu_items[items_num].str, + k_menu_items[items_num].str); + set_item_userptr(curses_menu_items[items_num], + &k_menu_items[items_num]); + /* + if (!k_menu_items[items_num].is_visible) + item_opts_off(curses_menu_items[items_num], O_SELECTABLE); + */ + + items_num++; + curses_menu_items[items_num] = NULL; +} + +/* very hackish. adds a string to the last item added */ +static void item_add_str(const char *fmt, ...) +{ + va_list ap; + int index = items_num-1; + char new_str[256]; + char tmp_str[256]; + + if (index < 0) + return; + + va_start(ap, fmt); + vsnprintf(new_str, sizeof(new_str), fmt, ap); + va_end(ap); + snprintf(tmp_str, sizeof(tmp_str), "%s%s", + k_menu_items[index].str, new_str); + strncpy(k_menu_items[index].str, + tmp_str, + sizeof(k_menu_items[index].str)); + + free_item(curses_menu_items[index]); + curses_menu_items[index] = new_item( + k_menu_items[index].str, + k_menu_items[index].str); + set_item_userptr(curses_menu_items[index], + &k_menu_items[index]); +} + +/* get the tag of the currently selected item */ +static char item_tag(void) +{ + ITEM *cur; + struct mitem *mcur; + + cur = current_item(curses_menu); + if (cur == NULL) + return 0; + mcur = (struct mitem *) item_userptr(cur); + return mcur->tag; +} + +static int curses_item_index(void) +{ + return item_index(current_item(curses_menu)); +} + +static void *item_data(void) +{ + ITEM *cur; + struct mitem *mcur; + + cur = current_item(curses_menu); + if (!cur) + return NULL; + mcur = (struct mitem *) item_userptr(cur); + return mcur->usrptr; + +} + +static int item_is_tag(char tag) +{ + return item_tag() == tag; +} + +static char filename[PATH_MAX+1]; +static char menu_backtitle[PATH_MAX+128]; +static const char *set_config_filename(const char *config_filename) +{ + int size; + + size = snprintf(menu_backtitle, sizeof(menu_backtitle), + "%s - %s", config_filename, rootmenu.prompt->text); + if (size >= sizeof(menu_backtitle)) + menu_backtitle[sizeof(menu_backtitle)-1] = '\0'; + + size = snprintf(filename, sizeof(filename), "%s", config_filename); + if (size >= sizeof(filename)) + filename[sizeof(filename)-1] = '\0'; + return menu_backtitle; +} + +/* return = 0 means we are successful. + * -1 means go on doing what you were doing + */ +static int do_exit(void) +{ + int res; + if (!conf_get_changed()) { + global_exit = 1; + return 0; + } + res = btn_dialog(main_window, + _("Do you wish to save your new configuration?\n" + " to cancel and resume nconfig."), + 2, + " ", + ""); + if (res == KEY_EXIT) { + global_exit = 0; + return -1; + } + + /* if we got here, the user really wants to exit */ + switch (res) { + case 0: + res = conf_write(filename); + if (res) + btn_dialog( + main_window, + _("Error during writing of configuration.\n" + "Your configuration changes were NOT saved."), + 1, + ""); + break; + default: + btn_dialog( + main_window, + _("Your configuration changes were NOT saved."), + 1, + ""); + break; + } + global_exit = 1; + return 0; +} + + +static void search_conf(void) +{ + struct symbol **sym_arr; + struct gstr res; + char dialog_input_result[100]; + char *dialog_input; + int dres; +again: + dres = dialog_inputbox(main_window, + _("Search Configuration Parameter"), + _("Enter " CONFIG_ " (sub)string to search for " + "(with or without \"" CONFIG_ "\")"), + "", dialog_input_result, 99); + switch (dres) { + case 0: + break; + case 1: + show_scroll_win(main_window, + _("Search Configuration"), search_help); + goto again; + default: + return; + } + + /* strip the prefix if necessary */ + dialog_input = dialog_input_result; + if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0) + dialog_input += strlen(CONFIG_); + + sym_arr = sym_re_search(dialog_input); + res = get_relations_str(sym_arr); + free(sym_arr); + show_scroll_win(main_window, + _("Search Results"), str_get(&res)); + str_free(&res); +} + + +static void build_conf(struct menu *menu) +{ + struct symbol *sym; + struct property *prop; + struct menu *child; + int type, tmp, doint = 2; + tristate val; + char ch; + + if (!menu || (!show_all_items && !menu_is_visible(menu))) + return; + + sym = menu->sym; + prop = menu->prompt; + if (!sym) { + if (prop && menu != current_menu) { + const char *prompt = menu_get_prompt(menu); + enum prop_type ptype; + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + switch (ptype) { + case P_MENU: + child_count++; + prompt = _(prompt); + if (single_menu_mode) { + item_make(menu, 'm', + "%s%*c%s", + menu->data ? "-->" : "++>", + indent + 1, ' ', prompt); + } else + item_make(menu, 'm', + " %*c%s --->", + indent + 1, + ' ', prompt); + + if (single_menu_mode && menu->data) + goto conf_childs; + return; + case P_COMMENT: + if (prompt) { + child_count++; + item_make(menu, ':', + " %*c*** %s ***", + indent + 1, ' ', + _(prompt)); + } + break; + default: + if (prompt) { + child_count++; + item_make(menu, ':', "---%*c%s", + indent + 1, ' ', + _(prompt)); + } + } + } else + doint = 0; + goto conf_childs; + } + + type = sym_get_type(sym); + if (sym_is_choice(sym)) { + struct symbol *def_sym = sym_get_choice_value(sym); + struct menu *def_menu = NULL; + + child_count++; + for (child = menu->list; child; child = child->next) { + if (menu_is_visible(child) && child->sym == def_sym) + def_menu = child; + } + + val = sym_get_tristate_value(sym); + if (sym_is_changable(sym)) { + switch (type) { + case S_BOOLEAN: + item_make(menu, 't', "[%c]", + val == no ? ' ' : '*'); + break; + case S_TRISTATE: + switch (val) { + case yes: + ch = '*'; + break; + case mod: + ch = 'M'; + break; + default: + ch = ' '; + break; + } + item_make(menu, 't', "<%c>", ch); + break; + } + } else { + item_make(menu, def_menu ? 't' : ':', " "); + } + + item_add_str("%*c%s", indent + 1, + ' ', _(menu_get_prompt(menu))); + if (val == yes) { + if (def_menu) { + item_add_str(" (%s)", + _(menu_get_prompt(def_menu))); + item_add_str(" --->"); + if (def_menu->list) { + indent += 2; + build_conf(def_menu); + indent -= 2; + } + } + return; + } + } else { + if (menu == current_menu) { + item_make(menu, ':', + "---%*c%s", indent + 1, + ' ', _(menu_get_prompt(menu))); + goto conf_childs; + } + child_count++; + val = sym_get_tristate_value(sym); + if (sym_is_choice_value(sym) && val == yes) { + item_make(menu, ':', " "); + } else { + switch (type) { + case S_BOOLEAN: + if (sym_is_changable(sym)) + item_make(menu, 't', "[%c]", + val == no ? ' ' : '*'); + else + item_make(menu, 't', "-%c-", + val == no ? ' ' : '*'); + break; + case S_TRISTATE: + switch (val) { + case yes: + ch = '*'; + break; + case mod: + ch = 'M'; + break; + default: + ch = ' '; + break; + } + if (sym_is_changable(sym)) { + if (sym->rev_dep.tri == mod) + item_make(menu, + 't', "{%c}", ch); + else + item_make(menu, + 't', "<%c>", ch); + } else + item_make(menu, 't', "-%c-", ch); + break; + default: + tmp = 2 + strlen(sym_get_string_value(sym)); + item_make(menu, 's', " (%s)", + sym_get_string_value(sym)); + tmp = indent - tmp + 4; + if (tmp < 0) + tmp = 0; + item_add_str("%*c%s%s", tmp, ' ', + _(menu_get_prompt(menu)), + (sym_has_value(sym) || + !sym_is_changable(sym)) ? "" : + _(" (NEW)")); + goto conf_childs; + } + } + item_add_str("%*c%s%s", indent + 1, ' ', + _(menu_get_prompt(menu)), + (sym_has_value(sym) || !sym_is_changable(sym)) ? + "" : _(" (NEW)")); + if (menu->prompt && menu->prompt->type == P_MENU) { + item_add_str(" --->"); + return; + } + } + +conf_childs: + indent += doint; + for (child = menu->list; child; child = child->next) + build_conf(child); + indent -= doint; +} + +static void reset_menu(void) +{ + unpost_menu(curses_menu); + clean_items(); +} + +/* adjust the menu to show this item. + * prefer not to scroll the menu if possible*/ +static void center_item(int selected_index, int *last_top_row) +{ + int toprow; + + set_top_row(curses_menu, *last_top_row); + toprow = top_row(curses_menu); + if (selected_index < toprow || + selected_index >= toprow+mwin_max_lines) { + toprow = max(selected_index-mwin_max_lines/2, 0); + if (toprow >= item_count(curses_menu)-mwin_max_lines) + toprow = item_count(curses_menu)-mwin_max_lines; + set_top_row(curses_menu, toprow); + } + set_current_item(curses_menu, + curses_menu_items[selected_index]); + *last_top_row = toprow; + post_menu(curses_menu); + refresh_all_windows(main_window); +} + +/* this function assumes reset_menu has been called before */ +static void show_menu(const char *prompt, const char *instructions, + int selected_index, int *last_top_row) +{ + int maxx, maxy; + WINDOW *menu_window; + + current_instructions = instructions; + + clear(); + wattrset(main_window, attributes[NORMAL]); + print_in_middle(stdscr, 1, 0, COLS, + menu_backtitle, + attributes[MAIN_HEADING]); + + wattrset(main_window, attributes[MAIN_MENU_BOX]); + box(main_window, 0, 0); + wattrset(main_window, attributes[MAIN_MENU_HEADING]); + mvwprintw(main_window, 0, 3, " %s ", prompt); + wattrset(main_window, attributes[NORMAL]); + + set_menu_items(curses_menu, curses_menu_items); + + /* position the menu at the middle of the screen */ + scale_menu(curses_menu, &maxy, &maxx); + maxx = min(maxx, mwin_max_cols-2); + maxy = mwin_max_lines; + menu_window = derwin(main_window, + maxy, + maxx, + 2, + (mwin_max_cols-maxx)/2); + keypad(menu_window, TRUE); + set_menu_win(curses_menu, menu_window); + set_menu_sub(curses_menu, menu_window); + + /* must reassert this after changing items, otherwise returns to a + * default of 16 + */ + set_menu_format(curses_menu, maxy, 1); + center_item(selected_index, last_top_row); + set_menu_format(curses_menu, maxy, 1); + + print_function_line(); + + /* Post the menu */ + post_menu(curses_menu); + refresh_all_windows(main_window); +} + +static void adj_match_dir(match_f *match_direction) +{ + if (*match_direction == FIND_NEXT_MATCH_DOWN) + *match_direction = + MATCH_TINKER_PATTERN_DOWN; + else if (*match_direction == FIND_NEXT_MATCH_UP) + *match_direction = + MATCH_TINKER_PATTERN_UP; + /* else, do no change.. */ +} + +struct match_state +{ + int in_search; + match_f match_direction; + char pattern[256]; +}; + +/* Return 0 means I have handled the key. In such a case, ans should hold the + * item to center, or -1 otherwise. + * Else return -1 . + */ +static int do_match(int key, struct match_state *state, int *ans) +{ + char c = (char) key; + int terminate_search = 0; + *ans = -1; + if (key == '/' || (state->in_search && key == 27)) { + move(0, 0); + refresh(); + clrtoeol(); + state->in_search = 1-state->in_search; + bzero(state->pattern, sizeof(state->pattern)); + state->match_direction = MATCH_TINKER_PATTERN_DOWN; + return 0; + } else if (!state->in_search) + return 1; + + if (isalnum(c) || isgraph(c) || c == ' ') { + state->pattern[strlen(state->pattern)] = c; + state->pattern[strlen(state->pattern)] = '\0'; + adj_match_dir(&state->match_direction); + *ans = get_mext_match(state->pattern, + state->match_direction); + } else if (key == KEY_DOWN) { + state->match_direction = FIND_NEXT_MATCH_DOWN; + *ans = get_mext_match(state->pattern, + state->match_direction); + } else if (key == KEY_UP) { + state->match_direction = FIND_NEXT_MATCH_UP; + *ans = get_mext_match(state->pattern, + state->match_direction); + } else if (key == KEY_BACKSPACE || key == 127) { + state->pattern[strlen(state->pattern)-1] = '\0'; + adj_match_dir(&state->match_direction); + } else + terminate_search = 1; + + if (terminate_search) { + state->in_search = 0; + bzero(state->pattern, sizeof(state->pattern)); + move(0, 0); + refresh(); + clrtoeol(); + return -1; + } + return 0; +} + +static void conf(struct menu *menu) +{ + struct menu *submenu = 0; + const char *prompt = menu_get_prompt(menu); + struct symbol *sym; + struct menu *active_menu = NULL; + int res; + int current_index = 0; + int last_top_row = 0; + struct match_state match_state = { + .in_search = 0, + .match_direction = MATCH_TINKER_PATTERN_DOWN, + .pattern = "", + }; + + while (!global_exit) { + reset_menu(); + current_menu = menu; + build_conf(menu); + if (!child_count) + break; + + show_menu(prompt ? _(prompt) : _("Main Menu"), + _(menu_instructions), + current_index, &last_top_row); + keypad((menu_win(curses_menu)), TRUE); + while (!global_exit) { + if (match_state.in_search) { + mvprintw(0, 0, + "searching: %s", match_state.pattern); + clrtoeol(); + } + refresh_all_windows(main_window); + res = wgetch(menu_win(curses_menu)); + if (!res) + break; + if (do_match(res, &match_state, ¤t_index) == 0) { + if (current_index != -1) + center_item(current_index, + &last_top_row); + continue; + } + if (process_special_keys(&res, + (struct menu *) item_data())) + break; + switch (res) { + case KEY_DOWN: + menu_driver(curses_menu, REQ_DOWN_ITEM); + break; + case KEY_UP: + menu_driver(curses_menu, REQ_UP_ITEM); + break; + case KEY_NPAGE: + menu_driver(curses_menu, REQ_SCR_DPAGE); + break; + case KEY_PPAGE: + menu_driver(curses_menu, REQ_SCR_UPAGE); + break; + case KEY_HOME: + menu_driver(curses_menu, REQ_FIRST_ITEM); + break; + case KEY_END: + menu_driver(curses_menu, REQ_LAST_ITEM); + break; + case 'h': + case '?': + show_help((struct menu *) item_data()); + break; + } + if (res == 10 || res == 27 || + res == 32 || res == 'n' || res == 'y' || + res == KEY_LEFT || res == KEY_RIGHT || + res == 'm') + break; + refresh_all_windows(main_window); + } + + refresh_all_windows(main_window); + /* if ESC or left*/ + if (res == 27 || (menu != &rootmenu && res == KEY_LEFT)) + break; + + /* remember location in the menu */ + last_top_row = top_row(curses_menu); + current_index = curses_item_index(); + + if (!item_tag()) + continue; + + submenu = (struct menu *) item_data(); + active_menu = (struct menu *)item_data(); + if (!submenu || !menu_is_visible(submenu)) + continue; + if (submenu) + sym = submenu->sym; + else + sym = NULL; + + switch (res) { + case ' ': + if (item_is_tag('t')) + sym_toggle_tristate_value(sym); + else if (item_is_tag('m')) + conf(submenu); + break; + case KEY_RIGHT: + case 10: /* ENTER WAS PRESSED */ + switch (item_tag()) { + case 'm': + if (single_menu_mode) + submenu->data = + (void *) (long) !submenu->data; + else + conf(submenu); + break; + case 't': + if (sym_is_choice(sym) && + sym_get_tristate_value(sym) == yes) + conf_choice(submenu); + else if (submenu->prompt && + submenu->prompt->type == P_MENU) + conf(submenu); + else if (res == 10) + sym_toggle_tristate_value(sym); + break; + case 's': + conf_string(submenu); + break; + } + break; + case 'y': + if (item_is_tag('t')) { + if (sym_set_tristate_value(sym, yes)) + break; + if (sym_set_tristate_value(sym, mod)) + btn_dialog(main_window, setmod_text, 0); + } + break; + case 'n': + if (item_is_tag('t')) + sym_set_tristate_value(sym, no); + break; + case 'm': + if (item_is_tag('t')) + sym_set_tristate_value(sym, mod); + break; + } + } +} + +static void conf_message_callback(const char *fmt, va_list ap) +{ + char buf[1024]; + + vsnprintf(buf, sizeof(buf), fmt, ap); + btn_dialog(main_window, buf, 1, ""); +} + +static void show_help(struct menu *menu) +{ + struct gstr help = str_new(); + + if (menu && menu->sym && menu_has_help(menu)) { + if (menu->sym->name) { + str_printf(&help, "%s%s:\n\n", CONFIG_, menu->sym->name); + str_append(&help, _(menu_get_help(menu))); + str_append(&help, "\n"); + get_symbol_str(&help, menu->sym); + } else { + str_append(&help, _(menu_get_help(menu))); + } + } else { + str_append(&help, nohelp_text); + } + show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help)); + str_free(&help); +} + +static void conf_choice(struct menu *menu) +{ + const char *prompt = _(menu_get_prompt(menu)); + struct menu *child = 0; + struct symbol *active; + int selected_index = 0; + int last_top_row = 0; + int res, i = 0; + struct match_state match_state = { + .in_search = 0, + .match_direction = MATCH_TINKER_PATTERN_DOWN, + .pattern = "", + }; + + active = sym_get_choice_value(menu->sym); + /* this is mostly duplicated from the conf() function. */ + while (!global_exit) { + reset_menu(); + + for (i = 0, child = menu->list; child; child = child->next) { + if (!show_all_items && !menu_is_visible(child)) + continue; + + if (child->sym == sym_get_choice_value(menu->sym)) + item_make(child, ':', " %s", + _(menu_get_prompt(child))); + else if (child->sym) + item_make(child, ':', " %s", + _(menu_get_prompt(child))); + else + item_make(child, ':', "*** %s ***", + _(menu_get_prompt(child))); + + if (child->sym == active){ + last_top_row = top_row(curses_menu); + selected_index = i; + } + i++; + } + show_menu(prompt ? _(prompt) : _("Choice Menu"), + _(radiolist_instructions), + selected_index, + &last_top_row); + while (!global_exit) { + if (match_state.in_search) { + mvprintw(0, 0, "searching: %s", + match_state.pattern); + clrtoeol(); + } + refresh_all_windows(main_window); + res = wgetch(menu_win(curses_menu)); + if (!res) + break; + if (do_match(res, &match_state, &selected_index) == 0) { + if (selected_index != -1) + center_item(selected_index, + &last_top_row); + continue; + } + if (process_special_keys( + &res, + (struct menu *) item_data())) + break; + switch (res) { + case KEY_DOWN: + menu_driver(curses_menu, REQ_DOWN_ITEM); + break; + case KEY_UP: + menu_driver(curses_menu, REQ_UP_ITEM); + break; + case KEY_NPAGE: + menu_driver(curses_menu, REQ_SCR_DPAGE); + break; + case KEY_PPAGE: + menu_driver(curses_menu, REQ_SCR_UPAGE); + break; + case KEY_HOME: + menu_driver(curses_menu, REQ_FIRST_ITEM); + break; + case KEY_END: + menu_driver(curses_menu, REQ_LAST_ITEM); + break; + case 'h': + case '?': + show_help((struct menu *) item_data()); + break; + } + if (res == 10 || res == 27 || res == ' ' || + res == KEY_LEFT){ + break; + } + refresh_all_windows(main_window); + } + /* if ESC or left */ + if (res == 27 || res == KEY_LEFT) + break; + + child = item_data(); + if (!child || !menu_is_visible(child) || !child->sym) + continue; + switch (res) { + case ' ': + case 10: + case KEY_RIGHT: + sym_set_tristate_value(child->sym, yes); + return; + case 'h': + case '?': + show_help(child); + active = child->sym; + break; + case KEY_EXIT: + return; + } + } +} + +static void conf_string(struct menu *menu) +{ + const char *prompt = menu_get_prompt(menu); + char dialog_input_result[256]; + + while (1) { + int res; + const char *heading; + + switch (sym_get_type(menu->sym)) { + case S_INT: + heading = _(inputbox_instructions_int); + break; + case S_HEX: + heading = _(inputbox_instructions_hex); + break; + case S_STRING: + heading = _(inputbox_instructions_string); + break; + default: + heading = _("Internal nconf error!"); + } + res = dialog_inputbox(main_window, + prompt ? _(prompt) : _("Main Menu"), + heading, + sym_get_string_value(menu->sym), + dialog_input_result, + sizeof(dialog_input_result)); + switch (res) { + case 0: + if (sym_set_string_value(menu->sym, + dialog_input_result)) + return; + btn_dialog(main_window, + _("You have made an invalid entry."), 0); + break; + case 1: + show_help(menu); + break; + case KEY_EXIT: + return; + } + } +} + +static void conf_load(void) +{ + char dialog_input_result[256]; + while (1) { + int res; + res = dialog_inputbox(main_window, + NULL, load_config_text, + filename, + dialog_input_result, + sizeof(dialog_input_result)); + switch (res) { + case 0: + if (!dialog_input_result[0]) + return; + if (!conf_read(dialog_input_result)) { + set_config_filename(dialog_input_result); + sym_set_change_count(1); + return; + } + btn_dialog(main_window, _("File does not exist!"), 0); + break; + case 1: + show_scroll_win(main_window, + _("Load Alternate Configuration"), + load_config_help); + break; + case KEY_EXIT: + return; + } + } +} + +static void conf_save(void) +{ + char dialog_input_result[256]; + while (1) { + int res; + res = dialog_inputbox(main_window, + NULL, save_config_text, + filename, + dialog_input_result, + sizeof(dialog_input_result)); + switch (res) { + case 0: + if (!dialog_input_result[0]) + return; + res = conf_write(dialog_input_result); + if (!res) { + set_config_filename(dialog_input_result); + return; + } + btn_dialog(main_window, _("Can't create file! " + "Probably a nonexistent directory."), + 1, ""); + break; + case 1: + show_scroll_win(main_window, + _("Save Alternate Configuration"), + save_config_help); + break; + case KEY_EXIT: + return; + } + } +} + +void setup_windows(void) +{ + if (main_window != NULL) + delwin(main_window); + + /* set up the menu and menu window */ + main_window = newwin(LINES-2, COLS-2, 2, 1); + keypad(main_window, TRUE); + mwin_max_lines = LINES-7; + mwin_max_cols = COLS-6; + + /* panels order is from bottom to top */ + new_panel(main_window); +} + +int main(int ac, char **av) +{ + char *mode; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + conf_parse(av[1]); + conf_read(NULL); + + mode = getenv("NCONFIG_MODE"); + if (mode) { + if (!strcasecmp(mode, "single_menu")) + single_menu_mode = 1; + } + + /* Initialize curses */ + initscr(); + /* set color theme */ + set_colors(); + + cbreak(); + noecho(); + keypad(stdscr, TRUE); + curs_set(0); + + if (COLS < 75 || LINES < 20) { + endwin(); + printf("Your terminal should have at " + "least 20 lines and 75 columns\n"); + return 1; + } + + notimeout(stdscr, FALSE); + ESCDELAY = 1; + + /* set btns menu */ + curses_menu = new_menu(curses_menu_items); + menu_opts_off(curses_menu, O_SHOWDESC); + menu_opts_on(curses_menu, O_SHOWMATCH); + menu_opts_on(curses_menu, O_ONEVALUE); + menu_opts_on(curses_menu, O_NONCYCLIC); + menu_opts_on(curses_menu, O_IGNORECASE); + set_menu_mark(curses_menu, " "); + set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]); + set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]); + set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]); + + set_config_filename(conf_get_configname()); + setup_windows(); + + /* check for KEY_FUNC(1) */ + if (has_key(KEY_F(1)) == FALSE) { + show_scroll_win(main_window, + _("Instructions"), + _(menu_no_f_instructions)); + } + + conf_set_message_callback(conf_message_callback); + /* do the work */ + while (!global_exit) { + conf(&rootmenu); + if (!global_exit && do_exit() == 0) + break; + } + /* ok, we are done */ + unpost_menu(curses_menu); + free_menu(curses_menu); + delwin(main_window); + clear(); + refresh(); + endwin(); + return 0; +} + diff --git a/bios/seabios/tools/kconfig/nconf.gui.c b/bios/seabios/tools/kconfig/nconf.gui.c new file mode 100644 index 0000000..f8137b3 --- /dev/null +++ b/bios/seabios/tools/kconfig/nconf.gui.c @@ -0,0 +1,617 @@ +/* + * Copyright (C) 2008 Nir Tzachar 0) + win_rows = msg_lines+4; + else + win_rows = msg_lines+2; + + win = newwin(win_rows, total_width+4, y, x); + keypad(win, TRUE); + menu_win = derwin(win, 1, btns_width, win_rows-2, + 1+(total_width+2-btns_width)/2); + menu = new_menu(btns); + msg_win = derwin(win, win_rows-2, msg_width, 1, + 1+(total_width+2-msg_width)/2); + + set_menu_fore(menu, attributes[DIALOG_MENU_FORE]); + set_menu_back(menu, attributes[DIALOG_MENU_BACK]); + + (void) wattrset(win, attributes[DIALOG_BOX]); + box(win, 0, 0); + + /* print message */ + (void) wattrset(msg_win, attributes[DIALOG_TEXT]); + fill_window(msg_win, msg); + + set_menu_win(menu, win); + set_menu_sub(menu, menu_win); + set_menu_format(menu, 1, btn_num); + menu_opts_off(menu, O_SHOWDESC); + menu_opts_off(menu, O_SHOWMATCH); + menu_opts_on(menu, O_ONEVALUE); + menu_opts_on(menu, O_NONCYCLIC); + set_menu_mark(menu, ""); + post_menu(menu); + + + touchwin(win); + refresh_all_windows(main_window); + while ((res = wgetch(win))) { + switch (res) { + case KEY_LEFT: + menu_driver(menu, REQ_LEFT_ITEM); + break; + case KEY_RIGHT: + menu_driver(menu, REQ_RIGHT_ITEM); + break; + case 10: /* ENTER */ + case 27: /* ESCAPE */ + case ' ': + case KEY_F(F_BACK): + case KEY_F(F_EXIT): + break; + } + touchwin(win); + refresh_all_windows(main_window); + + if (res == 10 || res == ' ') { + res = item_index(current_item(menu)); + break; + } else if (res == 27 || res == KEY_F(F_BACK) || + res == KEY_F(F_EXIT)) { + res = KEY_EXIT; + break; + } + } + + unpost_menu(menu); + free_menu(menu); + for (i = 0; i < btn_num; i++) + free_item(btns[i]); + + delwin(win); + return res; +} + +int dialog_inputbox(WINDOW *main_window, + const char *title, const char *prompt, + const char *init, char *result, int result_len) +{ + int prompt_lines = 0; + int prompt_width = 0; + WINDOW *win; + WINDOW *prompt_win; + WINDOW *form_win; + PANEL *panel; + int i, x, y; + int res = -1; + int cursor_position = strlen(init); + + + /* find the widest line of msg: */ + prompt_lines = get_line_no(prompt); + for (i = 0; i < prompt_lines; i++) { + const char *line = get_line(prompt, i); + int len = get_line_length(line); + prompt_width = max(prompt_width, len); + } + + if (title) + prompt_width = max(prompt_width, strlen(title)); + + /* place dialog in middle of screen */ + y = (LINES-(prompt_lines+4))/2; + x = (COLS-(prompt_width+4))/2; + + strncpy(result, init, result_len); + + /* create the windows */ + win = newwin(prompt_lines+6, prompt_width+7, y, x); + prompt_win = derwin(win, prompt_lines+1, prompt_width, 2, 2); + form_win = derwin(win, 1, prompt_width, prompt_lines+3, 2); + keypad(form_win, TRUE); + + (void) wattrset(form_win, attributes[INPUT_FIELD]); + + (void) wattrset(win, attributes[INPUT_BOX]); + box(win, 0, 0); + (void) wattrset(win, attributes[INPUT_HEADING]); + if (title) + mvwprintw(win, 0, 3, "%s", title); + + /* print message */ + (void) wattrset(prompt_win, attributes[INPUT_TEXT]); + fill_window(prompt_win, prompt); + + mvwprintw(form_win, 0, 0, "%*s", prompt_width, " "); + mvwprintw(form_win, 0, 0, "%s", result); + + /* create panels */ + panel = new_panel(win); + + /* show the cursor */ + curs_set(1); + + touchwin(win); + refresh_all_windows(main_window); + while ((res = wgetch(form_win))) { + int len = strlen(result); + switch (res) { + case 10: /* ENTER */ + case 27: /* ESCAPE */ + case KEY_F(F_HELP): + case KEY_F(F_EXIT): + case KEY_F(F_BACK): + break; + case 127: + case KEY_BACKSPACE: + if (cursor_position > 0) { + memmove(&result[cursor_position-1], + &result[cursor_position], + len-cursor_position+1); + cursor_position--; + } + break; + case KEY_DC: + if (cursor_position >= 0 && cursor_position < len) { + memmove(&result[cursor_position], + &result[cursor_position+1], + len-cursor_position+1); + } + break; + case KEY_UP: + case KEY_RIGHT: + if (cursor_position < len && + cursor_position < min(result_len, prompt_width)) + cursor_position++; + break; + case KEY_DOWN: + case KEY_LEFT: + if (cursor_position > 0) + cursor_position--; + break; + default: + if ((isgraph(res) || isspace(res)) && + len-2 < result_len) { + /* insert the char at the proper position */ + memmove(&result[cursor_position+1], + &result[cursor_position], + len+1); + result[cursor_position] = res; + cursor_position++; + } else { + mvprintw(0, 0, "unknow key: %d\n", res); + } + break; + } + wmove(form_win, 0, 0); + wclrtoeol(form_win); + mvwprintw(form_win, 0, 0, "%*s", prompt_width, " "); + mvwprintw(form_win, 0, 0, "%s", result); + wmove(form_win, 0, cursor_position); + touchwin(win); + refresh_all_windows(main_window); + + if (res == 10) { + res = 0; + break; + } else if (res == 27 || res == KEY_F(F_BACK) || + res == KEY_F(F_EXIT)) { + res = KEY_EXIT; + break; + } else if (res == KEY_F(F_HELP)) { + res = 1; + break; + } + } + + /* hide the cursor */ + curs_set(0); + del_panel(panel); + delwin(prompt_win); + delwin(form_win); + delwin(win); + return res; +} + +/* refresh all windows in the correct order */ +void refresh_all_windows(WINDOW *main_window) +{ + update_panels(); + touchwin(main_window); + refresh(); +} + +/* layman's scrollable window... */ +void show_scroll_win(WINDOW *main_window, + const char *title, + const char *text) +{ + int res; + int total_lines = get_line_no(text); + int x, y; + int start_x = 0, start_y = 0; + int text_lines = 0, text_cols = 0; + int total_cols = 0; + int win_cols = 0; + int win_lines = 0; + int i = 0; + WINDOW *win; + WINDOW *pad; + PANEL *panel; + + /* find the widest line of msg: */ + total_lines = get_line_no(text); + for (i = 0; i < total_lines; i++) { + const char *line = get_line(text, i); + int len = get_line_length(line); + total_cols = max(total_cols, len+2); + } + + /* create the pad */ + pad = newpad(total_lines+10, total_cols+10); + (void) wattrset(pad, attributes[SCROLLWIN_TEXT]); + fill_window(pad, text); + + win_lines = min(total_lines+4, LINES-2); + win_cols = min(total_cols+2, COLS-2); + text_lines = max(win_lines-4, 0); + text_cols = max(win_cols-2, 0); + + /* place window in middle of screen */ + y = (LINES-win_lines)/2; + x = (COLS-win_cols)/2; + + win = newwin(win_lines, win_cols, y, x); + keypad(win, TRUE); + /* show the help in the help window, and show the help panel */ + (void) wattrset(win, attributes[SCROLLWIN_BOX]); + box(win, 0, 0); + (void) wattrset(win, attributes[SCROLLWIN_HEADING]); + mvwprintw(win, 0, 3, " %s ", title); + panel = new_panel(win); + + /* handle scrolling */ + do { + + copywin(pad, win, start_y, start_x, 2, 2, text_lines, + text_cols, 0); + print_in_middle(win, + text_lines+2, + 0, + text_cols, + "", + attributes[DIALOG_MENU_FORE]); + wrefresh(win); + + res = wgetch(win); + switch (res) { + case KEY_NPAGE: + case ' ': + start_y += text_lines-2; + break; + case KEY_PPAGE: + start_y -= text_lines+2; + break; + case KEY_HOME: + start_y = 0; + break; + case KEY_END: + start_y = total_lines-text_lines; + break; + case KEY_DOWN: + case 'j': + start_y++; + break; + case KEY_UP: + case 'k': + start_y--; + break; + case KEY_LEFT: + case 'h': + start_x--; + break; + case KEY_RIGHT: + case 'l': + start_x++; + break; + } + if (res == 10 || res == 27 || res == 'q' + || res == KEY_F(F_BACK) || res == KEY_F(F_EXIT)) { + break; + } + if (start_y < 0) + start_y = 0; + if (start_y >= total_lines-text_lines) + start_y = total_lines-text_lines; + if (start_x < 0) + start_x = 0; + if (start_x >= total_cols-text_cols) + start_x = total_cols-text_cols; + } while (res); + + del_panel(panel); + delwin(win); + refresh_all_windows(main_window); +} diff --git a/bios/seabios/tools/kconfig/nconf.h b/bios/seabios/tools/kconfig/nconf.h new file mode 100644 index 0000000..58fbda8 --- /dev/null +++ b/bios/seabios/tools/kconfig/nconf.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2008 Nir Tzachar +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ncurses.h" + +#define max(a, b) ({\ + typeof(a) _a = a;\ + typeof(b) _b = b;\ + _a > _b ? _a : _b; }) + +#define min(a, b) ({\ + typeof(a) _a = a;\ + typeof(b) _b = b;\ + _a < _b ? _a : _b; }) + +typedef enum { + NORMAL = 1, + MAIN_HEADING, + MAIN_MENU_BOX, + MAIN_MENU_FORE, + MAIN_MENU_BACK, + MAIN_MENU_GREY, + MAIN_MENU_HEADING, + SCROLLWIN_TEXT, + SCROLLWIN_HEADING, + SCROLLWIN_BOX, + DIALOG_TEXT, + DIALOG_MENU_FORE, + DIALOG_MENU_BACK, + DIALOG_BOX, + INPUT_BOX, + INPUT_HEADING, + INPUT_TEXT, + INPUT_FIELD, + FUNCTION_TEXT, + FUNCTION_HIGHLIGHT, + ATTR_MAX +} attributes_t; +extern attributes_t attributes[]; + +typedef enum { + F_HELP = 1, + F_SYMBOL = 2, + F_INSTS = 3, + F_CONF = 4, + F_BACK = 5, + F_SAVE = 6, + F_LOAD = 7, + F_SEARCH = 8, + F_EXIT = 9, +} function_key; + +void set_colors(void); + +/* this changes the windows attributes !!! */ +void print_in_middle(WINDOW *win, + int starty, + int startx, + int width, + const char *string, + chtype color); +int get_line_length(const char *line); +int get_line_no(const char *text); +const char *get_line(const char *text, int line_no); +void fill_window(WINDOW *win, const char *text); +int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...); +int dialog_inputbox(WINDOW *main_window, + const char *title, const char *prompt, + const char *init, char *result, int result_len); +void refresh_all_windows(WINDOW *main_window); +void show_scroll_win(WINDOW *main_window, + const char *title, + const char *text); diff --git a/bios/seabios/tools/kconfig/qconf.cc b/bios/seabios/tools/kconfig/qconf.cc new file mode 100644 index 0000000..06dd2e3 --- /dev/null +++ b/bios/seabios/tools/kconfig/qconf.cc @@ -0,0 +1,1787 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include + +#if QT_VERSION < 0x040000 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "lkc.h" +#include "qconf.h" + +#include "qconf.moc" +#include "images.c" + +#ifdef _ +# undef _ +# define _ qgettext +#endif + +static QApplication *configApp; +static ConfigSettings *configSettings; + +Q3Action *ConfigMainWindow::saveAction; + +static inline QString qgettext(const char* str) +{ + return QString::fromLocal8Bit(gettext(str)); +} + +static inline QString qgettext(const QString& str) +{ + return QString::fromLocal8Bit(gettext(str.latin1())); +} + +/** + * Reads a list of integer values from the application settings. + */ +Q3ValueList ConfigSettings::readSizes(const QString& key, bool *ok) +{ + Q3ValueList result; + QStringList entryList = readListEntry(key, ok); + QStringList::Iterator it; + + for (it = entryList.begin(); it != entryList.end(); ++it) + result.push_back((*it).toInt()); + + return result; +} + +/** + * Writes a list of integer values to the application settings. + */ +bool ConfigSettings::writeSizes(const QString& key, const Q3ValueList& value) +{ + QStringList stringList; + Q3ValueList::ConstIterator it; + + for (it = value.begin(); it != value.end(); ++it) + stringList.push_back(QString::number(*it)); + return writeEntry(key, stringList); +} + + +/* + * set the new data + * TODO check the value + */ +void ConfigItem::okRename(int col) +{ + Parent::okRename(col); + sym_set_string_value(menu->sym, text(dataColIdx).latin1()); + listView()->updateList(this); +} + +/* + * update the displayed of a menu entry + */ +void ConfigItem::updateMenu(void) +{ + ConfigList* list; + struct symbol* sym; + struct property *prop; + QString prompt; + int type; + tristate expr; + + list = listView(); + if (goParent) { + setPixmap(promptColIdx, list->menuBackPix); + prompt = ".."; + goto set_prompt; + } + + sym = menu->sym; + prop = menu->prompt; + prompt = _(menu_get_prompt(menu)); + + if (prop) switch (prop->type) { + case P_MENU: + if (list->mode == singleMode || list->mode == symbolMode) { + /* a menuconfig entry is displayed differently + * depending whether it's at the view root or a child. + */ + if (sym && list->rootEntry == menu) + break; + setPixmap(promptColIdx, list->menuPix); + } else { + if (sym) + break; + setPixmap(promptColIdx, 0); + } + goto set_prompt; + case P_COMMENT: + setPixmap(promptColIdx, 0); + goto set_prompt; + default: + ; + } + if (!sym) + goto set_prompt; + + setText(nameColIdx, QString::fromLocal8Bit(sym->name)); + + type = sym_get_type(sym); + switch (type) { + case S_BOOLEAN: + case S_TRISTATE: + char ch; + + if (!sym_is_changable(sym) && list->optMode == normalOpt) { + setPixmap(promptColIdx, 0); + setText(noColIdx, QString::null); + setText(modColIdx, QString::null); + setText(yesColIdx, QString::null); + break; + } + expr = sym_get_tristate_value(sym); + switch (expr) { + case yes: + if (sym_is_choice_value(sym) && type == S_BOOLEAN) + setPixmap(promptColIdx, list->choiceYesPix); + else + setPixmap(promptColIdx, list->symbolYesPix); + setText(yesColIdx, "Y"); + ch = 'Y'; + break; + case mod: + setPixmap(promptColIdx, list->symbolModPix); + setText(modColIdx, "M"); + ch = 'M'; + break; + default: + if (sym_is_choice_value(sym) && type == S_BOOLEAN) + setPixmap(promptColIdx, list->choiceNoPix); + else + setPixmap(promptColIdx, list->symbolNoPix); + setText(noColIdx, "N"); + ch = 'N'; + break; + } + if (expr != no) + setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0); + if (expr != mod) + setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0); + if (expr != yes) + setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0); + + setText(dataColIdx, QChar(ch)); + break; + case S_INT: + case S_HEX: + case S_STRING: + const char* data; + + data = sym_get_string_value(sym); + + int i = list->mapIdx(dataColIdx); + if (i >= 0) + setRenameEnabled(i, TRUE); + setText(dataColIdx, data); + if (type == S_STRING) + prompt = QString("%1: %2").arg(prompt).arg(data); + else + prompt = QString("(%2) %1").arg(prompt).arg(data); + break; + } + if (!sym_has_value(sym) && visible) + prompt += _(" (NEW)"); +set_prompt: + setText(promptColIdx, prompt); +} + +void ConfigItem::testUpdateMenu(bool v) +{ + ConfigItem* i; + + visible = v; + if (!menu) + return; + + sym_calc_value(menu->sym); + if (menu->flags & MENU_CHANGED) { + /* the menu entry changed, so update all list items */ + menu->flags &= ~MENU_CHANGED; + for (i = (ConfigItem*)menu->data; i; i = i->nextItem) + i->updateMenu(); + } else if (listView()->updateAll) + updateMenu(); +} + +void ConfigItem::paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align) +{ + ConfigList* list = listView(); + + if (visible) { + if (isSelected() && !list->hasFocus() && list->mode == menuMode) + Parent::paintCell(p, list->inactivedColorGroup, column, width, align); + else + Parent::paintCell(p, cg, column, width, align); + } else + Parent::paintCell(p, list->disabledColorGroup, column, width, align); +} + +/* + * construct a menu entry + */ +void ConfigItem::init(void) +{ + if (menu) { + ConfigList* list = listView(); + nextItem = (ConfigItem*)menu->data; + menu->data = this; + + if (list->mode != fullMode) + setOpen(TRUE); + sym_calc_value(menu->sym); + } + updateMenu(); +} + +/* + * destruct a menu entry + */ +ConfigItem::~ConfigItem(void) +{ + if (menu) { + ConfigItem** ip = (ConfigItem**)&menu->data; + for (; *ip; ip = &(*ip)->nextItem) { + if (*ip == this) { + *ip = nextItem; + break; + } + } + } +} + +ConfigLineEdit::ConfigLineEdit(ConfigView* parent) + : Parent(parent) +{ + connect(this, SIGNAL(lostFocus()), SLOT(hide())); +} + +void ConfigLineEdit::show(ConfigItem* i) +{ + item = i; + if (sym_get_string_value(item->menu->sym)) + setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym))); + else + setText(QString::null); + Parent::show(); + setFocus(); +} + +void ConfigLineEdit::keyPressEvent(QKeyEvent* e) +{ + switch (e->key()) { + case Qt::Key_Escape: + break; + case Qt::Key_Return: + case Qt::Key_Enter: + sym_set_string_value(item->menu->sym, text().latin1()); + parent()->updateList(item); + break; + default: + Parent::keyPressEvent(e); + return; + } + e->accept(); + parent()->list->setFocus(); + hide(); +} + +ConfigList::ConfigList(ConfigView* p, const char *name) + : Parent(p, name), + updateAll(false), + symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no), + choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no), + menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void), + showName(false), showRange(false), showData(false), optMode(normalOpt), + rootEntry(0), headerPopup(0) +{ + int i; + + setSorting(-1); + setRootIsDecorated(TRUE); + disabledColorGroup = palette().active(); + disabledColorGroup.setColor(QColorGroup::Text, palette().disabled().text()); + inactivedColorGroup = palette().active(); + inactivedColorGroup.setColor(QColorGroup::Highlight, palette().disabled().highlight()); + + connect(this, SIGNAL(selectionChanged(void)), + SLOT(updateSelection(void))); + + if (name) { + configSettings->beginGroup(name); + showName = configSettings->readBoolEntry("/showName", false); + showRange = configSettings->readBoolEntry("/showRange", false); + showData = configSettings->readBoolEntry("/showData", false); + optMode = (enum optionMode)configSettings->readNumEntry("/optionMode", false); + configSettings->endGroup(); + connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); + } + + for (i = 0; i < colNr; i++) + colMap[i] = colRevMap[i] = -1; + addColumn(promptColIdx, _("Option")); + + reinit(); +} + +bool ConfigList::menuSkip(struct menu *menu) +{ + if (optMode == normalOpt && menu_is_visible(menu)) + return false; + if (optMode == promptOpt && menu_has_prompt(menu)) + return false; + if (optMode == allOpt) + return false; + return true; +} + +void ConfigList::reinit(void) +{ + removeColumn(dataColIdx); + removeColumn(yesColIdx); + removeColumn(modColIdx); + removeColumn(noColIdx); + removeColumn(nameColIdx); + + if (showName) + addColumn(nameColIdx, _("Name")); + if (showRange) { + addColumn(noColIdx, "N"); + addColumn(modColIdx, "M"); + addColumn(yesColIdx, "Y"); + } + if (showData) + addColumn(dataColIdx, _("Value")); + + updateListAll(); +} + +void ConfigList::saveSettings(void) +{ + if (name()) { + configSettings->beginGroup(name()); + configSettings->writeEntry("/showName", showName); + configSettings->writeEntry("/showRange", showRange); + configSettings->writeEntry("/showData", showData); + configSettings->writeEntry("/optionMode", (int)optMode); + configSettings->endGroup(); + } +} + +ConfigItem* ConfigList::findConfigItem(struct menu *menu) +{ + ConfigItem* item = (ConfigItem*)menu->data; + + for (; item; item = item->nextItem) { + if (this == item->listView()) + break; + } + + return item; +} + +void ConfigList::updateSelection(void) +{ + struct menu *menu; + enum prop_type type; + + ConfigItem* item = (ConfigItem*)selectedItem(); + if (!item) + return; + + menu = item->menu; + emit menuChanged(menu); + if (!menu) + return; + type = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (mode == menuMode && type == P_MENU) + emit menuSelected(menu); +} + +void ConfigList::updateList(ConfigItem* item) +{ + ConfigItem* last = 0; + + if (!rootEntry) { + if (mode != listMode) + goto update; + Q3ListViewItemIterator it(this); + ConfigItem* item; + + for (; it.current(); ++it) { + item = (ConfigItem*)it.current(); + if (!item->menu) + continue; + item->testUpdateMenu(menu_is_visible(item->menu)); + } + return; + } + + if (rootEntry != &rootmenu && (mode == singleMode || + (mode == symbolMode && rootEntry->parent != &rootmenu))) { + item = firstChild(); + if (!item) + item = new ConfigItem(this, 0, true); + last = item; + } + if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) && + rootEntry->sym && rootEntry->prompt) { + item = last ? last->nextSibling() : firstChild(); + if (!item) + item = new ConfigItem(this, last, rootEntry, true); + else + item->testUpdateMenu(true); + + updateMenuList(item, rootEntry); + triggerUpdate(); + return; + } +update: + updateMenuList(this, rootEntry); + triggerUpdate(); +} + +void ConfigList::setValue(ConfigItem* item, tristate val) +{ + struct symbol* sym; + int type; + tristate oldval; + + sym = item->menu ? item->menu->sym : 0; + if (!sym) + return; + + type = sym_get_type(sym); + switch (type) { + case S_BOOLEAN: + case S_TRISTATE: + oldval = sym_get_tristate_value(sym); + + if (!sym_set_tristate_value(sym, val)) + return; + if (oldval == no && item->menu->list) + item->setOpen(TRUE); + parent()->updateList(item); + break; + } +} + +void ConfigList::changeValue(ConfigItem* item) +{ + struct symbol* sym; + struct menu* menu; + int type, oldexpr, newexpr; + + menu = item->menu; + if (!menu) + return; + sym = menu->sym; + if (!sym) { + if (item->menu->list) + item->setOpen(!item->isOpen()); + return; + } + + type = sym_get_type(sym); + switch (type) { + case S_BOOLEAN: + case S_TRISTATE: + oldexpr = sym_get_tristate_value(sym); + newexpr = sym_toggle_tristate_value(sym); + if (item->menu->list) { + if (oldexpr == newexpr) + item->setOpen(!item->isOpen()); + else if (oldexpr == no) + item->setOpen(TRUE); + } + if (oldexpr != newexpr) + parent()->updateList(item); + break; + case S_INT: + case S_HEX: + case S_STRING: + if (colMap[dataColIdx] >= 0) + item->startRename(colMap[dataColIdx]); + else + parent()->lineEdit->show(item); + break; + } +} + +void ConfigList::setRootMenu(struct menu *menu) +{ + enum prop_type type; + + if (rootEntry == menu) + return; + type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (type != P_MENU) + return; + updateMenuList(this, 0); + rootEntry = menu; + updateListAll(); + setSelected(currentItem(), hasFocus()); + ensureItemVisible(currentItem()); +} + +void ConfigList::setParentMenu(void) +{ + ConfigItem* item; + struct menu *oldroot; + + oldroot = rootEntry; + if (rootEntry == &rootmenu) + return; + setRootMenu(menu_get_parent_menu(rootEntry->parent)); + + Q3ListViewItemIterator it(this); + for (; (item = (ConfigItem*)it.current()); it++) { + if (item->menu == oldroot) { + setCurrentItem(item); + ensureItemVisible(item); + break; + } + } +} + +/* + * update all the children of a menu entry + * removes/adds the entries from the parent widget as necessary + * + * parent: either the menu list widget or a menu entry widget + * menu: entry to be updated + */ +template +void ConfigList::updateMenuList(P* parent, struct menu* menu) +{ + struct menu* child; + ConfigItem* item; + ConfigItem* last; + bool visible; + enum prop_type type; + + if (!menu) { + while ((item = parent->firstChild())) + delete item; + return; + } + + last = parent->firstChild(); + if (last && !last->goParent) + last = 0; + for (child = menu->list; child; child = child->next) { + item = last ? last->nextSibling() : parent->firstChild(); + type = child->prompt ? child->prompt->type : P_UNKNOWN; + + switch (mode) { + case menuMode: + if (!(child->flags & MENU_ROOT)) + goto hide; + break; + case symbolMode: + if (child->flags & MENU_ROOT) + goto hide; + break; + default: + break; + } + + visible = menu_is_visible(child); + if (!menuSkip(child)) { + if (!child->sym && !child->list && !child->prompt) + continue; + if (!item || item->menu != child) + item = new ConfigItem(parent, last, child, visible); + else + item->testUpdateMenu(visible); + + if (mode == fullMode || mode == menuMode || type != P_MENU) + updateMenuList(item, child); + else + updateMenuList(item, 0); + last = item; + continue; + } + hide: + if (item && item->menu == child) { + last = parent->firstChild(); + if (last == item) + last = 0; + else while (last->nextSibling() != item) + last = last->nextSibling(); + delete item; + } + } +} + +void ConfigList::keyPressEvent(QKeyEvent* ev) +{ + Q3ListViewItem* i = currentItem(); + ConfigItem* item; + struct menu *menu; + enum prop_type type; + + if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) { + emit parentSelected(); + ev->accept(); + return; + } + + if (!i) { + Parent::keyPressEvent(ev); + return; + } + item = (ConfigItem*)i; + + switch (ev->key()) { + case Qt::Key_Return: + case Qt::Key_Enter: + if (item->goParent) { + emit parentSelected(); + break; + } + menu = item->menu; + if (!menu) + break; + type = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (type == P_MENU && rootEntry != menu && + mode != fullMode && mode != menuMode) { + emit menuSelected(menu); + break; + } + case Qt::Key_Space: + changeValue(item); + break; + case Qt::Key_N: + setValue(item, no); + break; + case Qt::Key_M: + setValue(item, mod); + break; + case Qt::Key_Y: + setValue(item, yes); + break; + default: + Parent::keyPressEvent(ev); + return; + } + ev->accept(); +} + +void ConfigList::contentsMousePressEvent(QMouseEvent* e) +{ + //QPoint p(contentsToViewport(e->pos())); + //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y()); + Parent::contentsMousePressEvent(e); +} + +void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e) +{ + QPoint p(contentsToViewport(e->pos())); + ConfigItem* item = (ConfigItem*)itemAt(p); + struct menu *menu; + enum prop_type ptype; + const QPixmap* pm; + int idx, x; + + if (!item) + goto skip; + + menu = item->menu; + x = header()->offset() + p.x(); + idx = colRevMap[header()->sectionAt(x)]; + switch (idx) { + case promptColIdx: + pm = item->pixmap(promptColIdx); + if (pm) { + int off = header()->sectionPos(0) + itemMargin() + + treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0)); + if (x >= off && x < off + pm->width()) { + if (item->goParent) { + emit parentSelected(); + break; + } else if (!menu) + break; + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (ptype == P_MENU && rootEntry != menu && + mode != fullMode && mode != menuMode) + emit menuSelected(menu); + else + changeValue(item); + } + } + break; + case noColIdx: + setValue(item, no); + break; + case modColIdx: + setValue(item, mod); + break; + case yesColIdx: + setValue(item, yes); + break; + case dataColIdx: + changeValue(item); + break; + } + +skip: + //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y()); + Parent::contentsMouseReleaseEvent(e); +} + +void ConfigList::contentsMouseMoveEvent(QMouseEvent* e) +{ + //QPoint p(contentsToViewport(e->pos())); + //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y()); + Parent::contentsMouseMoveEvent(e); +} + +void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e) +{ + QPoint p(contentsToViewport(e->pos())); + ConfigItem* item = (ConfigItem*)itemAt(p); + struct menu *menu; + enum prop_type ptype; + + if (!item) + goto skip; + if (item->goParent) { + emit parentSelected(); + goto skip; + } + menu = item->menu; + if (!menu) + goto skip; + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (ptype == P_MENU && (mode == singleMode || mode == symbolMode)) + emit menuSelected(menu); + else if (menu->sym) + changeValue(item); + +skip: + //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y()); + Parent::contentsMouseDoubleClickEvent(e); +} + +void ConfigList::focusInEvent(QFocusEvent *e) +{ + struct menu *menu = NULL; + + Parent::focusInEvent(e); + + ConfigItem* item = (ConfigItem *)currentItem(); + if (item) { + setSelected(item, TRUE); + menu = item->menu; + } + emit gotFocus(menu); +} + +void ConfigList::contextMenuEvent(QContextMenuEvent *e) +{ + if (e->y() <= header()->geometry().bottom()) { + if (!headerPopup) { + Q3Action *action; + + headerPopup = new Q3PopupMenu(this); + action = new Q3Action(NULL, _("Show Name"), 0, this); + action->setToggleAction(TRUE); + connect(action, SIGNAL(toggled(bool)), + parent(), SLOT(setShowName(bool))); + connect(parent(), SIGNAL(showNameChanged(bool)), + action, SLOT(setOn(bool))); + action->setOn(showName); + action->addTo(headerPopup); + action = new Q3Action(NULL, _("Show Range"), 0, this); + action->setToggleAction(TRUE); + connect(action, SIGNAL(toggled(bool)), + parent(), SLOT(setShowRange(bool))); + connect(parent(), SIGNAL(showRangeChanged(bool)), + action, SLOT(setOn(bool))); + action->setOn(showRange); + action->addTo(headerPopup); + action = new Q3Action(NULL, _("Show Data"), 0, this); + action->setToggleAction(TRUE); + connect(action, SIGNAL(toggled(bool)), + parent(), SLOT(setShowData(bool))); + connect(parent(), SIGNAL(showDataChanged(bool)), + action, SLOT(setOn(bool))); + action->setOn(showData); + action->addTo(headerPopup); + } + headerPopup->exec(e->globalPos()); + e->accept(); + } else + e->ignore(); +} + +ConfigView*ConfigView::viewList; +QAction *ConfigView::showNormalAction; +QAction *ConfigView::showAllAction; +QAction *ConfigView::showPromptAction; + +ConfigView::ConfigView(QWidget* parent, const char *name) + : Parent(parent, name) +{ + list = new ConfigList(this, name); + lineEdit = new ConfigLineEdit(this); + lineEdit->hide(); + + this->nextView = viewList; + viewList = this; +} + +ConfigView::~ConfigView(void) +{ + ConfigView** vp; + + for (vp = &viewList; *vp; vp = &(*vp)->nextView) { + if (*vp == this) { + *vp = nextView; + break; + } + } +} + +void ConfigView::setOptionMode(QAction *act) +{ + if (act == showNormalAction) + list->optMode = normalOpt; + else if (act == showAllAction) + list->optMode = allOpt; + else + list->optMode = promptOpt; + + list->updateListAll(); +} + +void ConfigView::setShowName(bool b) +{ + if (list->showName != b) { + list->showName = b; + list->reinit(); + emit showNameChanged(b); + } +} + +void ConfigView::setShowRange(bool b) +{ + if (list->showRange != b) { + list->showRange = b; + list->reinit(); + emit showRangeChanged(b); + } +} + +void ConfigView::setShowData(bool b) +{ + if (list->showData != b) { + list->showData = b; + list->reinit(); + emit showDataChanged(b); + } +} + +void ConfigList::setAllOpen(bool open) +{ + Q3ListViewItemIterator it(this); + + for (; it.current(); it++) + it.current()->setOpen(open); +} + +void ConfigView::updateList(ConfigItem* item) +{ + ConfigView* v; + + for (v = viewList; v; v = v->nextView) + v->list->updateList(item); +} + +void ConfigView::updateListAll(void) +{ + ConfigView* v; + + for (v = viewList; v; v = v->nextView) + v->list->updateListAll(); +} + +ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name) + : Parent(parent, name), sym(0), _menu(0) +{ + if (name) { + configSettings->beginGroup(name); + _showDebug = configSettings->readBoolEntry("/showDebug", false); + configSettings->endGroup(); + connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); + } +} + +void ConfigInfoView::saveSettings(void) +{ + if (name()) { + configSettings->beginGroup(name()); + configSettings->writeEntry("/showDebug", showDebug()); + configSettings->endGroup(); + } +} + +void ConfigInfoView::setShowDebug(bool b) +{ + if (_showDebug != b) { + _showDebug = b; + if (_menu) + menuInfo(); + else if (sym) + symbolInfo(); + emit showDebugChanged(b); + } +} + +void ConfigInfoView::setInfo(struct menu *m) +{ + if (_menu == m) + return; + _menu = m; + sym = NULL; + if (!_menu) + clear(); + else + menuInfo(); +} + +void ConfigInfoView::symbolInfo(void) +{ + QString str; + + str += "Symbol: "; + str += print_filter(sym->name); + str += "

value: "; + str += print_filter(sym_get_string_value(sym)); + str += "
visibility: "; + str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n"; + str += "
"; + str += debug_info(sym); + + setText(str); +} + +void ConfigInfoView::menuInfo(void) +{ + struct symbol* sym; + QString head, debug, help; + + sym = _menu->sym; + if (sym) { + if (_menu->prompt) { + head += ""; + head += print_filter(_(_menu->prompt->text)); + head += ""; + if (sym->name) { + head += " ("; + if (showDebug()) + head += QString().sprintf("", sym); + head += print_filter(sym->name); + if (showDebug()) + head += ""; + head += ")"; + } + } else if (sym->name) { + head += ""; + if (showDebug()) + head += QString().sprintf("", sym); + head += print_filter(sym->name); + if (showDebug()) + head += ""; + head += ""; + } + head += "

"; + + if (showDebug()) + debug = debug_info(sym); + + struct gstr help_gstr = str_new(); + menu_get_ext_help(_menu, &help_gstr); + help = print_filter(str_get(&help_gstr)); + str_free(&help_gstr); + } else if (_menu->prompt) { + head += ""; + head += print_filter(_(_menu->prompt->text)); + head += "

"; + if (showDebug()) { + if (_menu->prompt->visible.expr) { + debug += "  dep: "; + expr_print(_menu->prompt->visible.expr, expr_print_help, &debug, E_NONE); + debug += "

"; + } + } + } + if (showDebug()) + debug += QString().sprintf("defined at %s:%d

", _menu->file->name, _menu->lineno); + + setText(head + debug + help); +} + +QString ConfigInfoView::debug_info(struct symbol *sym) +{ + QString debug; + + debug += "type: "; + debug += print_filter(sym_type_name(sym->type)); + if (sym_is_choice(sym)) + debug += " (choice)"; + debug += "
"; + if (sym->rev_dep.expr) { + debug += "reverse dep: "; + expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE); + debug += "
"; + } + for (struct property *prop = sym->prop; prop; prop = prop->next) { + switch (prop->type) { + case P_PROMPT: + case P_MENU: + debug += QString().sprintf("prompt: ", prop->menu); + debug += print_filter(_(prop->text)); + debug += "
"; + break; + case P_DEFAULT: + case P_SELECT: + case P_RANGE: + case P_ENV: + debug += prop_get_type_name(prop->type); + debug += ": "; + expr_print(prop->expr, expr_print_help, &debug, E_NONE); + debug += "
"; + break; + case P_CHOICE: + if (sym_is_choice(sym)) { + debug += "choice: "; + expr_print(prop->expr, expr_print_help, &debug, E_NONE); + debug += "
"; + } + break; + default: + debug += "unknown property: "; + debug += prop_get_type_name(prop->type); + debug += "
"; + } + if (prop->visible.expr) { + debug += "    dep: "; + expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE); + debug += "
"; + } + } + debug += "
"; + + return debug; +} + +QString ConfigInfoView::print_filter(const QString &str) +{ + QRegExp re("[<>&\"\\n]"); + QString res = str; + for (int i = 0; (i = res.find(re, i)) >= 0;) { + switch (res[i].latin1()) { + case '<': + res.replace(i, 1, "<"); + i += 4; + break; + case '>': + res.replace(i, 1, ">"); + i += 4; + break; + case '&': + res.replace(i, 1, "&"); + i += 5; + break; + case '"': + res.replace(i, 1, """); + i += 6; + break; + case '\n': + res.replace(i, 1, "
"); + i += 4; + break; + } + } + return res; +} + +void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str) +{ + QString* text = reinterpret_cast(data); + QString str2 = print_filter(str); + + if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) { + *text += QString().sprintf("", sym); + *text += str2; + *text += ""; + } else + *text += str2; +} + +Q3PopupMenu* ConfigInfoView::createPopupMenu(const QPoint& pos) +{ + Q3PopupMenu* popup = Parent::createPopupMenu(pos); + Q3Action* action = new Q3Action(NULL, _("Show Debug Info"), 0, popup); + action->setToggleAction(TRUE); + connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool))); + connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool))); + action->setOn(showDebug()); + popup->insertSeparator(); + action->addTo(popup); + return popup; +} + +void ConfigInfoView::contentsContextMenuEvent(QContextMenuEvent *e) +{ + Parent::contentsContextMenuEvent(e); +} + +ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name) + : Parent(parent, name), result(NULL) +{ + setCaption("Search Config"); + + QVBoxLayout* layout1 = new QVBoxLayout(this, 11, 6); + QHBoxLayout* layout2 = new QHBoxLayout(0, 0, 6); + layout2->addWidget(new QLabel(_("Find:"), this)); + editField = new QLineEdit(this); + connect(editField, SIGNAL(returnPressed()), SLOT(search())); + layout2->addWidget(editField); + searchButton = new QPushButton(_("Search"), this); + searchButton->setAutoDefault(FALSE); + connect(searchButton, SIGNAL(clicked()), SLOT(search())); + layout2->addWidget(searchButton); + layout1->addLayout(layout2); + + split = new QSplitter(this); + split->setOrientation(Qt::Vertical); + list = new ConfigView(split, name); + list->list->mode = listMode; + info = new ConfigInfoView(split, name); + connect(list->list, SIGNAL(menuChanged(struct menu *)), + info, SLOT(setInfo(struct menu *))); + connect(list->list, SIGNAL(menuChanged(struct menu *)), + parent, SLOT(setMenuLink(struct menu *))); + + layout1->addWidget(split); + + if (name) { + int x, y, width, height; + bool ok; + + configSettings->beginGroup(name); + width = configSettings->readNumEntry("/window width", parent->width() / 2); + height = configSettings->readNumEntry("/window height", parent->height() / 2); + resize(width, height); + x = configSettings->readNumEntry("/window x", 0, &ok); + if (ok) + y = configSettings->readNumEntry("/window y", 0, &ok); + if (ok) + move(x, y); + Q3ValueList sizes = configSettings->readSizes("/split", &ok); + if (ok) + split->setSizes(sizes); + configSettings->endGroup(); + connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); + } +} + +void ConfigSearchWindow::saveSettings(void) +{ + if (name()) { + configSettings->beginGroup(name()); + configSettings->writeEntry("/window x", pos().x()); + configSettings->writeEntry("/window y", pos().y()); + configSettings->writeEntry("/window width", size().width()); + configSettings->writeEntry("/window height", size().height()); + configSettings->writeSizes("/split", split->sizes()); + configSettings->endGroup(); + } +} + +void ConfigSearchWindow::search(void) +{ + struct symbol **p; + struct property *prop; + ConfigItem *lastItem = NULL; + + free(result); + list->list->clear(); + info->clear(); + + result = sym_re_search(editField->text().latin1()); + if (!result) + return; + for (p = result; *p; p++) { + for_all_prompts((*p), prop) + lastItem = new ConfigItem(list->list, lastItem, prop->menu, + menu_is_visible(prop->menu)); + } +} + +/* + * Construct the complete config widget + */ +ConfigMainWindow::ConfigMainWindow(void) + : searchWindow(0) +{ + QMenuBar* menu; + bool ok; + int x, y, width, height; + char title[256]; + + QDesktopWidget *d = configApp->desktop(); + snprintf(title, sizeof(title), "%s%s", + rootmenu.prompt->text, +#if QT_VERSION < 0x040000 + " (Qt3)" +#else + "" +#endif + ); + setCaption(title); + + width = configSettings->readNumEntry("/window width", d->width() - 64); + height = configSettings->readNumEntry("/window height", d->height() - 64); + resize(width, height); + x = configSettings->readNumEntry("/window x", 0, &ok); + if (ok) + y = configSettings->readNumEntry("/window y", 0, &ok); + if (ok) + move(x, y); + + split1 = new QSplitter(this); + split1->setOrientation(Qt::Horizontal); + setCentralWidget(split1); + + menuView = new ConfigView(split1, "menu"); + menuList = menuView->list; + + split2 = new QSplitter(split1); + split2->setOrientation(Qt::Vertical); + + // create config tree + configView = new ConfigView(split2, "config"); + configList = configView->list; + + helpText = new ConfigInfoView(split2, "help"); + helpText->setTextFormat(Qt::RichText); + + setTabOrder(configList, helpText); + configList->setFocus(); + + menu = menuBar(); + toolBar = new Q3ToolBar("Tools", this); + + backAction = new Q3Action("Back", QPixmap(xpm_back), _("Back"), 0, this); + connect(backAction, SIGNAL(activated()), SLOT(goBack())); + backAction->setEnabled(FALSE); + Q3Action *quitAction = new Q3Action("Quit", _("&Quit"), Qt::CTRL + Qt::Key_Q, this); + connect(quitAction, SIGNAL(activated()), SLOT(close())); + Q3Action *loadAction = new Q3Action("Load", QPixmap(xpm_load), _("&Load"), Qt::CTRL + Qt::Key_L, this); + connect(loadAction, SIGNAL(activated()), SLOT(loadConfig())); + saveAction = new Q3Action("Save", QPixmap(xpm_save), _("&Save"), Qt::CTRL + Qt::Key_S, this); + connect(saveAction, SIGNAL(activated()), SLOT(saveConfig())); + conf_set_changed_callback(conf_changed); + // Set saveAction's initial state + conf_changed(); + Q3Action *saveAsAction = new Q3Action("Save As...", _("Save &As..."), 0, this); + connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs())); + Q3Action *searchAction = new Q3Action("Find", _("&Find"), Qt::CTRL + Qt::Key_F, this); + connect(searchAction, SIGNAL(activated()), SLOT(searchConfig())); + Q3Action *singleViewAction = new Q3Action("Single View", QPixmap(xpm_single_view), _("Single View"), 0, this); + connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView())); + Q3Action *splitViewAction = new Q3Action("Split View", QPixmap(xpm_split_view), _("Split View"), 0, this); + connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView())); + Q3Action *fullViewAction = new Q3Action("Full View", QPixmap(xpm_tree_view), _("Full View"), 0, this); + connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView())); + + Q3Action *showNameAction = new Q3Action(NULL, _("Show Name"), 0, this); + showNameAction->setToggleAction(TRUE); + connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool))); + connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool))); + showNameAction->setOn(configView->showName()); + Q3Action *showRangeAction = new Q3Action(NULL, _("Show Range"), 0, this); + showRangeAction->setToggleAction(TRUE); + connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool))); + connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool))); + showRangeAction->setOn(configList->showRange); + Q3Action *showDataAction = new Q3Action(NULL, _("Show Data"), 0, this); + showDataAction->setToggleAction(TRUE); + connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool))); + connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool))); + showDataAction->setOn(configList->showData); + + QActionGroup *optGroup = new QActionGroup(this); + optGroup->setExclusive(TRUE); + connect(optGroup, SIGNAL(selected(QAction *)), configView, + SLOT(setOptionMode(QAction *))); + connect(optGroup, SIGNAL(selected(QAction *)), menuView, + SLOT(setOptionMode(QAction *))); + +#if QT_VERSION >= 0x040000 + configView->showNormalAction = new QAction(_("Show Normal Options"), optGroup); + configView->showAllAction = new QAction(_("Show All Options"), optGroup); + configView->showPromptAction = new QAction(_("Show Prompt Options"), optGroup); +#else + configView->showNormalAction = new QAction(_("Show Normal Options"), 0, optGroup); + configView->showAllAction = new QAction(_("Show All Options"), 0, optGroup); + configView->showPromptAction = new QAction(_("Show Prompt Options"), 0, optGroup); +#endif + configView->showNormalAction->setToggleAction(TRUE); + configView->showNormalAction->setOn(configList->optMode == normalOpt); + configView->showAllAction->setToggleAction(TRUE); + configView->showAllAction->setOn(configList->optMode == allOpt); + configView->showPromptAction->setToggleAction(TRUE); + configView->showPromptAction->setOn(configList->optMode == promptOpt); + + Q3Action *showDebugAction = new Q3Action(NULL, _("Show Debug Info"), 0, this); + showDebugAction->setToggleAction(TRUE); + connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool))); + connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool))); + showDebugAction->setOn(helpText->showDebug()); + + Q3Action *showIntroAction = new Q3Action(NULL, _("Introduction"), 0, this); + connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro())); + Q3Action *showAboutAction = new Q3Action(NULL, _("About"), 0, this); + connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout())); + + // init tool bar + backAction->addTo(toolBar); + toolBar->addSeparator(); + loadAction->addTo(toolBar); + saveAction->addTo(toolBar); + toolBar->addSeparator(); + singleViewAction->addTo(toolBar); + splitViewAction->addTo(toolBar); + fullViewAction->addTo(toolBar); + + // create config menu + Q3PopupMenu* config = new Q3PopupMenu(this); + menu->insertItem(_("&File"), config); + loadAction->addTo(config); + saveAction->addTo(config); + saveAsAction->addTo(config); + config->insertSeparator(); + quitAction->addTo(config); + + // create edit menu + Q3PopupMenu* editMenu = new Q3PopupMenu(this); + menu->insertItem(_("&Edit"), editMenu); + searchAction->addTo(editMenu); + + // create options menu + Q3PopupMenu* optionMenu = new Q3PopupMenu(this); + menu->insertItem(_("&Option"), optionMenu); + showNameAction->addTo(optionMenu); + showRangeAction->addTo(optionMenu); + showDataAction->addTo(optionMenu); + optionMenu->insertSeparator(); + optGroup->addTo(optionMenu); + optionMenu->insertSeparator(); + + // create help menu + Q3PopupMenu* helpMenu = new Q3PopupMenu(this); + menu->insertSeparator(); + menu->insertItem(_("&Help"), helpMenu); + showIntroAction->addTo(helpMenu); + showAboutAction->addTo(helpMenu); + + connect(configList, SIGNAL(menuChanged(struct menu *)), + helpText, SLOT(setInfo(struct menu *))); + connect(configList, SIGNAL(menuSelected(struct menu *)), + SLOT(changeMenu(struct menu *))); + connect(configList, SIGNAL(parentSelected()), + SLOT(goBack())); + connect(menuList, SIGNAL(menuChanged(struct menu *)), + helpText, SLOT(setInfo(struct menu *))); + connect(menuList, SIGNAL(menuSelected(struct menu *)), + SLOT(changeMenu(struct menu *))); + + connect(configList, SIGNAL(gotFocus(struct menu *)), + helpText, SLOT(setInfo(struct menu *))); + connect(menuList, SIGNAL(gotFocus(struct menu *)), + helpText, SLOT(setInfo(struct menu *))); + connect(menuList, SIGNAL(gotFocus(struct menu *)), + SLOT(listFocusChanged(void))); + connect(helpText, SIGNAL(menuSelected(struct menu *)), + SLOT(setMenuLink(struct menu *))); + + QString listMode = configSettings->readEntry("/listMode", "symbol"); + if (listMode == "single") + showSingleView(); + else if (listMode == "full") + showFullView(); + else /*if (listMode == "split")*/ + showSplitView(); + + // UI setup done, restore splitter positions + Q3ValueList sizes = configSettings->readSizes("/split1", &ok); + if (ok) + split1->setSizes(sizes); + + sizes = configSettings->readSizes("/split2", &ok); + if (ok) + split2->setSizes(sizes); +} + +void ConfigMainWindow::loadConfig(void) +{ + QString s = Q3FileDialog::getOpenFileName(conf_get_configname(), NULL, this); + if (s.isNull()) + return; + if (conf_read(QFile::encodeName(s))) + QMessageBox::information(this, "qconf", _("Unable to load configuration!")); + ConfigView::updateListAll(); +} + +void ConfigMainWindow::saveConfig(void) +{ + if (conf_write(NULL)) + QMessageBox::information(this, "qconf", _("Unable to save configuration!")); +} + +void ConfigMainWindow::saveConfigAs(void) +{ + QString s = Q3FileDialog::getSaveFileName(conf_get_configname(), NULL, this); + if (s.isNull()) + return; + if (conf_write(QFile::encodeName(s))) + QMessageBox::information(this, "qconf", _("Unable to save configuration!")); +} + +void ConfigMainWindow::searchConfig(void) +{ + if (!searchWindow) + searchWindow = new ConfigSearchWindow(this, "search"); + searchWindow->show(); +} + +void ConfigMainWindow::changeMenu(struct menu *menu) +{ + configList->setRootMenu(menu); + if (configList->rootEntry->parent == &rootmenu) + backAction->setEnabled(FALSE); + else + backAction->setEnabled(TRUE); +} + +void ConfigMainWindow::setMenuLink(struct menu *menu) +{ + struct menu *parent; + ConfigList* list = NULL; + ConfigItem* item; + + if (configList->menuSkip(menu)) + return; + + switch (configList->mode) { + case singleMode: + list = configList; + parent = menu_get_parent_menu(menu); + if (!parent) + return; + list->setRootMenu(parent); + break; + case symbolMode: + if (menu->flags & MENU_ROOT) { + configList->setRootMenu(menu); + configList->clearSelection(); + list = menuList; + } else { + list = configList; + parent = menu_get_parent_menu(menu->parent); + if (!parent) + return; + item = menuList->findConfigItem(parent); + if (item) { + menuList->setSelected(item, TRUE); + menuList->ensureItemVisible(item); + } + list->setRootMenu(parent); + } + break; + case fullMode: + list = configList; + break; + default: + break; + } + + if (list) { + item = list->findConfigItem(menu); + if (item) { + list->setSelected(item, TRUE); + list->ensureItemVisible(item); + list->setFocus(); + } + } +} + +void ConfigMainWindow::listFocusChanged(void) +{ + if (menuList->mode == menuMode) + configList->clearSelection(); +} + +void ConfigMainWindow::goBack(void) +{ + ConfigItem* item; + + configList->setParentMenu(); + if (configList->rootEntry == &rootmenu) + backAction->setEnabled(FALSE); + item = (ConfigItem*)menuList->selectedItem(); + while (item) { + if (item->menu == configList->rootEntry) { + menuList->setSelected(item, TRUE); + break; + } + item = (ConfigItem*)item->parent(); + } +} + +void ConfigMainWindow::showSingleView(void) +{ + menuView->hide(); + menuList->setRootMenu(0); + configList->mode = singleMode; + if (configList->rootEntry == &rootmenu) + configList->updateListAll(); + else + configList->setRootMenu(&rootmenu); + configList->setAllOpen(TRUE); + configList->setFocus(); +} + +void ConfigMainWindow::showSplitView(void) +{ + configList->mode = symbolMode; + if (configList->rootEntry == &rootmenu) + configList->updateListAll(); + else + configList->setRootMenu(&rootmenu); + configList->setAllOpen(TRUE); + configApp->processEvents(); + menuList->mode = menuMode; + menuList->setRootMenu(&rootmenu); + menuList->setAllOpen(TRUE); + menuView->show(); + menuList->setFocus(); +} + +void ConfigMainWindow::showFullView(void) +{ + menuView->hide(); + menuList->setRootMenu(0); + configList->mode = fullMode; + if (configList->rootEntry == &rootmenu) + configList->updateListAll(); + else + configList->setRootMenu(&rootmenu); + configList->setAllOpen(FALSE); + configList->setFocus(); +} + +/* + * ask for saving configuration before quitting + * TODO ask only when something changed + */ +void ConfigMainWindow::closeEvent(QCloseEvent* e) +{ + if (!conf_get_changed()) { + e->accept(); + return; + } + QMessageBox mb("qconf", _("Save configuration?"), QMessageBox::Warning, + QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape); + mb.setButtonText(QMessageBox::Yes, _("&Save Changes")); + mb.setButtonText(QMessageBox::No, _("&Discard Changes")); + mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit")); + switch (mb.exec()) { + case QMessageBox::Yes: + conf_write(NULL); + case QMessageBox::No: + e->accept(); + break; + case QMessageBox::Cancel: + e->ignore(); + break; + } +} + +void ConfigMainWindow::showIntro(void) +{ + static const QString str = _("Welcome to the qconf graphical configuration tool.\n\n" + "For each option, a blank box indicates the feature is disabled, a check\n" + "indicates it is enabled, and a dot indicates that it is to be compiled\n" + "as a module. Clicking on the box will cycle through the three states.\n\n" + "If you do not see an option (e.g., a device driver) that you believe\n" + "should be present, try turning on Show All Options under the Options menu.\n" + "Although there is no cross reference yet to help you figure out what other\n" + "options must be enabled to support the option you are interested in, you can\n" + "still view the help of a grayed-out option.\n\n" + "Toggling Show Debug Info under the Options menu will show the dependencies,\n" + "which you can then match by examining other options.\n\n"); + + QMessageBox::information(this, "qconf", str); +} + +void ConfigMainWindow::showAbout(void) +{ + static const QString str = _("qconf is Copyright (C) 2002 Roman Zippel .\n\n" + "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n"); + + QMessageBox::information(this, "qconf", str); +} + +void ConfigMainWindow::saveSettings(void) +{ + configSettings->writeEntry("/window x", pos().x()); + configSettings->writeEntry("/window y", pos().y()); + configSettings->writeEntry("/window width", size().width()); + configSettings->writeEntry("/window height", size().height()); + + QString entry; + switch(configList->mode) { + case singleMode : + entry = "single"; + break; + + case symbolMode : + entry = "split"; + break; + + case fullMode : + entry = "full"; + break; + + default: + break; + } + configSettings->writeEntry("/listMode", entry); + + configSettings->writeSizes("/split1", split1->sizes()); + configSettings->writeSizes("/split2", split2->sizes()); +} + +void ConfigMainWindow::conf_changed(void) +{ + if (saveAction) + saveAction->setEnabled(conf_get_changed()); +} + +void fixup_rootmenu(struct menu *menu) +{ + struct menu *child; + static int menu_cnt = 0; + + menu->flags |= MENU_ROOT; + for (child = menu->list; child; child = child->next) { + if (child->prompt && child->prompt->type == P_MENU) { + menu_cnt++; + fixup_rootmenu(child); + menu_cnt--; + } else if (!menu_cnt) + fixup_rootmenu(child); + } +} + +static const char *progname; + +static void usage(void) +{ + printf(_("%s \n"), progname); + exit(0); +} + +int main(int ac, char** av) +{ + ConfigMainWindow* v; + const char *name; + + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + +#ifndef LKC_DIRECT_LINK + kconfig_load(); +#endif + + progname = av[0]; + configApp = new QApplication(ac, av); + if (ac > 1 && av[1][0] == '-') { + switch (av[1][1]) { + case 'h': + case '?': + usage(); + } + name = av[2]; + } else + name = av[1]; + if (!name) + usage(); + + conf_parse(name); + fixup_rootmenu(&rootmenu); + conf_read(NULL); + //zconfdump(stdout); + + configSettings = new ConfigSettings(); + configSettings->beginGroup("/kconfig/qconf"); + v = new ConfigMainWindow(); + + //zconfdump(stdout); + configApp->setMainWidget(v); + configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit())); + configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings())); + v->show(); + configApp->exec(); + + configSettings->endGroup(); + delete configSettings; + + return 0; +} diff --git a/bios/seabios/tools/kconfig/qconf.h b/bios/seabios/tools/kconfig/qconf.h new file mode 100644 index 0000000..91677d9 --- /dev/null +++ b/bios/seabios/tools/kconfig/qconf.h @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#if QT_VERSION < 0x040000 +#include +#else +#include +#endif +#include + +#if QT_VERSION < 0x040000 +#define Q3ValueList QValueList +#define Q3PopupMenu QPopupMenu +#define Q3ListView QListView +#define Q3ListViewItem QListViewItem +#define Q3VBox QVBox +#define Q3TextBrowser QTextBrowser +#define Q3MainWindow QMainWindow +#define Q3Action QAction +#define Q3ToolBar QToolBar +#define Q3ListViewItemIterator QListViewItemIterator +#define Q3FileDialog QFileDialog +#endif + +class ConfigView; +class ConfigList; +class ConfigItem; +class ConfigLineEdit; +class ConfigMainWindow; + +class ConfigSettings : public QSettings { +public: + Q3ValueList readSizes(const QString& key, bool *ok); + bool writeSizes(const QString& key, const Q3ValueList& value); +}; + +enum colIdx { + promptColIdx, nameColIdx, noColIdx, modColIdx, yesColIdx, dataColIdx, colNr +}; +enum listMode { + singleMode, menuMode, symbolMode, fullMode, listMode +}; +enum optionMode { + normalOpt = 0, allOpt, promptOpt +}; + +class ConfigList : public Q3ListView { + Q_OBJECT + typedef class Q3ListView Parent; +public: + ConfigList(ConfigView* p, const char *name = 0); + void reinit(void); + ConfigView* parent(void) const + { + return (ConfigView*)Parent::parent(); + } + ConfigItem* findConfigItem(struct menu *); + +protected: + void keyPressEvent(QKeyEvent *e); + void contentsMousePressEvent(QMouseEvent *e); + void contentsMouseReleaseEvent(QMouseEvent *e); + void contentsMouseMoveEvent(QMouseEvent *e); + void contentsMouseDoubleClickEvent(QMouseEvent *e); + void focusInEvent(QFocusEvent *e); + void contextMenuEvent(QContextMenuEvent *e); + +public slots: + void setRootMenu(struct menu *menu); + + void updateList(ConfigItem *item); + void setValue(ConfigItem* item, tristate val); + void changeValue(ConfigItem* item); + void updateSelection(void); + void saveSettings(void); +signals: + void menuChanged(struct menu *menu); + void menuSelected(struct menu *menu); + void parentSelected(void); + void gotFocus(struct menu *); + +public: + void updateListAll(void) + { + updateAll = true; + updateList(NULL); + updateAll = false; + } + ConfigList* listView() + { + return this; + } + ConfigItem* firstChild() const + { + return (ConfigItem *)Parent::firstChild(); + } + int mapIdx(colIdx idx) + { + return colMap[idx]; + } + void addColumn(colIdx idx, const QString& label) + { + colMap[idx] = Parent::addColumn(label); + colRevMap[colMap[idx]] = idx; + } + void removeColumn(colIdx idx) + { + int col = colMap[idx]; + if (col >= 0) { + Parent::removeColumn(col); + colRevMap[col] = colMap[idx] = -1; + } + } + void setAllOpen(bool open); + void setParentMenu(void); + + bool menuSkip(struct menu *); + + template + void updateMenuList(P*, struct menu*); + + bool updateAll; + + QPixmap symbolYesPix, symbolModPix, symbolNoPix; + QPixmap choiceYesPix, choiceNoPix; + QPixmap menuPix, menuInvPix, menuBackPix, voidPix; + + bool showName, showRange, showData; + enum listMode mode; + enum optionMode optMode; + struct menu *rootEntry; + QColorGroup disabledColorGroup; + QColorGroup inactivedColorGroup; + Q3PopupMenu* headerPopup; + +private: + int colMap[colNr]; + int colRevMap[colNr]; +}; + +class ConfigItem : public Q3ListViewItem { + typedef class Q3ListViewItem Parent; +public: + ConfigItem(Q3ListView *parent, ConfigItem *after, struct menu *m, bool v) + : Parent(parent, after), menu(m), visible(v), goParent(false) + { + init(); + } + ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool v) + : Parent(parent, after), menu(m), visible(v), goParent(false) + { + init(); + } + ConfigItem(Q3ListView *parent, ConfigItem *after, bool v) + : Parent(parent, after), menu(0), visible(v), goParent(true) + { + init(); + } + ~ConfigItem(void); + void init(void); + void okRename(int col); + void updateMenu(void); + void testUpdateMenu(bool v); + ConfigList* listView() const + { + return (ConfigList*)Parent::listView(); + } + ConfigItem* firstChild() const + { + return (ConfigItem *)Parent::firstChild(); + } + ConfigItem* nextSibling() const + { + return (ConfigItem *)Parent::nextSibling(); + } + void setText(colIdx idx, const QString& text) + { + Parent::setText(listView()->mapIdx(idx), text); + } + QString text(colIdx idx) const + { + return Parent::text(listView()->mapIdx(idx)); + } + void setPixmap(colIdx idx, const QPixmap& pm) + { + Parent::setPixmap(listView()->mapIdx(idx), pm); + } + const QPixmap* pixmap(colIdx idx) const + { + return Parent::pixmap(listView()->mapIdx(idx)); + } + void paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align); + + ConfigItem* nextItem; + struct menu *menu; + bool visible; + bool goParent; +}; + +class ConfigLineEdit : public QLineEdit { + Q_OBJECT + typedef class QLineEdit Parent; +public: + ConfigLineEdit(ConfigView* parent); + ConfigView* parent(void) const + { + return (ConfigView*)Parent::parent(); + } + void show(ConfigItem *i); + void keyPressEvent(QKeyEvent *e); + +public: + ConfigItem *item; +}; + +class ConfigView : public Q3VBox { + Q_OBJECT + typedef class Q3VBox Parent; +public: + ConfigView(QWidget* parent, const char *name = 0); + ~ConfigView(void); + static void updateList(ConfigItem* item); + static void updateListAll(void); + + bool showName(void) const { return list->showName; } + bool showRange(void) const { return list->showRange; } + bool showData(void) const { return list->showData; } +public slots: + void setShowName(bool); + void setShowRange(bool); + void setShowData(bool); + void setOptionMode(QAction *); +signals: + void showNameChanged(bool); + void showRangeChanged(bool); + void showDataChanged(bool); +public: + ConfigList* list; + ConfigLineEdit* lineEdit; + + static ConfigView* viewList; + ConfigView* nextView; + + static QAction *showNormalAction; + static QAction *showAllAction; + static QAction *showPromptAction; +}; + +class ConfigInfoView : public Q3TextBrowser { + Q_OBJECT + typedef class Q3TextBrowser Parent; +public: + ConfigInfoView(QWidget* parent, const char *name = 0); + bool showDebug(void) const { return _showDebug; } + +public slots: + void setInfo(struct menu *menu); + void saveSettings(void); + void setShowDebug(bool); + +signals: + void showDebugChanged(bool); + void menuSelected(struct menu *); + +protected: + void symbolInfo(void); + void menuInfo(void); + QString debug_info(struct symbol *sym); + static QString print_filter(const QString &str); + static void expr_print_help(void *data, struct symbol *sym, const char *str); + Q3PopupMenu* createPopupMenu(const QPoint& pos); + void contentsContextMenuEvent(QContextMenuEvent *e); + + struct symbol *sym; + struct menu *_menu; + bool _showDebug; +}; + +class ConfigSearchWindow : public QDialog { + Q_OBJECT + typedef class QDialog Parent; +public: + ConfigSearchWindow(ConfigMainWindow* parent, const char *name = 0); + +public slots: + void saveSettings(void); + void search(void); + +protected: + QLineEdit* editField; + QPushButton* searchButton; + QSplitter* split; + ConfigView* list; + ConfigInfoView* info; + + struct symbol **result; +}; + +class ConfigMainWindow : public Q3MainWindow { + Q_OBJECT + + static Q3Action *saveAction; + static void conf_changed(void); +public: + ConfigMainWindow(void); +public slots: + void changeMenu(struct menu *); + void setMenuLink(struct menu *); + void listFocusChanged(void); + void goBack(void); + void loadConfig(void); + void saveConfig(void); + void saveConfigAs(void); + void searchConfig(void); + void showSingleView(void); + void showSplitView(void); + void showFullView(void); + void showIntro(void); + void showAbout(void); + void saveSettings(void); + +protected: + void closeEvent(QCloseEvent *e); + + ConfigSearchWindow *searchWindow; + ConfigView *menuView; + ConfigList *menuList; + ConfigView *configView; + ConfigList *configList; + ConfigInfoView *helpText; + Q3ToolBar *toolBar; + Q3Action *backAction; + QSplitter* split1; + QSplitter* split2; +}; diff --git a/bios/seabios/tools/kconfig/symbol.c b/bios/seabios/tools/kconfig/symbol.c new file mode 100644 index 0000000..a796c95 --- /dev/null +++ b/bios/seabios/tools/kconfig/symbol.c @@ -0,0 +1,1260 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +struct symbol symbol_yes = { + .name = "y", + .curr = { "y", yes }, + .flags = SYMBOL_CONST|SYMBOL_VALID, +}, symbol_mod = { + .name = "m", + .curr = { "m", mod }, + .flags = SYMBOL_CONST|SYMBOL_VALID, +}, symbol_no = { + .name = "n", + .curr = { "n", no }, + .flags = SYMBOL_CONST|SYMBOL_VALID, +}, symbol_empty = { + .name = "", + .curr = { "", no }, + .flags = SYMBOL_VALID, +}; + +struct symbol *sym_defconfig_list; +struct symbol *modules_sym; +tristate modules_val; + +struct expr *sym_env_list; + +static void sym_add_default(struct symbol *sym, const char *def) +{ + struct property *prop = prop_alloc(P_DEFAULT, sym); + + prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST)); +} + +void sym_init(void) +{ + struct symbol *sym; + struct utsname uts; + static bool inited = false; + + if (inited) + return; + inited = true; + + uname(&uts); + + sym = sym_lookup("UNAME_RELEASE", 0); + sym->type = S_STRING; + sym->flags |= SYMBOL_AUTO; + sym_add_default(sym, uts.release); +} + +enum symbol_type sym_get_type(struct symbol *sym) +{ + enum symbol_type type = sym->type; + + if (type == S_TRISTATE) { + if (sym_is_choice_value(sym) && sym->visible == yes) + type = S_BOOLEAN; + else if (modules_val == no) + type = S_BOOLEAN; + } + return type; +} + +const char *sym_type_name(enum symbol_type type) +{ + switch (type) { + case S_BOOLEAN: + return "boolean"; + case S_TRISTATE: + return "tristate"; + case S_INT: + return "integer"; + case S_HEX: + return "hex"; + case S_STRING: + return "string"; + case S_UNKNOWN: + return "unknown"; + case S_OTHER: + break; + } + return "???"; +} + +struct property *sym_get_choice_prop(struct symbol *sym) +{ + struct property *prop; + + for_all_choices(sym, prop) + return prop; + return NULL; +} + +struct property *sym_get_env_prop(struct symbol *sym) +{ + struct property *prop; + + for_all_properties(sym, prop, P_ENV) + return prop; + return NULL; +} + +struct property *sym_get_default_prop(struct symbol *sym) +{ + struct property *prop; + + for_all_defaults(sym, prop) { + prop->visible.tri = expr_calc_value(prop->visible.expr); + if (prop->visible.tri != no) + return prop; + } + return NULL; +} + +static struct property *sym_get_range_prop(struct symbol *sym) +{ + struct property *prop; + + for_all_properties(sym, prop, P_RANGE) { + prop->visible.tri = expr_calc_value(prop->visible.expr); + if (prop->visible.tri != no) + return prop; + } + return NULL; +} + +static int sym_get_range_val(struct symbol *sym, int base) +{ + sym_calc_value(sym); + switch (sym->type) { + case S_INT: + base = 10; + break; + case S_HEX: + base = 16; + break; + default: + break; + } + return strtol(sym->curr.val, NULL, base); +} + +static void sym_validate_range(struct symbol *sym) +{ + struct property *prop; + int base, val, val2; + char str[64]; + + switch (sym->type) { + case S_INT: + base = 10; + break; + case S_HEX: + base = 16; + break; + default: + return; + } + prop = sym_get_range_prop(sym); + if (!prop) + return; + val = strtol(sym->curr.val, NULL, base); + val2 = sym_get_range_val(prop->expr->left.sym, base); + if (val >= val2) { + val2 = sym_get_range_val(prop->expr->right.sym, base); + if (val <= val2) + return; + } + if (sym->type == S_INT) + sprintf(str, "%d", val2); + else + sprintf(str, "0x%x", val2); + sym->curr.val = strdup(str); +} + +static void sym_calc_visibility(struct symbol *sym) +{ + struct property *prop; + tristate tri; + + /* any prompt visible? */ + tri = no; + for_all_prompts(sym, prop) { + prop->visible.tri = expr_calc_value(prop->visible.expr); + tri = EXPR_OR(tri, prop->visible.tri); + } + if (tri == mod && (sym->type != S_TRISTATE || modules_val == no)) + tri = yes; + if (sym->visible != tri) { + sym->visible = tri; + sym_set_changed(sym); + } + if (sym_is_choice_value(sym)) + return; + /* defaulting to "yes" if no explicit "depends on" are given */ + tri = yes; + if (sym->dir_dep.expr) + tri = expr_calc_value(sym->dir_dep.expr); + if (tri == mod) + tri = yes; + if (sym->dir_dep.tri != tri) { + sym->dir_dep.tri = tri; + sym_set_changed(sym); + } + tri = no; + if (sym->rev_dep.expr) + tri = expr_calc_value(sym->rev_dep.expr); + if (tri == mod && sym_get_type(sym) == S_BOOLEAN) + tri = yes; + if (sym->rev_dep.tri != tri) { + sym->rev_dep.tri = tri; + sym_set_changed(sym); + } +} + +/* + * Find the default symbol for a choice. + * First try the default values for the choice symbol + * Next locate the first visible choice value + * Return NULL if none was found + */ +struct symbol *sym_choice_default(struct symbol *sym) +{ + struct symbol *def_sym; + struct property *prop; + struct expr *e; + + /* any of the defaults visible? */ + for_all_defaults(sym, prop) { + prop->visible.tri = expr_calc_value(prop->visible.expr); + if (prop->visible.tri == no) + continue; + def_sym = prop_get_symbol(prop); + if (def_sym->visible != no) + return def_sym; + } + + /* just get the first visible value */ + prop = sym_get_choice_prop(sym); + expr_list_for_each_sym(prop->expr, e, def_sym) + if (def_sym->visible != no) + return def_sym; + + /* failed to locate any defaults */ + return NULL; +} + +static struct symbol *sym_calc_choice(struct symbol *sym) +{ + struct symbol *def_sym; + struct property *prop; + struct expr *e; + + /* first calculate all choice values' visibilities */ + prop = sym_get_choice_prop(sym); + expr_list_for_each_sym(prop->expr, e, def_sym) + sym_calc_visibility(def_sym); + + /* is the user choice visible? */ + def_sym = sym->def[S_DEF_USER].val; + if (def_sym && def_sym->visible != no) + return def_sym; + + def_sym = sym_choice_default(sym); + + if (def_sym == NULL) + /* no choice? reset tristate value */ + sym->curr.tri = no; + + return def_sym; +} + +void sym_calc_value(struct symbol *sym) +{ + struct symbol_value newval, oldval; + struct property *prop; + struct expr *e; + + if (!sym) + return; + + if (sym->flags & SYMBOL_VALID) + return; + sym->flags |= SYMBOL_VALID; + + oldval = sym->curr; + + switch (sym->type) { + case S_INT: + case S_HEX: + case S_STRING: + newval = symbol_empty.curr; + break; + case S_BOOLEAN: + case S_TRISTATE: + newval = symbol_no.curr; + break; + default: + sym->curr.val = sym->name; + sym->curr.tri = no; + return; + } + if (!sym_is_choice_value(sym)) + sym->flags &= ~SYMBOL_WRITE; + + sym_calc_visibility(sym); + + /* set default if recursively called */ + sym->curr = newval; + + switch (sym_get_type(sym)) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym_is_choice_value(sym) && sym->visible == yes) { + prop = sym_get_choice_prop(sym); + newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no; + } else { + if (sym->visible != no) { + /* if the symbol is visible use the user value + * if available, otherwise try the default value + */ + sym->flags |= SYMBOL_WRITE; + if (sym_has_value(sym)) { + newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, + sym->visible); + goto calc_newval; + } + } + if (sym->rev_dep.tri != no) + sym->flags |= SYMBOL_WRITE; + if (!sym_is_choice(sym)) { + prop = sym_get_default_prop(sym); + if (prop) { + sym->flags |= SYMBOL_WRITE; + newval.tri = EXPR_AND(expr_calc_value(prop->expr), + prop->visible.tri); + } + } + calc_newval: + if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) { + struct expr *e; + e = expr_simplify_unmet_dep(sym->rev_dep.expr, + sym->dir_dep.expr); + fprintf(stderr, "warning: ("); + expr_fprint(e, stderr); + fprintf(stderr, ") selects %s which has unmet direct dependencies (", + sym->name); + expr_fprint(sym->dir_dep.expr, stderr); + fprintf(stderr, ")\n"); + expr_free(e); + } + newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri); + } + if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN) + newval.tri = yes; + break; + case S_STRING: + case S_HEX: + case S_INT: + if (sym->visible != no) { + sym->flags |= SYMBOL_WRITE; + if (sym_has_value(sym)) { + newval.val = sym->def[S_DEF_USER].val; + break; + } + } + prop = sym_get_default_prop(sym); + if (prop) { + struct symbol *ds = prop_get_symbol(prop); + if (ds) { + sym->flags |= SYMBOL_WRITE; + sym_calc_value(ds); + newval.val = ds->curr.val; + } + } + break; + default: + ; + } + + sym->curr = newval; + if (sym_is_choice(sym) && newval.tri == yes) + sym->curr.val = sym_calc_choice(sym); + sym_validate_range(sym); + + if (memcmp(&oldval, &sym->curr, sizeof(oldval))) { + sym_set_changed(sym); + if (modules_sym == sym) { + sym_set_all_changed(); + modules_val = modules_sym->curr.tri; + } + } + + if (sym_is_choice(sym)) { + struct symbol *choice_sym; + + prop = sym_get_choice_prop(sym); + expr_list_for_each_sym(prop->expr, e, choice_sym) { + if ((sym->flags & SYMBOL_WRITE) && + choice_sym->visible != no) + choice_sym->flags |= SYMBOL_WRITE; + if (sym->flags & SYMBOL_CHANGED) + sym_set_changed(choice_sym); + } + } + + if (sym->flags & SYMBOL_AUTO) + sym->flags &= ~SYMBOL_WRITE; +} + +void sym_clear_all_valid(void) +{ + struct symbol *sym; + int i; + + for_all_symbols(i, sym) + sym->flags &= ~SYMBOL_VALID; + sym_add_change_count(1); + if (modules_sym) + sym_calc_value(modules_sym); +} + +void sym_set_changed(struct symbol *sym) +{ + struct property *prop; + + sym->flags |= SYMBOL_CHANGED; + for (prop = sym->prop; prop; prop = prop->next) { + if (prop->menu) + prop->menu->flags |= MENU_CHANGED; + } +} + +void sym_set_all_changed(void) +{ + struct symbol *sym; + int i; + + for_all_symbols(i, sym) + sym_set_changed(sym); +} + +bool sym_tristate_within_range(struct symbol *sym, tristate val) +{ + int type = sym_get_type(sym); + + if (sym->visible == no) + return false; + + if (type != S_BOOLEAN && type != S_TRISTATE) + return false; + + if (type == S_BOOLEAN && val == mod) + return false; + if (sym->visible <= sym->rev_dep.tri) + return false; + if (sym_is_choice_value(sym) && sym->visible == yes) + return val == yes; + return val >= sym->rev_dep.tri && val <= sym->visible; +} + +bool sym_set_tristate_value(struct symbol *sym, tristate val) +{ + tristate oldval = sym_get_tristate_value(sym); + + if (oldval != val && !sym_tristate_within_range(sym, val)) + return false; + + if (!(sym->flags & SYMBOL_DEF_USER)) { + sym->flags |= SYMBOL_DEF_USER; + sym_set_changed(sym); + } + /* + * setting a choice value also resets the new flag of the choice + * symbol and all other choice values. + */ + if (sym_is_choice_value(sym) && val == yes) { + struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); + struct property *prop; + struct expr *e; + + cs->def[S_DEF_USER].val = sym; + cs->flags |= SYMBOL_DEF_USER; + prop = sym_get_choice_prop(cs); + for (e = prop->expr; e; e = e->left.expr) { + if (e->right.sym->visible != no) + e->right.sym->flags |= SYMBOL_DEF_USER; + } + } + + sym->def[S_DEF_USER].tri = val; + if (oldval != val) + sym_clear_all_valid(); + + return true; +} + +tristate sym_toggle_tristate_value(struct symbol *sym) +{ + tristate oldval, newval; + + oldval = newval = sym_get_tristate_value(sym); + do { + switch (newval) { + case no: + newval = mod; + break; + case mod: + newval = yes; + break; + case yes: + newval = no; + break; + } + if (sym_set_tristate_value(sym, newval)) + break; + } while (oldval != newval); + return newval; +} + +bool sym_string_valid(struct symbol *sym, const char *str) +{ + signed char ch; + + switch (sym->type) { + case S_STRING: + return true; + case S_INT: + ch = *str++; + if (ch == '-') + ch = *str++; + if (!isdigit(ch)) + return false; + if (ch == '0' && *str != 0) + return false; + while ((ch = *str++)) { + if (!isdigit(ch)) + return false; + } + return true; + case S_HEX: + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) + str += 2; + ch = *str++; + do { + if (!isxdigit(ch)) + return false; + } while ((ch = *str++)); + return true; + case S_BOOLEAN: + case S_TRISTATE: + switch (str[0]) { + case 'y': case 'Y': + case 'm': case 'M': + case 'n': case 'N': + return true; + } + return false; + default: + return false; + } +} + +bool sym_string_within_range(struct symbol *sym, const char *str) +{ + struct property *prop; + int val; + + switch (sym->type) { + case S_STRING: + return sym_string_valid(sym, str); + case S_INT: + if (!sym_string_valid(sym, str)) + return false; + prop = sym_get_range_prop(sym); + if (!prop) + return true; + val = strtol(str, NULL, 10); + return val >= sym_get_range_val(prop->expr->left.sym, 10) && + val <= sym_get_range_val(prop->expr->right.sym, 10); + case S_HEX: + if (!sym_string_valid(sym, str)) + return false; + prop = sym_get_range_prop(sym); + if (!prop) + return true; + val = strtol(str, NULL, 16); + return val >= sym_get_range_val(prop->expr->left.sym, 16) && + val <= sym_get_range_val(prop->expr->right.sym, 16); + case S_BOOLEAN: + case S_TRISTATE: + switch (str[0]) { + case 'y': case 'Y': + return sym_tristate_within_range(sym, yes); + case 'm': case 'M': + return sym_tristate_within_range(sym, mod); + case 'n': case 'N': + return sym_tristate_within_range(sym, no); + } + return false; + default: + return false; + } +} + +bool sym_set_string_value(struct symbol *sym, const char *newval) +{ + const char *oldval; + char *val; + int size; + + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + switch (newval[0]) { + case 'y': case 'Y': + return sym_set_tristate_value(sym, yes); + case 'm': case 'M': + return sym_set_tristate_value(sym, mod); + case 'n': case 'N': + return sym_set_tristate_value(sym, no); + } + return false; + default: + ; + } + + if (!sym_string_within_range(sym, newval)) + return false; + + if (!(sym->flags & SYMBOL_DEF_USER)) { + sym->flags |= SYMBOL_DEF_USER; + sym_set_changed(sym); + } + + oldval = sym->def[S_DEF_USER].val; + size = strlen(newval) + 1; + if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) { + size += 2; + sym->def[S_DEF_USER].val = val = malloc(size); + *val++ = '0'; + *val++ = 'x'; + } else if (!oldval || strcmp(oldval, newval)) + sym->def[S_DEF_USER].val = val = malloc(size); + else + return true; + + strcpy(val, newval); + free((void *)oldval); + sym_clear_all_valid(); + + return true; +} + +/* + * Find the default value associated to a symbol. + * For tristate symbol handle the modules=n case + * in which case "m" becomes "y". + * If the symbol does not have any default then fallback + * to the fixed default values. + */ +const char *sym_get_string_default(struct symbol *sym) +{ + struct property *prop; + struct symbol *ds; + const char *str; + tristate val; + + sym_calc_visibility(sym); + sym_calc_value(modules_sym); + val = symbol_no.curr.tri; + str = symbol_empty.curr.val; + + /* If symbol has a default value look it up */ + prop = sym_get_default_prop(sym); + if (prop != NULL) { + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + /* The visibility may limit the value from yes => mod */ + val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri); + break; + default: + /* + * The following fails to handle the situation + * where a default value is further limited by + * the valid range. + */ + ds = prop_get_symbol(prop); + if (ds != NULL) { + sym_calc_value(ds); + str = (const char *)ds->curr.val; + } + } + } + + /* Handle select statements */ + val = EXPR_OR(val, sym->rev_dep.tri); + + /* transpose mod to yes if modules are not enabled */ + if (val == mod) + if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no) + val = yes; + + /* transpose mod to yes if type is bool */ + if (sym->type == S_BOOLEAN && val == mod) + val = yes; + + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + switch (val) { + case no: return "n"; + case mod: return "m"; + case yes: return "y"; + } + case S_INT: + case S_HEX: + return str; + case S_STRING: + return str; + case S_OTHER: + case S_UNKNOWN: + break; + } + return ""; +} + +const char *sym_get_string_value(struct symbol *sym) +{ + tristate val; + + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + val = sym_get_tristate_value(sym); + switch (val) { + case no: + return "n"; + case mod: + return "m"; + case yes: + return "y"; + } + break; + default: + ; + } + return (const char *)sym->curr.val; +} + +bool sym_is_changable(struct symbol *sym) +{ + return sym->visible > sym->rev_dep.tri; +} + +static unsigned strhash(const char *s) +{ + /* fnv32 hash */ + unsigned hash = 2166136261U; + for (; *s; s++) + hash = (hash ^ *s) * 0x01000193; + return hash; +} + +struct symbol *sym_lookup(const char *name, int flags) +{ + struct symbol *symbol; + char *new_name; + int hash; + + if (name) { + if (name[0] && !name[1]) { + switch (name[0]) { + case 'y': return &symbol_yes; + case 'm': return &symbol_mod; + case 'n': return &symbol_no; + } + } + hash = strhash(name) % SYMBOL_HASHSIZE; + + for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { + if (symbol->name && + !strcmp(symbol->name, name) && + (flags ? symbol->flags & flags + : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE)))) + return symbol; + } + new_name = strdup(name); + } else { + new_name = NULL; + hash = 0; + } + + symbol = malloc(sizeof(*symbol)); + memset(symbol, 0, sizeof(*symbol)); + symbol->name = new_name; + symbol->type = S_UNKNOWN; + symbol->flags |= flags; + + symbol->next = symbol_hash[hash]; + symbol_hash[hash] = symbol; + + return symbol; +} + +struct symbol *sym_find(const char *name) +{ + struct symbol *symbol = NULL; + int hash = 0; + + if (!name) + return NULL; + + if (name[0] && !name[1]) { + switch (name[0]) { + case 'y': return &symbol_yes; + case 'm': return &symbol_mod; + case 'n': return &symbol_no; + } + } + hash = strhash(name) % SYMBOL_HASHSIZE; + + for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { + if (symbol->name && + !strcmp(symbol->name, name) && + !(symbol->flags & SYMBOL_CONST)) + break; + } + + return symbol; +} + +/* + * Expand symbol's names embedded in the string given in argument. Symbols' + * name to be expanded shall be prefixed by a '$'. Unknown symbol expands to + * the empty string. + */ +const char *sym_expand_string_value(const char *in) +{ + const char *src; + char *res; + size_t reslen; + + reslen = strlen(in) + 1; + res = malloc(reslen); + res[0] = '\0'; + + while ((src = strchr(in, '$'))) { + char *p, name[SYMBOL_MAXLENGTH]; + const char *symval = ""; + struct symbol *sym; + size_t newlen; + + strncat(res, in, src - in); + src++; + + p = name; + while (isalnum(*src) || *src == '_') + *p++ = *src++; + *p = '\0'; + + sym = sym_find(name); + if (sym != NULL) { + sym_calc_value(sym); + symval = sym_get_string_value(sym); + } + + newlen = strlen(res) + strlen(symval) + strlen(src) + 1; + if (newlen > reslen) { + reslen = newlen; + res = realloc(res, reslen); + } + + strcat(res, symval); + in = src; + } + strcat(res, in); + + return res; +} + +struct symbol **sym_re_search(const char *pattern) +{ + struct symbol *sym, **sym_arr = NULL; + int i, cnt, size; + regex_t re; + + cnt = size = 0; + /* Skip if empty */ + if (strlen(pattern) == 0) + return NULL; + if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE)) + return NULL; + + for_all_symbols(i, sym) { + if (sym->flags & SYMBOL_CONST || !sym->name) + continue; + if (regexec(&re, sym->name, 0, NULL, 0)) + continue; + if (cnt + 1 >= size) { + void *tmp = sym_arr; + size += 16; + sym_arr = realloc(sym_arr, size * sizeof(struct symbol *)); + if (!sym_arr) { + free(tmp); + return NULL; + } + } + sym_calc_value(sym); + sym_arr[cnt++] = sym; + } + if (sym_arr) + sym_arr[cnt] = NULL; + regfree(&re); + + return sym_arr; +} + +/* + * When we check for recursive dependencies we use a stack to save + * current state so we can print out relevant info to user. + * The entries are located on the call stack so no need to free memory. + * Note inser() remove() must always match to properly clear the stack. + */ +static struct dep_stack { + struct dep_stack *prev, *next; + struct symbol *sym; + struct property *prop; + struct expr *expr; +} *check_top; + +static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym) +{ + memset(stack, 0, sizeof(*stack)); + if (check_top) + check_top->next = stack; + stack->prev = check_top; + stack->sym = sym; + check_top = stack; +} + +static void dep_stack_remove(void) +{ + check_top = check_top->prev; + if (check_top) + check_top->next = NULL; +} + +/* + * Called when we have detected a recursive dependency. + * check_top point to the top of the stact so we use + * the ->prev pointer to locate the bottom of the stack. + */ +static void sym_check_print_recursive(struct symbol *last_sym) +{ + struct dep_stack *stack; + struct symbol *sym, *next_sym; + struct menu *menu = NULL; + struct property *prop; + struct dep_stack cv_stack; + + if (sym_is_choice_value(last_sym)) { + dep_stack_insert(&cv_stack, last_sym); + last_sym = prop_get_symbol(sym_get_choice_prop(last_sym)); + } + + for (stack = check_top; stack != NULL; stack = stack->prev) + if (stack->sym == last_sym) + break; + if (!stack) { + fprintf(stderr, "unexpected recursive dependency error\n"); + return; + } + + for (; stack; stack = stack->next) { + sym = stack->sym; + next_sym = stack->next ? stack->next->sym : last_sym; + prop = stack->prop; + if (prop == NULL) + prop = stack->sym->prop; + + /* for choice values find the menu entry (used below) */ + if (sym_is_choice(sym) || sym_is_choice_value(sym)) { + for (prop = sym->prop; prop; prop = prop->next) { + menu = prop->menu; + if (prop->menu) + break; + } + } + if (stack->sym == last_sym) + fprintf(stderr, "%s:%d:error: recursive dependency detected!\n", + prop->file->name, prop->lineno); + if (stack->expr) { + fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n", + prop->file->name, prop->lineno, + sym->name ? sym->name : "", + prop_get_type_name(prop->type), + next_sym->name ? next_sym->name : ""); + } else if (stack->prop) { + fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n", + prop->file->name, prop->lineno, + sym->name ? sym->name : "", + next_sym->name ? next_sym->name : ""); + } else if (sym_is_choice(sym)) { + fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n", + menu->file->name, menu->lineno, + sym->name ? sym->name : "", + next_sym->name ? next_sym->name : ""); + } else if (sym_is_choice_value(sym)) { + fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n", + menu->file->name, menu->lineno, + sym->name ? sym->name : "", + next_sym->name ? next_sym->name : ""); + } else { + fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n", + prop->file->name, prop->lineno, + sym->name ? sym->name : "", + next_sym->name ? next_sym->name : ""); + } + } + + if (check_top == &cv_stack) + dep_stack_remove(); +} + +static struct symbol *sym_check_expr_deps(struct expr *e) +{ + struct symbol *sym; + + if (!e) + return NULL; + switch (e->type) { + case E_OR: + case E_AND: + sym = sym_check_expr_deps(e->left.expr); + if (sym) + return sym; + return sym_check_expr_deps(e->right.expr); + case E_NOT: + return sym_check_expr_deps(e->left.expr); + case E_EQUAL: + case E_UNEQUAL: + sym = sym_check_deps(e->left.sym); + if (sym) + return sym; + return sym_check_deps(e->right.sym); + case E_SYMBOL: + return sym_check_deps(e->left.sym); + default: + break; + } + printf("Oops! How to check %d?\n", e->type); + return NULL; +} + +/* return NULL when dependencies are OK */ +static struct symbol *sym_check_sym_deps(struct symbol *sym) +{ + struct symbol *sym2; + struct property *prop; + struct dep_stack stack; + + dep_stack_insert(&stack, sym); + + sym2 = sym_check_expr_deps(sym->rev_dep.expr); + if (sym2) + goto out; + + for (prop = sym->prop; prop; prop = prop->next) { + if (prop->type == P_CHOICE || prop->type == P_SELECT) + continue; + stack.prop = prop; + sym2 = sym_check_expr_deps(prop->visible.expr); + if (sym2) + break; + if (prop->type != P_DEFAULT || sym_is_choice(sym)) + continue; + stack.expr = prop->expr; + sym2 = sym_check_expr_deps(prop->expr); + if (sym2) + break; + stack.expr = NULL; + } + +out: + dep_stack_remove(); + + return sym2; +} + +static struct symbol *sym_check_choice_deps(struct symbol *choice) +{ + struct symbol *sym, *sym2; + struct property *prop; + struct expr *e; + struct dep_stack stack; + + dep_stack_insert(&stack, choice); + + prop = sym_get_choice_prop(choice); + expr_list_for_each_sym(prop->expr, e, sym) + sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); + + choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); + sym2 = sym_check_sym_deps(choice); + choice->flags &= ~SYMBOL_CHECK; + if (sym2) + goto out; + + expr_list_for_each_sym(prop->expr, e, sym) { + sym2 = sym_check_sym_deps(sym); + if (sym2) + break; + } +out: + expr_list_for_each_sym(prop->expr, e, sym) + sym->flags &= ~SYMBOL_CHECK; + + if (sym2 && sym_is_choice_value(sym2) && + prop_get_symbol(sym_get_choice_prop(sym2)) == choice) + sym2 = choice; + + dep_stack_remove(); + + return sym2; +} + +struct symbol *sym_check_deps(struct symbol *sym) +{ + struct symbol *sym2; + struct property *prop; + + if (sym->flags & SYMBOL_CHECK) { + sym_check_print_recursive(sym); + return sym; + } + if (sym->flags & SYMBOL_CHECKED) + return NULL; + + if (sym_is_choice_value(sym)) { + struct dep_stack stack; + + /* for choice groups start the check with main choice symbol */ + dep_stack_insert(&stack, sym); + prop = sym_get_choice_prop(sym); + sym2 = sym_check_deps(prop_get_symbol(prop)); + dep_stack_remove(); + } else if (sym_is_choice(sym)) { + sym2 = sym_check_choice_deps(sym); + } else { + sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); + sym2 = sym_check_sym_deps(sym); + sym->flags &= ~SYMBOL_CHECK; + } + + if (sym2 && sym2 == sym) + sym2 = NULL; + + return sym2; +} + +struct property *prop_alloc(enum prop_type type, struct symbol *sym) +{ + struct property *prop; + struct property **propp; + + prop = malloc(sizeof(*prop)); + memset(prop, 0, sizeof(*prop)); + prop->type = type; + prop->sym = sym; + prop->file = current_file; + prop->lineno = zconf_lineno(); + + /* append property to the prop list of symbol */ + if (sym) { + for (propp = &sym->prop; *propp; propp = &(*propp)->next) + ; + *propp = prop; + } + + return prop; +} + +struct symbol *prop_get_symbol(struct property *prop) +{ + if (prop->expr && (prop->expr->type == E_SYMBOL || + prop->expr->type == E_LIST)) + return prop->expr->left.sym; + return NULL; +} + +const char *prop_get_type_name(enum prop_type type) +{ + switch (type) { + case P_PROMPT: + return "prompt"; + case P_ENV: + return "env"; + case P_COMMENT: + return "comment"; + case P_MENU: + return "menu"; + case P_DEFAULT: + return "default"; + case P_CHOICE: + return "choice"; + case P_SELECT: + return "select"; + case P_RANGE: + return "range"; + case P_SYMBOL: + return "symbol"; + case P_UNKNOWN: + break; + } + return "unknown"; +} + +static void prop_add_env(const char *env) +{ + struct symbol *sym, *sym2; + struct property *prop; + char *p; + + sym = current_entry->sym; + sym->flags |= SYMBOL_AUTO; + for_all_properties(sym, prop, P_ENV) { + sym2 = prop_get_symbol(prop); + if (strcmp(sym2->name, env)) + menu_warn(current_entry, "redefining environment symbol from %s", + sym2->name); + return; + } + + prop = prop_alloc(P_ENV, sym); + prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST)); + + sym_env_list = expr_alloc_one(E_LIST, sym_env_list); + sym_env_list->right.sym = sym; + + p = getenv(env); + if (p) + sym_add_default(sym, p); + else + menu_warn(current_entry, "environment variable %s undefined", env); +} diff --git a/bios/seabios/tools/kconfig/util.c b/bios/seabios/tools/kconfig/util.c new file mode 100644 index 0000000..6330cc8 --- /dev/null +++ b/bios/seabios/tools/kconfig/util.c @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2002-2005 Roman Zippel + * Copyright (C) 2002-2005 Sam Ravnborg + * + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include "lkc.h" + +/* file already present in list? If not add it */ +struct file *file_lookup(const char *name) +{ + struct file *file; + const char *file_name = sym_expand_string_value(name); + + for (file = file_list; file; file = file->next) { + if (!strcmp(name, file->name)) { + free((void *)file_name); + return file; + } + } + + file = malloc(sizeof(*file)); + memset(file, 0, sizeof(*file)); + file->name = file_name; + file->next = file_list; + file_list = file; + return file; +} + +/* write a dependency file as used by kbuild to track dependencies */ +int file_write_dep(const char *name) +{ + struct symbol *sym, *env_sym; + struct expr *e; + struct file *file; + FILE *out; + + if (!name) + name = ".kconfig.d"; + out = fopen("..config.tmp", "w"); + if (!out) + return 1; + fprintf(out, "deps_config := \\\n"); + for (file = file_list; file; file = file->next) { + if (file->next) + fprintf(out, "\t%s \\\n", file->name); + else + fprintf(out, "\t%s\n", file->name); + } + fprintf(out, "\n%s: \\\n" + "\t$(deps_config)\n\n", conf_get_autoconfig_name()); + + expr_list_for_each_sym(sym_env_list, e, sym) { + struct property *prop; + const char *value; + + prop = sym_get_env_prop(sym); + env_sym = prop_get_symbol(prop); + if (!env_sym) + continue; + value = getenv(env_sym->name); + if (!value) + value = ""; + fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value); + fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name()); + fprintf(out, "endif\n"); + } + + fprintf(out, "\n$(deps_config): ;\n"); + fclose(out); + rename("..config.tmp", name); + return 0; +} + + +/* Allocate initial growable string */ +struct gstr str_new(void) +{ + struct gstr gs; + gs.s = malloc(sizeof(char) * 64); + gs.len = 64; + gs.max_width = 0; + strcpy(gs.s, "\0"); + return gs; +} + +/* Allocate and assign growable string */ +struct gstr str_assign(const char *s) +{ + struct gstr gs; + gs.s = strdup(s); + gs.len = strlen(s) + 1; + gs.max_width = 0; + return gs; +} + +/* Free storage for growable string */ +void str_free(struct gstr *gs) +{ + if (gs->s) + free(gs->s); + gs->s = NULL; + gs->len = 0; +} + +/* Append to growable string */ +void str_append(struct gstr *gs, const char *s) +{ + size_t l; + if (s) { + l = strlen(gs->s) + strlen(s) + 1; + if (l > gs->len) { + gs->s = realloc(gs->s, l); + gs->len = l; + } + strcat(gs->s, s); + } +} + +/* Append printf formatted string to growable string */ +void str_printf(struct gstr *gs, const char *fmt, ...) +{ + va_list ap; + char s[10000]; /* big enough... */ + va_start(ap, fmt); + vsnprintf(s, sizeof(s), fmt, ap); + str_append(gs, s); + va_end(ap); +} + +/* Retrieve value of growable string */ +const char *str_get(struct gstr *gs) +{ + return gs->s; +} + diff --git a/bios/seabios/tools/kconfig/zconf.gperf b/bios/seabios/tools/kconfig/zconf.gperf new file mode 100644 index 0000000..c9e690e --- /dev/null +++ b/bios/seabios/tools/kconfig/zconf.gperf @@ -0,0 +1,47 @@ +%language=ANSI-C +%define hash-function-name kconf_id_hash +%define lookup-function-name kconf_id_lookup +%define string-pool-name kconf_id_strings +%compare-strncmp +%enum +%pic +%struct-type + +struct kconf_id; + +static struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len); + +%% +mainmenu, T_MAINMENU, TF_COMMAND +menu, T_MENU, TF_COMMAND +endmenu, T_ENDMENU, TF_COMMAND +source, T_SOURCE, TF_COMMAND +choice, T_CHOICE, TF_COMMAND +endchoice, T_ENDCHOICE, TF_COMMAND +comment, T_COMMENT, TF_COMMAND +config, T_CONFIG, TF_COMMAND +menuconfig, T_MENUCONFIG, TF_COMMAND +help, T_HELP, TF_COMMAND +if, T_IF, TF_COMMAND|TF_PARAM +endif, T_ENDIF, TF_COMMAND +depends, T_DEPENDS, TF_COMMAND +optional, T_OPTIONAL, TF_COMMAND +default, T_DEFAULT, TF_COMMAND, S_UNKNOWN +prompt, T_PROMPT, TF_COMMAND +tristate, T_TYPE, TF_COMMAND, S_TRISTATE +def_tristate, T_DEFAULT, TF_COMMAND, S_TRISTATE +bool, T_TYPE, TF_COMMAND, S_BOOLEAN +boolean, T_TYPE, TF_COMMAND, S_BOOLEAN +def_bool, T_DEFAULT, TF_COMMAND, S_BOOLEAN +int, T_TYPE, TF_COMMAND, S_INT +hex, T_TYPE, TF_COMMAND, S_HEX +string, T_TYPE, TF_COMMAND, S_STRING +select, T_SELECT, TF_COMMAND +range, T_RANGE, TF_COMMAND +visible, T_VISIBLE, TF_COMMAND +option, T_OPTION, TF_COMMAND +on, T_ON, TF_PARAM +modules, T_OPT_MODULES, TF_OPTION +defconfig_list, T_OPT_DEFCONFIG_LIST,TF_OPTION +env, T_OPT_ENV, TF_OPTION +%% diff --git a/bios/seabios/tools/kconfig/zconf.hash.c_shipped b/bios/seabios/tools/kconfig/zconf.hash.c_shipped new file mode 100644 index 0000000..4055d5d --- /dev/null +++ b/bios/seabios/tools/kconfig/zconf.hash.c_shipped @@ -0,0 +1,245 @@ +/* ANSI-C code produced by gperf version 3.0.3 */ +/* Command-line: gperf */ +/* Computed positions: -k'1,3' */ + +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ + && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ + && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ + && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ + && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ + && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ + && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ + && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ + && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ + && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ + && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ + && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ + && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ + && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ + && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ + && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ + && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ + && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ + && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ + && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ + && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ + && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ + && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) +/* The character set is not based on ISO-646. */ +#error "gperf generated tables don't work with this execution character set. Please report a bug to ." +#endif + +struct kconf_id; + +static struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len); +/* maximum key range = 50, duplicates = 0 */ + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static unsigned int +kconf_id_hash (register const char *str, register unsigned int len) +{ + static unsigned char asso_values[] = + { + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 40, 5, + 0, 0, 5, 52, 0, 20, 52, 52, 10, 20, + 5, 0, 35, 52, 0, 30, 0, 15, 0, 52, + 15, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52 + }; + register int hval = len; + + switch (hval) + { + default: + hval += asso_values[(unsigned char)str[2]]; + /*FALLTHROUGH*/ + case 2: + case 1: + hval += asso_values[(unsigned char)str[0]]; + break; + } + return hval; +} + +struct kconf_id_strings_t + { + char kconf_id_strings_str2[sizeof("on")]; + char kconf_id_strings_str3[sizeof("env")]; + char kconf_id_strings_str5[sizeof("endif")]; + char kconf_id_strings_str6[sizeof("option")]; + char kconf_id_strings_str7[sizeof("endmenu")]; + char kconf_id_strings_str8[sizeof("optional")]; + char kconf_id_strings_str9[sizeof("endchoice")]; + char kconf_id_strings_str10[sizeof("range")]; + char kconf_id_strings_str11[sizeof("choice")]; + char kconf_id_strings_str12[sizeof("default")]; + char kconf_id_strings_str13[sizeof("def_bool")]; + char kconf_id_strings_str14[sizeof("help")]; + char kconf_id_strings_str16[sizeof("config")]; + char kconf_id_strings_str17[sizeof("def_tristate")]; + char kconf_id_strings_str18[sizeof("hex")]; + char kconf_id_strings_str19[sizeof("defconfig_list")]; + char kconf_id_strings_str22[sizeof("if")]; + char kconf_id_strings_str23[sizeof("int")]; + char kconf_id_strings_str27[sizeof("modules")]; + char kconf_id_strings_str28[sizeof("tristate")]; + char kconf_id_strings_str29[sizeof("menu")]; + char kconf_id_strings_str32[sizeof("comment")]; + char kconf_id_strings_str35[sizeof("menuconfig")]; + char kconf_id_strings_str36[sizeof("string")]; + char kconf_id_strings_str37[sizeof("visible")]; + char kconf_id_strings_str41[sizeof("prompt")]; + char kconf_id_strings_str42[sizeof("depends")]; + char kconf_id_strings_str44[sizeof("bool")]; + char kconf_id_strings_str46[sizeof("select")]; + char kconf_id_strings_str47[sizeof("boolean")]; + char kconf_id_strings_str48[sizeof("mainmenu")]; + char kconf_id_strings_str51[sizeof("source")]; + }; +static struct kconf_id_strings_t kconf_id_strings_contents = + { + "on", + "env", + "endif", + "option", + "endmenu", + "optional", + "endchoice", + "range", + "choice", + "default", + "def_bool", + "help", + "config", + "def_tristate", + "hex", + "defconfig_list", + "if", + "int", + "modules", + "tristate", + "menu", + "comment", + "menuconfig", + "string", + "visible", + "prompt", + "depends", + "bool", + "select", + "boolean", + "mainmenu", + "source" + }; +#define kconf_id_strings ((const char *) &kconf_id_strings_contents) +#ifdef __GNUC__ +__inline +#ifdef __GNUC_STDC_INLINE__ +__attribute__ ((__gnu_inline__)) +#endif +#endif +struct kconf_id * +kconf_id_lookup (register const char *str, register unsigned int len) +{ + enum + { + TOTAL_KEYWORDS = 32, + MIN_WORD_LENGTH = 2, + MAX_WORD_LENGTH = 14, + MIN_HASH_VALUE = 2, + MAX_HASH_VALUE = 51 + }; + + static struct kconf_id wordlist[] = + { + {-1}, {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2, T_ON, TF_PARAM}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3, T_OPT_ENV, TF_OPTION}, + {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5, T_ENDIF, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6, T_OPTION, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7, T_ENDMENU, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8, T_OPTIONAL, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9, T_ENDCHOICE, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10, T_RANGE, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11, T_CHOICE, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_UNKNOWN}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_DEFAULT, TF_COMMAND, S_BOOLEAN}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_HELP, TF_COMMAND}, + {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16, T_CONFIG, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_DEFAULT, TF_COMMAND, S_TRISTATE}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_TYPE, TF_COMMAND, S_HEX}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str19, T_OPT_DEFCONFIG_LIST,TF_OPTION}, + {-1}, {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_IF, TF_COMMAND|TF_PARAM}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23, T_TYPE, TF_COMMAND, S_INT}, + {-1}, {-1}, {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_OPT_MODULES, TF_OPTION}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28, T_TYPE, TF_COMMAND, S_TRISTATE}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29, T_MENU, TF_COMMAND}, + {-1}, {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_COMMENT, TF_COMMAND}, + {-1}, {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35, T_MENUCONFIG, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36, T_TYPE, TF_COMMAND, S_STRING}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37, T_VISIBLE, TF_COMMAND}, + {-1}, {-1}, {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_PROMPT, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42, T_DEPENDS, TF_COMMAND}, + {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str44, T_TYPE, TF_COMMAND, S_BOOLEAN}, + {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46, T_SELECT, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str47, T_TYPE, TF_COMMAND, S_BOOLEAN}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str48, T_MAINMENU, TF_COMMAND}, + {-1}, {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str51, T_SOURCE, TF_COMMAND} + }; + + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) + { + register int key = kconf_id_hash (str, len); + + if (key <= MAX_HASH_VALUE && key >= 0) + { + register int o = wordlist[key].name; + if (o >= 0) + { + register const char *s = o + kconf_id_strings; + + if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0') + return &wordlist[key]; + } + } + } + return 0; +} + diff --git a/bios/seabios/tools/kconfig/zconf.l b/bios/seabios/tools/kconfig/zconf.l new file mode 100644 index 0000000..3dbaec1 --- /dev/null +++ b/bios/seabios/tools/kconfig/zconf.l @@ -0,0 +1,360 @@ +%option backup nostdinit noyywrap never-interactive full ecs +%option 8bit backup nodefault perf-report perf-report +%option noinput +%x COMMAND HELP STRING PARAM +%{ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +#define START_STRSIZE 16 + +static struct { + struct file *file; + int lineno; +} current_pos; + +static char *text; +static int text_size, text_asize; + +struct buffer { + struct buffer *parent; + YY_BUFFER_STATE state; +}; + +struct buffer *current_buf; + +static int last_ts, first_ts; + +static void zconf_endhelp(void); +static void zconf_endfile(void); + +static void new_string(void) +{ + text = malloc(START_STRSIZE); + text_asize = START_STRSIZE; + text_size = 0; + *text = 0; +} + +static void append_string(const char *str, int size) +{ + int new_size = text_size + size + 1; + if (new_size > text_asize) { + new_size += START_STRSIZE - 1; + new_size &= -START_STRSIZE; + text = realloc(text, new_size); + text_asize = new_size; + } + memcpy(text + text_size, str, size); + text_size += size; + text[text_size] = 0; +} + +static void alloc_string(const char *str, int size) +{ + text = malloc(size + 1); + memcpy(text, str, size); + text[size] = 0; +} +%} + +ws [ \n\t] +n [A-Za-z0-9_] + +%% + int str = 0; + int ts, i; + +[ \t]*#.*\n | +[ \t]*\n { + current_file->lineno++; + return T_EOL; +} +[ \t]*#.* + + +[ \t]+ { + BEGIN(COMMAND); +} + +. { + unput(yytext[0]); + BEGIN(COMMAND); +} + + +{ + {n}+ { + struct kconf_id *id = kconf_id_lookup(yytext, yyleng); + BEGIN(PARAM); + current_pos.file = current_file; + current_pos.lineno = current_file->lineno; + if (id && id->flags & TF_COMMAND) { + zconflval.id = id; + return id->token; + } + alloc_string(yytext, yyleng); + zconflval.string = text; + return T_WORD; + } + . + \n { + BEGIN(INITIAL); + current_file->lineno++; + return T_EOL; + } +} + +{ + "&&" return T_AND; + "||" return T_OR; + "(" return T_OPEN_PAREN; + ")" return T_CLOSE_PAREN; + "!" return T_NOT; + "=" return T_EQUAL; + "!=" return T_UNEQUAL; + \"|\' { + str = yytext[0]; + new_string(); + BEGIN(STRING); + } + \n BEGIN(INITIAL); current_file->lineno++; return T_EOL; + --- /* ignore */ + ({n}|[-/.])+ { + struct kconf_id *id = kconf_id_lookup(yytext, yyleng); + if (id && id->flags & TF_PARAM) { + zconflval.id = id; + return id->token; + } + alloc_string(yytext, yyleng); + zconflval.string = text; + return T_WORD; + } + #.* /* comment */ + \\\n current_file->lineno++; + . + <> { + BEGIN(INITIAL); + } +} + +{ + [^'"\\\n]+/\n { + append_string(yytext, yyleng); + zconflval.string = text; + return T_WORD_QUOTE; + } + [^'"\\\n]+ { + append_string(yytext, yyleng); + } + \\.?/\n { + append_string(yytext + 1, yyleng - 1); + zconflval.string = text; + return T_WORD_QUOTE; + } + \\.? { + append_string(yytext + 1, yyleng - 1); + } + \'|\" { + if (str == yytext[0]) { + BEGIN(PARAM); + zconflval.string = text; + return T_WORD_QUOTE; + } else + append_string(yytext, 1); + } + \n { + printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno()); + current_file->lineno++; + BEGIN(INITIAL); + return T_EOL; + } + <> { + BEGIN(INITIAL); + } +} + +{ + [ \t]+ { + ts = 0; + for (i = 0; i < yyleng; i++) { + if (yytext[i] == '\t') + ts = (ts & ~7) + 8; + else + ts++; + } + last_ts = ts; + if (first_ts) { + if (ts < first_ts) { + zconf_endhelp(); + return T_HELPTEXT; + } + ts -= first_ts; + while (ts > 8) { + append_string(" ", 8); + ts -= 8; + } + append_string(" ", ts); + } + } + [ \t]*\n/[^ \t\n] { + current_file->lineno++; + zconf_endhelp(); + return T_HELPTEXT; + } + [ \t]*\n { + current_file->lineno++; + append_string("\n", 1); + } + [^ \t\n].* { + while (yyleng) { + if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t')) + break; + yyleng--; + } + append_string(yytext, yyleng); + if (!first_ts) + first_ts = last_ts; + } + <> { + zconf_endhelp(); + return T_HELPTEXT; + } +} + +<> { + if (current_file) { + zconf_endfile(); + return T_EOL; + } + fclose(yyin); + yyterminate(); +} + +%% +void zconf_starthelp(void) +{ + new_string(); + last_ts = first_ts = 0; + BEGIN(HELP); +} + +static void zconf_endhelp(void) +{ + zconflval.string = text; + BEGIN(INITIAL); +} + + +/* + * Try to open specified file with following names: + * ./name + * $(srctree)/name + * The latter is used when srctree is separate from objtree + * when compiling the kernel. + * Return NULL if file is not found. + */ +FILE *zconf_fopen(const char *name) +{ + char *env, fullname[PATH_MAX+1]; + FILE *f; + + f = fopen(name, "r"); + if (!f && name != NULL && name[0] != '/') { + env = getenv(SRCTREE); + if (env) { + sprintf(fullname, "%s/%s", env, name); + f = fopen(fullname, "r"); + } + } + return f; +} + +void zconf_initscan(const char *name) +{ + yyin = zconf_fopen(name); + if (!yyin) { + printf("can't find file %s\n", name); + exit(1); + } + + current_buf = malloc(sizeof(*current_buf)); + memset(current_buf, 0, sizeof(*current_buf)); + + current_file = file_lookup(name); + current_file->lineno = 1; + current_file->flags = FILE_BUSY; +} + +void zconf_nextfile(const char *name) +{ + struct file *file = file_lookup(name); + struct buffer *buf = malloc(sizeof(*buf)); + memset(buf, 0, sizeof(*buf)); + + current_buf->state = YY_CURRENT_BUFFER; + yyin = zconf_fopen(file->name); + if (!yyin) { + printf("%s:%d: can't open file \"%s\"\n", + zconf_curname(), zconf_lineno(), file->name); + exit(1); + } + yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); + buf->parent = current_buf; + current_buf = buf; + + if (file->flags & FILE_BUSY) { + printf("%s:%d: do not source '%s' from itself\n", + zconf_curname(), zconf_lineno(), name); + exit(1); + } + if (file->flags & FILE_SCANNED) { + printf("%s:%d: file '%s' is already sourced from '%s'\n", + zconf_curname(), zconf_lineno(), name, + file->parent->name); + exit(1); + } + file->flags |= FILE_BUSY; + file->lineno = 1; + file->parent = current_file; + current_file = file; +} + +static void zconf_endfile(void) +{ + struct buffer *parent; + + current_file->flags |= FILE_SCANNED; + current_file->flags &= ~FILE_BUSY; + current_file = current_file->parent; + + parent = current_buf->parent; + if (parent) { + fclose(yyin); + yy_delete_buffer(YY_CURRENT_BUFFER); + yy_switch_to_buffer(parent->state); + } + free(current_buf); + current_buf = parent; +} + +int zconf_lineno(void) +{ + return current_pos.lineno; +} + +const char *zconf_curname(void) +{ + return current_pos.file ? current_pos.file->name : ""; +} diff --git a/bios/seabios/tools/kconfig/zconf.tab.c_shipped b/bios/seabios/tools/kconfig/zconf.tab.c_shipped new file mode 100644 index 0000000..4c5495e --- /dev/null +++ b/bios/seabios/tools/kconfig/zconf.tab.c_shipped @@ -0,0 +1,2505 @@ + +/* A Bison parser, made by GNU Bison 2.4.1. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + 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 . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.4.1" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + +/* Substitute the variable and function names. */ +#define yyparse zconfparse +#define yylex zconflex +#define yyerror zconferror +#define yylval zconflval +#define yychar zconfchar +#define yydebug zconfdebug +#define yynerrs zconfnerrs + + +/* Copy the first part of user declarations. */ + + +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) + +#define PRINTD 0x0001 +#define DEBUG_PARSE 0x0002 + +int cdebug = PRINTD; + +extern int zconflex(void); +static void zconfprint(const char *err, ...); +static void zconf_error(const char *err, ...); +static void zconferror(const char *err); +static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken); + +struct symbol *symbol_hash[SYMBOL_HASHSIZE]; + +static struct menu *current_menu, *current_entry; + +#define YYDEBUG 0 +#if YYDEBUG +#define YYERROR_VERBOSE +#endif + + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + T_MAINMENU = 258, + T_MENU = 259, + T_ENDMENU = 260, + T_SOURCE = 261, + T_CHOICE = 262, + T_ENDCHOICE = 263, + T_COMMENT = 264, + T_CONFIG = 265, + T_MENUCONFIG = 266, + T_HELP = 267, + T_HELPTEXT = 268, + T_IF = 269, + T_ENDIF = 270, + T_DEPENDS = 271, + T_OPTIONAL = 272, + T_PROMPT = 273, + T_TYPE = 274, + T_DEFAULT = 275, + T_SELECT = 276, + T_RANGE = 277, + T_VISIBLE = 278, + T_OPTION = 279, + T_ON = 280, + T_WORD = 281, + T_WORD_QUOTE = 282, + T_UNEQUAL = 283, + T_CLOSE_PAREN = 284, + T_OPEN_PAREN = 285, + T_EOL = 286, + T_OR = 287, + T_AND = 288, + T_EQUAL = 289, + T_NOT = 290 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + + + char *string; + struct file *file; + struct symbol *symbol; + struct expr *expr; + struct menu *menu; + struct kconf_id *id; + + + +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + +/* Copy the second part of user declarations. */ + + +/* Include zconf.hash.c here so it can see the token constants. */ +#include "zconf.hash.c" + + + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 11 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 290 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 36 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 50 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 118 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 191 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 290 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint16 yyprhs[] = +{ + 0, 0, 3, 6, 8, 11, 13, 14, 17, 20, + 23, 26, 31, 36, 40, 42, 44, 46, 48, 50, + 52, 54, 56, 58, 60, 62, 64, 66, 68, 72, + 75, 79, 82, 86, 89, 90, 93, 96, 99, 102, + 105, 108, 112, 117, 122, 127, 133, 137, 138, 142, + 143, 146, 150, 153, 155, 159, 160, 163, 166, 169, + 172, 175, 180, 184, 187, 192, 193, 196, 200, 202, + 206, 207, 210, 213, 216, 220, 224, 228, 230, 234, + 235, 238, 241, 244, 248, 252, 255, 258, 261, 262, + 265, 268, 271, 276, 277, 280, 283, 286, 287, 290, + 292, 294, 297, 300, 303, 305, 308, 309, 312, 314, + 318, 322, 326, 329, 333, 337, 339, 341, 342 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 37, 0, -1, 81, 38, -1, 38, -1, 63, 39, + -1, 39, -1, -1, 39, 41, -1, 39, 55, -1, + 39, 67, -1, 39, 80, -1, 39, 26, 1, 31, + -1, 39, 40, 1, 31, -1, 39, 1, 31, -1, + 16, -1, 18, -1, 19, -1, 21, -1, 17, -1, + 22, -1, 20, -1, 23, -1, 31, -1, 61, -1, + 71, -1, 44, -1, 46, -1, 69, -1, 26, 1, + 31, -1, 1, 31, -1, 10, 26, 31, -1, 43, + 47, -1, 11, 26, 31, -1, 45, 47, -1, -1, + 47, 48, -1, 47, 49, -1, 47, 75, -1, 47, + 73, -1, 47, 42, -1, 47, 31, -1, 19, 78, + 31, -1, 18, 79, 82, 31, -1, 20, 83, 82, + 31, -1, 21, 26, 82, 31, -1, 22, 84, 84, + 82, 31, -1, 24, 50, 31, -1, -1, 50, 26, + 51, -1, -1, 34, 79, -1, 7, 85, 31, -1, + 52, 56, -1, 80, -1, 53, 58, 54, -1, -1, + 56, 57, -1, 56, 75, -1, 56, 73, -1, 56, + 31, -1, 56, 42, -1, 18, 79, 82, 31, -1, + 19, 78, 31, -1, 17, 31, -1, 20, 26, 82, + 31, -1, -1, 58, 41, -1, 14, 83, 81, -1, + 80, -1, 59, 62, 60, -1, -1, 62, 41, -1, + 62, 67, -1, 62, 55, -1, 3, 79, 81, -1, + 4, 79, 31, -1, 64, 76, 74, -1, 80, -1, + 65, 68, 66, -1, -1, 68, 41, -1, 68, 67, + -1, 68, 55, -1, 6, 79, 31, -1, 9, 79, + 31, -1, 70, 74, -1, 12, 31, -1, 72, 13, + -1, -1, 74, 75, -1, 74, 31, -1, 74, 42, + -1, 16, 25, 83, 31, -1, -1, 76, 77, -1, + 76, 31, -1, 23, 82, -1, -1, 79, 82, -1, + 26, -1, 27, -1, 5, 31, -1, 8, 31, -1, + 15, 31, -1, 31, -1, 81, 31, -1, -1, 14, + 83, -1, 84, -1, 84, 34, 84, -1, 84, 28, + 84, -1, 30, 83, 29, -1, 35, 83, -1, 83, + 32, 83, -1, 83, 33, 83, -1, 26, -1, 27, + -1, -1, 26, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 108, 108, 108, 110, 110, 112, 114, 115, 116, + 117, 118, 119, 123, 127, 127, 127, 127, 127, 127, + 127, 127, 131, 132, 133, 134, 135, 136, 140, 141, + 147, 155, 161, 169, 179, 181, 182, 183, 184, 185, + 186, 189, 197, 203, 213, 219, 225, 228, 230, 241, + 242, 247, 256, 261, 269, 272, 274, 275, 276, 277, + 278, 281, 287, 298, 304, 314, 316, 321, 329, 337, + 340, 342, 343, 344, 349, 356, 363, 368, 376, 379, + 381, 382, 383, 386, 394, 401, 408, 414, 421, 423, + 424, 425, 428, 436, 438, 439, 442, 449, 451, 456, + 457, 460, 461, 462, 466, 467, 470, 471, 474, 475, + 476, 477, 478, 479, 480, 483, 484, 487, 488 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU", + "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG", + "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS", + "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT", "T_SELECT", "T_RANGE", + "T_VISIBLE", "T_OPTION", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL", + "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL", + "T_NOT", "$accept", "input", "start", "stmt_list", "option_name", + "common_stmt", "option_error", "config_entry_start", "config_stmt", + "menuconfig_entry_start", "menuconfig_stmt", "config_option_list", + "config_option", "symbol_option", "symbol_option_list", + "symbol_option_arg", "choice", "choice_entry", "choice_end", + "choice_stmt", "choice_option_list", "choice_option", "choice_block", + "if_entry", "if_end", "if_stmt", "if_block", "mainmenu_stmt", "menu", + "menu_entry", "menu_end", "menu_stmt", "menu_block", "source_stmt", + "comment", "comment_stmt", "help_start", "help", "depends_list", + "depends", "visibility_list", "visible", "prompt_stmt_opt", "prompt", + "end", "nl", "if_expr", "expr", "symbol", "word_opt", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 36, 37, 37, 38, 38, 39, 39, 39, 39, + 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, + 40, 40, 41, 41, 41, 41, 41, 41, 42, 42, + 43, 44, 45, 46, 47, 47, 47, 47, 47, 47, + 47, 48, 48, 48, 48, 48, 49, 50, 50, 51, + 51, 52, 53, 54, 55, 56, 56, 56, 56, 56, + 56, 57, 57, 57, 57, 58, 58, 59, 60, 61, + 62, 62, 62, 62, 63, 64, 65, 66, 67, 68, + 68, 68, 68, 69, 70, 71, 72, 73, 74, 74, + 74, 74, 75, 76, 76, 76, 77, 78, 78, 79, + 79, 80, 80, 80, 81, 81, 82, 82, 83, 83, + 83, 83, 83, 83, 83, 84, 84, 85, 85 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 2, 1, 2, 1, 0, 2, 2, 2, + 2, 4, 4, 3, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, + 3, 2, 3, 2, 0, 2, 2, 2, 2, 2, + 2, 3, 4, 4, 4, 5, 3, 0, 3, 0, + 2, 3, 2, 1, 3, 0, 2, 2, 2, 2, + 2, 4, 3, 2, 4, 0, 2, 3, 1, 3, + 0, 2, 2, 2, 3, 3, 3, 1, 3, 0, + 2, 2, 2, 3, 3, 2, 2, 2, 0, 2, + 2, 2, 4, 0, 2, 2, 2, 0, 2, 1, + 1, 2, 2, 2, 1, 2, 0, 2, 1, 3, + 3, 3, 2, 3, 3, 1, 1, 0, 1 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 6, 0, 104, 0, 3, 0, 6, 6, 99, 100, + 0, 1, 0, 0, 0, 0, 117, 0, 0, 0, + 0, 0, 0, 14, 18, 15, 16, 20, 17, 19, + 21, 0, 22, 0, 7, 34, 25, 34, 26, 55, + 65, 8, 70, 23, 93, 79, 9, 27, 88, 24, + 10, 0, 105, 2, 74, 13, 0, 101, 0, 118, + 0, 102, 0, 0, 0, 115, 116, 0, 0, 0, + 108, 103, 0, 0, 0, 0, 0, 0, 0, 88, + 0, 0, 75, 83, 51, 84, 30, 32, 0, 112, + 0, 0, 67, 0, 0, 11, 12, 0, 0, 0, + 0, 97, 0, 0, 0, 47, 0, 40, 39, 35, + 36, 0, 38, 37, 0, 0, 97, 0, 59, 60, + 56, 58, 57, 66, 54, 53, 71, 73, 69, 72, + 68, 106, 95, 0, 94, 80, 82, 78, 81, 77, + 90, 91, 89, 111, 113, 114, 110, 109, 29, 86, + 0, 106, 0, 106, 106, 106, 0, 0, 0, 87, + 63, 106, 0, 106, 0, 96, 0, 0, 41, 98, + 0, 0, 106, 49, 46, 28, 0, 62, 0, 107, + 92, 42, 43, 44, 0, 0, 48, 61, 64, 45, + 50 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 3, 4, 5, 33, 34, 108, 35, 36, 37, + 38, 74, 109, 110, 157, 186, 39, 40, 124, 41, + 76, 120, 77, 42, 128, 43, 78, 6, 44, 45, + 137, 46, 80, 47, 48, 49, 111, 112, 81, 113, + 79, 134, 152, 153, 50, 7, 165, 69, 70, 60 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -90 +static const yytype_int16 yypact[] = +{ + 4, 42, -90, 96, -90, 111, -90, 15, -90, -90, + 75, -90, 82, 42, 104, 42, 110, 107, 42, 115, + 125, -4, 121, -90, -90, -90, -90, -90, -90, -90, + -90, 162, -90, 163, -90, -90, -90, -90, -90, -90, + -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, + -90, 139, -90, -90, 138, -90, 142, -90, 143, -90, + 152, -90, 164, 167, 168, -90, -90, -4, -4, 77, + -18, -90, 177, 185, 33, 71, 195, 247, 236, -2, + 236, 171, -90, -90, -90, -90, -90, -90, 41, -90, + -4, -4, 138, 97, 97, -90, -90, 186, 187, 194, + 42, 42, -4, 196, 97, -90, 219, -90, -90, -90, + -90, 210, -90, -90, 204, 42, 42, 199, -90, -90, + -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, + -90, 222, -90, 223, -90, -90, -90, -90, -90, -90, + -90, -90, -90, -90, 215, -90, -90, -90, -90, -90, + -4, 222, 228, 222, -5, 222, 97, 35, 229, -90, + -90, 222, 232, 222, -4, -90, 135, 233, -90, -90, + 234, 235, 222, 240, -90, -90, 237, -90, 239, -13, + -90, -90, -90, -90, 244, 42, -90, -90, -90, -90, + -90 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -90, -90, 269, 271, -90, 23, -70, -90, -90, -90, + -90, 243, -90, -90, -90, -90, -90, -90, -90, -48, + -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, + -90, -20, -90, -90, -90, -90, -90, 206, 205, -68, + -90, -90, 169, -1, 27, -7, 118, -66, -89, -90 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -86 +static const yytype_int16 yytable[] = +{ + 10, 88, 89, 54, 146, 147, 119, 1, 122, 164, + 93, 141, 56, 142, 58, 156, 94, 62, 1, 90, + 91, 131, 65, 66, 144, 145, 67, 90, 91, 132, + 127, 68, 136, -31, 97, 2, 154, -31, -31, -31, + -31, -31, -31, -31, -31, 98, 52, -31, -31, 99, + -31, 100, 101, 102, 103, 104, -31, 105, 129, 106, + 138, 173, 92, 141, 107, 142, 174, 172, 8, 9, + 143, -33, 97, 90, 91, -33, -33, -33, -33, -33, + -33, -33, -33, 98, 166, -33, -33, 99, -33, 100, + 101, 102, 103, 104, -33, 105, 11, 106, 179, 151, + 123, 126, 107, 135, 125, 130, 2, 139, 2, 90, + 91, -5, 12, 55, 161, 13, 14, 15, 16, 17, + 18, 19, 20, 65, 66, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 57, 59, 31, 61, -4, + 12, 63, 32, 13, 14, 15, 16, 17, 18, 19, + 20, 64, 71, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 72, 73, 31, 180, 90, 91, 52, + 32, -85, 97, 82, 83, -85, -85, -85, -85, -85, + -85, -85, -85, 84, 190, -85, -85, 99, -85, -85, + -85, -85, -85, -85, -85, 85, 97, 106, 86, 87, + -52, -52, 140, -52, -52, -52, -52, 98, 95, -52, + -52, 99, 114, 115, 116, 117, 96, 148, 149, 150, + 158, 106, 155, 159, 97, 163, 118, -76, -76, -76, + -76, -76, -76, -76, -76, 160, 164, -76, -76, 99, + 13, 14, 15, 16, 17, 18, 19, 20, 91, 106, + 21, 22, 14, 15, 140, 17, 18, 19, 20, 168, + 175, 21, 22, 177, 181, 182, 183, 32, 187, 167, + 188, 169, 170, 171, 185, 189, 53, 51, 32, 176, + 75, 178, 121, 0, 133, 162, 0, 0, 0, 0, + 184 +}; + +static const yytype_int16 yycheck[] = +{ + 1, 67, 68, 10, 93, 94, 76, 3, 76, 14, + 28, 81, 13, 81, 15, 104, 34, 18, 3, 32, + 33, 23, 26, 27, 90, 91, 30, 32, 33, 31, + 78, 35, 80, 0, 1, 31, 102, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 31, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 78, 26, + 80, 26, 69, 133, 31, 133, 31, 156, 26, 27, + 29, 0, 1, 32, 33, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 150, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 0, 26, 164, 100, + 77, 78, 31, 80, 77, 78, 31, 80, 31, 32, + 33, 0, 1, 31, 115, 4, 5, 6, 7, 8, + 9, 10, 11, 26, 27, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 31, 26, 26, 31, 0, + 1, 26, 31, 4, 5, 6, 7, 8, 9, 10, + 11, 26, 31, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 1, 1, 26, 31, 32, 33, 31, + 31, 0, 1, 31, 31, 4, 5, 6, 7, 8, + 9, 10, 11, 31, 185, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 31, 1, 26, 31, 31, + 5, 6, 31, 8, 9, 10, 11, 12, 31, 14, + 15, 16, 17, 18, 19, 20, 31, 31, 31, 25, + 1, 26, 26, 13, 1, 26, 31, 4, 5, 6, + 7, 8, 9, 10, 11, 31, 14, 14, 15, 16, + 4, 5, 6, 7, 8, 9, 10, 11, 33, 26, + 14, 15, 5, 6, 31, 8, 9, 10, 11, 31, + 31, 14, 15, 31, 31, 31, 31, 31, 31, 151, + 31, 153, 154, 155, 34, 31, 7, 6, 31, 161, + 37, 163, 76, -1, 79, 116, -1, -1, -1, -1, + 172 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 3, 31, 37, 38, 39, 63, 81, 26, 27, + 79, 0, 1, 4, 5, 6, 7, 8, 9, 10, + 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 26, 31, 40, 41, 43, 44, 45, 46, 52, + 53, 55, 59, 61, 64, 65, 67, 69, 70, 71, + 80, 39, 31, 38, 81, 31, 79, 31, 79, 26, + 85, 31, 79, 26, 26, 26, 27, 30, 35, 83, + 84, 31, 1, 1, 47, 47, 56, 58, 62, 76, + 68, 74, 31, 31, 31, 31, 31, 31, 83, 83, + 32, 33, 81, 28, 34, 31, 31, 1, 12, 16, + 18, 19, 20, 21, 22, 24, 26, 31, 42, 48, + 49, 72, 73, 75, 17, 18, 19, 20, 31, 42, + 57, 73, 75, 41, 54, 80, 41, 55, 60, 67, + 80, 23, 31, 74, 77, 41, 55, 66, 67, 80, + 31, 42, 75, 29, 83, 83, 84, 84, 31, 31, + 25, 79, 78, 79, 83, 26, 84, 50, 1, 13, + 31, 79, 78, 26, 14, 82, 83, 82, 31, 82, + 82, 82, 84, 26, 31, 31, 82, 31, 82, 83, + 31, 31, 31, 31, 82, 34, 51, 31, 31, 31, + 79 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + case 53: /* "choice_entry" */ + + { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); + if (current_menu == (yyvaluep->menu)) + menu_end_menu(); +}; + + break; + case 59: /* "if_entry" */ + + { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); + if (current_menu == (yyvaluep->menu)) + menu_end_menu(); +}; + + break; + case 65: /* "menu_entry" */ + + { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); + if (current_menu == (yyvaluep->menu)) + menu_end_menu(); +}; + + break; + + default: + break; + } +} + +/* Prevent warnings from -Wmissing-prototypes. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + + +/*-------------------------. +| yyparse or yypush_parse. | +`-------------------------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 10: + + { zconf_error("unexpected end statement"); ;} + break; + + case 11: + + { zconf_error("unknown statement \"%s\"", (yyvsp[(2) - (4)].string)); ;} + break; + + case 12: + + { + zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[(2) - (4)].id)->name); +;} + break; + + case 13: + + { zconf_error("invalid statement"); ;} + break; + + case 28: + + { zconf_error("unknown option \"%s\"", (yyvsp[(1) - (3)].string)); ;} + break; + + case 29: + + { zconf_error("invalid option"); ;} + break; + + case 30: + + { + struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); +;} + break; + + case 31: + + { + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 32: + + { + struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); +;} + break; + + case 33: + + { + if (current_entry->prompt) + current_entry->prompt->type = P_MENU; + else + zconfprint("warning: menuconfig statement without prompt"); + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 41: + + { + menu_set_type((yyvsp[(1) - (3)].id)->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + (yyvsp[(1) - (3)].id)->stype); +;} + break; + + case 42: + + { + menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 43: + + { + menu_add_expr(P_DEFAULT, (yyvsp[(2) - (4)].expr), (yyvsp[(3) - (4)].expr)); + if ((yyvsp[(1) - (4)].id)->stype != S_UNKNOWN) + menu_set_type((yyvsp[(1) - (4)].id)->stype); + printd(DEBUG_PARSE, "%s:%d:default(%u)\n", + zconf_curname(), zconf_lineno(), + (yyvsp[(1) - (4)].id)->stype); +;} + break; + + case 44: + + { + menu_add_symbol(P_SELECT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 45: + + { + menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[(2) - (5)].symbol), (yyvsp[(3) - (5)].symbol)), (yyvsp[(4) - (5)].expr)); + printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 48: + + { + struct kconf_id *id = kconf_id_lookup((yyvsp[(2) - (3)].string), strlen((yyvsp[(2) - (3)].string))); + if (id && id->flags & TF_OPTION) + menu_add_option(id->token, (yyvsp[(3) - (3)].string)); + else + zconfprint("warning: ignoring unknown option %s", (yyvsp[(2) - (3)].string)); + free((yyvsp[(2) - (3)].string)); +;} + break; + + case 49: + + { (yyval.string) = NULL; ;} + break; + + case 50: + + { (yyval.string) = (yyvsp[(2) - (2)].string); ;} + break; + + case 51: + + { + struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), SYMBOL_CHOICE); + sym->flags |= SYMBOL_AUTO; + menu_add_entry(sym); + menu_add_expr(P_CHOICE, NULL, NULL); + printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 52: + + { + (yyval.menu) = menu_add_menu(); +;} + break; + + case 53: + + { + if (zconf_endtoken((yyvsp[(1) - (1)].id), T_CHOICE, T_ENDCHOICE)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); + } +;} + break; + + case 61: + + { + menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 62: + + { + if ((yyvsp[(1) - (3)].id)->stype == S_BOOLEAN || (yyvsp[(1) - (3)].id)->stype == S_TRISTATE) { + menu_set_type((yyvsp[(1) - (3)].id)->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + (yyvsp[(1) - (3)].id)->stype); + } else + YYERROR; +;} + break; + + case 63: + + { + current_entry->sym->flags |= SYMBOL_OPTIONAL; + printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 64: + + { + if ((yyvsp[(1) - (4)].id)->stype == S_UNKNOWN) { + menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:default\n", + zconf_curname(), zconf_lineno()); + } else + YYERROR; +;} + break; + + case 67: + + { + printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); + menu_add_entry(NULL); + menu_add_dep((yyvsp[(2) - (3)].expr)); + (yyval.menu) = menu_add_menu(); +;} + break; + + case 68: + + { + if (zconf_endtoken((yyvsp[(1) - (1)].id), T_IF, T_ENDIF)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); + } +;} + break; + + case 74: + + { + menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL); +;} + break; + + case 75: + + { + menu_add_entry(NULL); + menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL); + printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 76: + + { + (yyval.menu) = menu_add_menu(); +;} + break; + + case 77: + + { + if (zconf_endtoken((yyvsp[(1) - (1)].id), T_MENU, T_ENDMENU)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); + } +;} + break; + + case 83: + + { + printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); + zconf_nextfile((yyvsp[(2) - (3)].string)); +;} + break; + + case 84: + + { + menu_add_entry(NULL); + menu_add_prompt(P_COMMENT, (yyvsp[(2) - (3)].string), NULL); + printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 85: + + { + menu_end_entry(); +;} + break; + + case 86: + + { + printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); + zconf_starthelp(); +;} + break; + + case 87: + + { + current_entry->help = (yyvsp[(2) - (2)].string); +;} + break; + + case 92: + + { + menu_add_dep((yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 96: + + { + menu_add_visibility((yyvsp[(2) - (2)].expr)); +;} + break; + + case 98: + + { + menu_add_prompt(P_PROMPT, (yyvsp[(1) - (2)].string), (yyvsp[(2) - (2)].expr)); +;} + break; + + case 101: + + { (yyval.id) = (yyvsp[(1) - (2)].id); ;} + break; + + case 102: + + { (yyval.id) = (yyvsp[(1) - (2)].id); ;} + break; + + case 103: + + { (yyval.id) = (yyvsp[(1) - (2)].id); ;} + break; + + case 106: + + { (yyval.expr) = NULL; ;} + break; + + case 107: + + { (yyval.expr) = (yyvsp[(2) - (2)].expr); ;} + break; + + case 108: + + { (yyval.expr) = expr_alloc_symbol((yyvsp[(1) - (1)].symbol)); ;} + break; + + case 109: + + { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;} + break; + + case 110: + + { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;} + break; + + case 111: + + { (yyval.expr) = (yyvsp[(2) - (3)].expr); ;} + break; + + case 112: + + { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[(2) - (2)].expr)); ;} + break; + + case 113: + + { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;} + break; + + case 114: + + { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;} + break; + + case 115: + + { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 0); free((yyvsp[(1) - (1)].string)); ;} + break; + + case 116: + + { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), SYMBOL_CONST); free((yyvsp[(1) - (1)].string)); ;} + break; + + case 117: + + { (yyval.string) = NULL; ;} + break; + + + + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (yymsg); + } + else + { + yyerror (YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined(yyoverflow) || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + + + +void conf_parse(const char *name) +{ + struct symbol *sym; + int i; + + zconf_initscan(name); + + sym_init(); + _menu_init(); + modules_sym = sym_lookup(NULL, 0); + modules_sym->type = S_BOOLEAN; + modules_sym->flags |= SYMBOL_AUTO; + rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL); + +#if YYDEBUG + if (getenv("ZCONF_DEBUG")) + zconfdebug = 1; +#endif + zconfparse(); + if (zconfnerrs) + exit(1); + if (!modules_sym->prop) { + struct property *prop; + + prop = prop_alloc(P_DEFAULT, modules_sym); + prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0)); + } + + rootmenu.prompt->text = _(rootmenu.prompt->text); + rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text); + + menu_finalize(&rootmenu); + for_all_symbols(i, sym) { + if (sym_check_deps(sym)) + zconfnerrs++; + } + if (zconfnerrs) + exit(1); + sym_set_change_count(1); +} + +static const char *zconf_tokenname(int token) +{ + switch (token) { + case T_MENU: return "menu"; + case T_ENDMENU: return "endmenu"; + case T_CHOICE: return "choice"; + case T_ENDCHOICE: return "endchoice"; + case T_IF: return "if"; + case T_ENDIF: return "endif"; + case T_DEPENDS: return "depends"; + case T_VISIBLE: return "visible"; + } + return ""; +} + +static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken) +{ + if (id->token != endtoken) { + zconf_error("unexpected '%s' within %s block", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + if (current_menu->file != current_file) { + zconf_error("'%s' in different file than '%s'", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + fprintf(stderr, "%s:%d: location of the '%s'\n", + current_menu->file->name, current_menu->lineno, + zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + return true; +} + +static void zconfprint(const char *err, ...) +{ + va_list ap; + + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconf_error(const char *err, ...) +{ + va_list ap; + + zconfnerrs++; + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconferror(const char *err) +{ +#if YYDEBUG + fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); +#endif +} + +static void print_quoted_string(FILE *out, const char *str) +{ + const char *p; + int len; + + putc('"', out); + while ((p = strchr(str, '"'))) { + len = p - str; + if (len) + fprintf(out, "%.*s", len, str); + fputs("\\\"", out); + str = p + 1; + } + fputs(str, out); + putc('"', out); +} + +static void print_symbol(FILE *out, struct menu *menu) +{ + struct symbol *sym = menu->sym; + struct property *prop; + + if (sym_is_choice(sym)) + fprintf(out, "\nchoice\n"); + else + fprintf(out, "\nconfig %s\n", sym->name); + switch (sym->type) { + case S_BOOLEAN: + fputs(" boolean\n", out); + break; + case S_TRISTATE: + fputs(" tristate\n", out); + break; + case S_STRING: + fputs(" string\n", out); + break; + case S_INT: + fputs(" integer\n", out); + break; + case S_HEX: + fputs(" hex\n", out); + break; + default: + fputs(" ???\n", out); + break; + } + for (prop = sym->prop; prop; prop = prop->next) { + if (prop->menu != menu) + continue; + switch (prop->type) { + case P_PROMPT: + fputs(" prompt ", out); + print_quoted_string(out, prop->text); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_DEFAULT: + fputs( " default ", out); + expr_fprint(prop->expr, out); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_CHOICE: + fputs(" #choice value\n", out); + break; + case P_SELECT: + fputs( " select ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_RANGE: + fputs( " range ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_MENU: + fputs( " menu ", out); + print_quoted_string(out, prop->text); + fputc('\n', out); + break; + default: + fprintf(out, " unknown prop %d!\n", prop->type); + break; + } + } + if (menu->help) { + int len = strlen(menu->help); + while (menu->help[--len] == '\n') + menu->help[len] = 0; + fprintf(out, " help\n%s\n", menu->help); + } +} + +void zconfdump(FILE *out) +{ + struct property *prop; + struct symbol *sym; + struct menu *menu; + + menu = rootmenu.list; + while (menu) { + if ((sym = menu->sym)) + print_symbol(out, menu); + else if ((prop = menu->prompt)) { + switch (prop->type) { + case P_COMMENT: + fputs("\ncomment ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + case P_MENU: + fputs("\nmenu ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + default: + ; + } + if (!expr_is_yes(prop->visible.expr)) { + fputs(" depends ", out); + expr_fprint(prop->visible.expr, out); + fputc('\n', out); + } + } + + if (menu->list) + menu = menu->list; + else if (menu->next) + menu = menu->next; + else while ((menu = menu->parent)) { + if (menu->prompt && menu->prompt->type == P_MENU) + fputs("\nendmenu\n", out); + if (menu->next) { + menu = menu->next; + break; + } + } + } +} + +#include "lex.zconf.c" +#include "util.c" +#include "confdata.c" +#include "expr.c" +#include "symbol.c" +#include "menu.c" + diff --git a/bios/seabios/tools/kconfig/zconf.y b/bios/seabios/tools/kconfig/zconf.y new file mode 100644 index 0000000..49fb4ab --- /dev/null +++ b/bios/seabios/tools/kconfig/zconf.y @@ -0,0 +1,749 @@ +%{ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) + +#define PRINTD 0x0001 +#define DEBUG_PARSE 0x0002 + +int cdebug = PRINTD; + +extern int zconflex(void); +static void zconfprint(const char *err, ...); +static void zconf_error(const char *err, ...); +static void zconferror(const char *err); +static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken); + +struct symbol *symbol_hash[SYMBOL_HASHSIZE]; + +static struct menu *current_menu, *current_entry; + +#define YYDEBUG 0 +#if YYDEBUG +#define YYERROR_VERBOSE +#endif +%} +%expect 30 + +%union +{ + char *string; + struct file *file; + struct symbol *symbol; + struct expr *expr; + struct menu *menu; + struct kconf_id *id; +} + +%token T_MAINMENU +%token T_MENU +%token T_ENDMENU +%token T_SOURCE +%token T_CHOICE +%token T_ENDCHOICE +%token T_COMMENT +%token T_CONFIG +%token T_MENUCONFIG +%token T_HELP +%token T_HELPTEXT +%token T_IF +%token T_ENDIF +%token T_DEPENDS +%token T_OPTIONAL +%token T_PROMPT +%token T_TYPE +%token T_DEFAULT +%token T_SELECT +%token T_RANGE +%token T_VISIBLE +%token T_OPTION +%token T_ON +%token T_WORD +%token T_WORD_QUOTE +%token T_UNEQUAL +%token T_CLOSE_PAREN +%token T_OPEN_PAREN +%token T_EOL + +%left T_OR +%left T_AND +%left T_EQUAL T_UNEQUAL +%nonassoc T_NOT + +%type prompt +%type symbol +%type expr +%type if_expr +%type end +%type option_name +%type if_entry menu_entry choice_entry +%type symbol_option_arg word_opt + +%destructor { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + $$->file->name, $$->lineno); + if (current_menu == $$) + menu_end_menu(); +} if_entry menu_entry choice_entry + +%{ +/* Include zconf.hash.c here so it can see the token constants. */ +#include "zconf.hash.c" +%} + +%% +input: nl start | start; + +start: mainmenu_stmt stmt_list | stmt_list; + +stmt_list: + /* empty */ + | stmt_list common_stmt + | stmt_list choice_stmt + | stmt_list menu_stmt + | stmt_list end { zconf_error("unexpected end statement"); } + | stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); } + | stmt_list option_name error T_EOL +{ + zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name); +} + | stmt_list error T_EOL { zconf_error("invalid statement"); } +; + +option_name: + T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE +; + +common_stmt: + T_EOL + | if_stmt + | comment_stmt + | config_stmt + | menuconfig_stmt + | source_stmt +; + +option_error: + T_WORD error T_EOL { zconf_error("unknown option \"%s\"", $1); } + | error T_EOL { zconf_error("invalid option"); } +; + + +/* config/menuconfig entry */ + +config_entry_start: T_CONFIG T_WORD T_EOL +{ + struct symbol *sym = sym_lookup($2, 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2); +}; + +config_stmt: config_entry_start config_option_list +{ + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +}; + +menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL +{ + struct symbol *sym = sym_lookup($2, 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2); +}; + +menuconfig_stmt: menuconfig_entry_start config_option_list +{ + if (current_entry->prompt) + current_entry->prompt->type = P_MENU; + else + zconfprint("warning: menuconfig statement without prompt"); + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +}; + +config_option_list: + /* empty */ + | config_option_list config_option + | config_option_list symbol_option + | config_option_list depends + | config_option_list help + | config_option_list option_error + | config_option_list T_EOL +; + +config_option: T_TYPE prompt_stmt_opt T_EOL +{ + menu_set_type($1->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + $1->stype); +}; + +config_option: T_PROMPT prompt if_expr T_EOL +{ + menu_add_prompt(P_PROMPT, $2, $3); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +}; + +config_option: T_DEFAULT expr if_expr T_EOL +{ + menu_add_expr(P_DEFAULT, $2, $3); + if ($1->stype != S_UNKNOWN) + menu_set_type($1->stype); + printd(DEBUG_PARSE, "%s:%d:default(%u)\n", + zconf_curname(), zconf_lineno(), + $1->stype); +}; + +config_option: T_SELECT T_WORD if_expr T_EOL +{ + menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3); + printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); +}; + +config_option: T_RANGE symbol symbol if_expr T_EOL +{ + menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4); + printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); +}; + +symbol_option: T_OPTION symbol_option_list T_EOL +; + +symbol_option_list: + /* empty */ + | symbol_option_list T_WORD symbol_option_arg +{ + struct kconf_id *id = kconf_id_lookup($2, strlen($2)); + if (id && id->flags & TF_OPTION) + menu_add_option(id->token, $3); + else + zconfprint("warning: ignoring unknown option %s", $2); + free($2); +}; + +symbol_option_arg: + /* empty */ { $$ = NULL; } + | T_EQUAL prompt { $$ = $2; } +; + +/* choice entry */ + +choice: T_CHOICE word_opt T_EOL +{ + struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE); + sym->flags |= SYMBOL_AUTO; + menu_add_entry(sym); + menu_add_expr(P_CHOICE, NULL, NULL); + printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); +}; + +choice_entry: choice choice_option_list +{ + $$ = menu_add_menu(); +}; + +choice_end: end +{ + if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); + } +}; + +choice_stmt: choice_entry choice_block choice_end +; + +choice_option_list: + /* empty */ + | choice_option_list choice_option + | choice_option_list depends + | choice_option_list help + | choice_option_list T_EOL + | choice_option_list option_error +; + +choice_option: T_PROMPT prompt if_expr T_EOL +{ + menu_add_prompt(P_PROMPT, $2, $3); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +}; + +choice_option: T_TYPE prompt_stmt_opt T_EOL +{ + if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) { + menu_set_type($1->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + $1->stype); + } else + YYERROR; +}; + +choice_option: T_OPTIONAL T_EOL +{ + current_entry->sym->flags |= SYMBOL_OPTIONAL; + printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); +}; + +choice_option: T_DEFAULT T_WORD if_expr T_EOL +{ + if ($1->stype == S_UNKNOWN) { + menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3); + printd(DEBUG_PARSE, "%s:%d:default\n", + zconf_curname(), zconf_lineno()); + } else + YYERROR; +}; + +choice_block: + /* empty */ + | choice_block common_stmt +; + +/* if entry */ + +if_entry: T_IF expr nl +{ + printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); + menu_add_entry(NULL); + menu_add_dep($2); + $$ = menu_add_menu(); +}; + +if_end: end +{ + if (zconf_endtoken($1, T_IF, T_ENDIF)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); + } +}; + +if_stmt: if_entry if_block if_end +; + +if_block: + /* empty */ + | if_block common_stmt + | if_block menu_stmt + | if_block choice_stmt +; + +/* mainmenu entry */ + +mainmenu_stmt: T_MAINMENU prompt nl +{ + menu_add_prompt(P_MENU, $2, NULL); +}; + +/* menu entry */ + +menu: T_MENU prompt T_EOL +{ + menu_add_entry(NULL); + menu_add_prompt(P_MENU, $2, NULL); + printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); +}; + +menu_entry: menu visibility_list depends_list +{ + $$ = menu_add_menu(); +}; + +menu_end: end +{ + if (zconf_endtoken($1, T_MENU, T_ENDMENU)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); + } +}; + +menu_stmt: menu_entry menu_block menu_end +; + +menu_block: + /* empty */ + | menu_block common_stmt + | menu_block menu_stmt + | menu_block choice_stmt +; + +source_stmt: T_SOURCE prompt T_EOL +{ + printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2); + zconf_nextfile($2); +}; + +/* comment entry */ + +comment: T_COMMENT prompt T_EOL +{ + menu_add_entry(NULL); + menu_add_prompt(P_COMMENT, $2, NULL); + printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); +}; + +comment_stmt: comment depends_list +{ + menu_end_entry(); +}; + +/* help option */ + +help_start: T_HELP T_EOL +{ + printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); + zconf_starthelp(); +}; + +help: help_start T_HELPTEXT +{ + current_entry->help = $2; +}; + +/* depends option */ + +depends_list: + /* empty */ + | depends_list depends + | depends_list T_EOL + | depends_list option_error +; + +depends: T_DEPENDS T_ON expr T_EOL +{ + menu_add_dep($3); + printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); +}; + +/* visibility option */ + +visibility_list: + /* empty */ + | visibility_list visible + | visibility_list T_EOL +; + +visible: T_VISIBLE if_expr +{ + menu_add_visibility($2); +}; + +/* prompt statement */ + +prompt_stmt_opt: + /* empty */ + | prompt if_expr +{ + menu_add_prompt(P_PROMPT, $1, $2); +}; + +prompt: T_WORD + | T_WORD_QUOTE +; + +end: T_ENDMENU T_EOL { $$ = $1; } + | T_ENDCHOICE T_EOL { $$ = $1; } + | T_ENDIF T_EOL { $$ = $1; } +; + +nl: + T_EOL + | nl T_EOL +; + +if_expr: /* empty */ { $$ = NULL; } + | T_IF expr { $$ = $2; } +; + +expr: symbol { $$ = expr_alloc_symbol($1); } + | symbol T_EQUAL symbol { $$ = expr_alloc_comp(E_EQUAL, $1, $3); } + | symbol T_UNEQUAL symbol { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); } + | T_OPEN_PAREN expr T_CLOSE_PAREN { $$ = $2; } + | T_NOT expr { $$ = expr_alloc_one(E_NOT, $2); } + | expr T_OR expr { $$ = expr_alloc_two(E_OR, $1, $3); } + | expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); } +; + +symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); } + | T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); } +; + +word_opt: /* empty */ { $$ = NULL; } + | T_WORD + +%% + +void conf_parse(const char *name) +{ + struct symbol *sym; + int i; + + zconf_initscan(name); + + sym_init(); + _menu_init(); + modules_sym = sym_lookup(NULL, 0); + modules_sym->type = S_BOOLEAN; + modules_sym->flags |= SYMBOL_AUTO; + rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL); + +#if YYDEBUG + if (getenv("ZCONF_DEBUG")) + zconfdebug = 1; +#endif + zconfparse(); + if (zconfnerrs) + exit(1); + if (!modules_sym->prop) { + struct property *prop; + + prop = prop_alloc(P_DEFAULT, modules_sym); + prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0)); + } + + rootmenu.prompt->text = _(rootmenu.prompt->text); + rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text); + + menu_finalize(&rootmenu); + for_all_symbols(i, sym) { + if (sym_check_deps(sym)) + zconfnerrs++; + } + if (zconfnerrs) + exit(1); + sym_set_change_count(1); +} + +static const char *zconf_tokenname(int token) +{ + switch (token) { + case T_MENU: return "menu"; + case T_ENDMENU: return "endmenu"; + case T_CHOICE: return "choice"; + case T_ENDCHOICE: return "endchoice"; + case T_IF: return "if"; + case T_ENDIF: return "endif"; + case T_DEPENDS: return "depends"; + case T_VISIBLE: return "visible"; + } + return ""; +} + +static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken) +{ + if (id->token != endtoken) { + zconf_error("unexpected '%s' within %s block", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + if (current_menu->file != current_file) { + zconf_error("'%s' in different file than '%s'", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + fprintf(stderr, "%s:%d: location of the '%s'\n", + current_menu->file->name, current_menu->lineno, + zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + return true; +} + +static void zconfprint(const char *err, ...) +{ + va_list ap; + + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconf_error(const char *err, ...) +{ + va_list ap; + + zconfnerrs++; + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconferror(const char *err) +{ +#if YYDEBUG + fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); +#endif +} + +static void print_quoted_string(FILE *out, const char *str) +{ + const char *p; + int len; + + putc('"', out); + while ((p = strchr(str, '"'))) { + len = p - str; + if (len) + fprintf(out, "%.*s", len, str); + fputs("\\\"", out); + str = p + 1; + } + fputs(str, out); + putc('"', out); +} + +static void print_symbol(FILE *out, struct menu *menu) +{ + struct symbol *sym = menu->sym; + struct property *prop; + + if (sym_is_choice(sym)) + fprintf(out, "\nchoice\n"); + else + fprintf(out, "\nconfig %s\n", sym->name); + switch (sym->type) { + case S_BOOLEAN: + fputs(" boolean\n", out); + break; + case S_TRISTATE: + fputs(" tristate\n", out); + break; + case S_STRING: + fputs(" string\n", out); + break; + case S_INT: + fputs(" integer\n", out); + break; + case S_HEX: + fputs(" hex\n", out); + break; + default: + fputs(" ???\n", out); + break; + } + for (prop = sym->prop; prop; prop = prop->next) { + if (prop->menu != menu) + continue; + switch (prop->type) { + case P_PROMPT: + fputs(" prompt ", out); + print_quoted_string(out, prop->text); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_DEFAULT: + fputs( " default ", out); + expr_fprint(prop->expr, out); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_CHOICE: + fputs(" #choice value\n", out); + break; + case P_SELECT: + fputs( " select ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_RANGE: + fputs( " range ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_MENU: + fputs( " menu ", out); + print_quoted_string(out, prop->text); + fputc('\n', out); + break; + default: + fprintf(out, " unknown prop %d!\n", prop->type); + break; + } + } + if (menu->help) { + int len = strlen(menu->help); + while (menu->help[--len] == '\n') + menu->help[len] = 0; + fprintf(out, " help\n%s\n", menu->help); + } +} + +void zconfdump(FILE *out) +{ + struct property *prop; + struct symbol *sym; + struct menu *menu; + + menu = rootmenu.list; + while (menu) { + if ((sym = menu->sym)) + print_symbol(out, menu); + else if ((prop = menu->prompt)) { + switch (prop->type) { + case P_COMMENT: + fputs("\ncomment ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + case P_MENU: + fputs("\nmenu ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + default: + ; + } + if (!expr_is_yes(prop->visible.expr)) { + fputs(" depends ", out); + expr_fprint(prop->visible.expr, out); + fputc('\n', out); + } + } + + if (menu->list) + menu = menu->list; + else if (menu->next) + menu = menu->next; + else while ((menu = menu->parent)) { + if (menu->prompt && menu->prompt->type == P_MENU) + fputs("\nendmenu\n", out); + if (menu->next) { + menu = menu->next; + break; + } + } + } +} + +#include "lex.zconf.c" +#include "util.c" +#include "confdata.c" +#include "expr.c" +#include "symbol.c" +#include "menu.c" diff --git a/bios/seabios/tools/layoutrom.py b/bios/seabios/tools/layoutrom.py new file mode 100755 index 0000000..45738a3 --- /dev/null +++ b/bios/seabios/tools/layoutrom.py @@ -0,0 +1,579 @@ +#!/usr/bin/env python +# Script to analyze code and arrange ld sections. +# +# Copyright (C) 2008-2010 Kevin O'Connor +# +# This file may be distributed under the terms of the GNU GPLv3 license. + +import sys + +# LD script headers/trailers +COMMONHEADER = """ +/* DO NOT EDIT! This is an autogenerated file. See tools/layoutrom.py. */ +OUTPUT_FORMAT("elf32-i386") +OUTPUT_ARCH("i386") +SECTIONS +{ +""" +COMMONTRAILER = """ + + /* Discard regular data sections to force a link error if + * code attempts to access data not marked with VAR16 (or other + * appropriate macro) + */ + /DISCARD/ : { + *(.text*) *(.data*) *(.bss*) *(.rodata*) + *(COMMON) *(.discard*) *(.eh_frame) + } +} +""" + + +###################################################################### +# Determine section locations +###################################################################### + +# Align 'pos' to 'alignbytes' offset +def alignpos(pos, alignbytes): + mask = alignbytes - 1 + return (pos + mask) & ~mask + +# Determine the final addresses for a list of sections that end at an +# address. +def setSectionsStart(sections, endaddr, minalign=1): + totspace = 0 + for section in sections: + if section.align > minalign: + minalign = section.align + totspace = alignpos(totspace, section.align) + section.size + startaddr = (endaddr - totspace) / minalign * minalign + curaddr = startaddr + # out = [(addr, sectioninfo), ...] + out = [] + for section in sections: + curaddr = alignpos(curaddr, section.align) + section.finalloc = curaddr + curaddr += section.size + return startaddr + +# The 16bit code can't exceed 64K of space. +BUILD_BIOS_ADDR = 0xf0000 +BUILD_BIOS_SIZE = 0x10000 + +# Layout the 16bit code. This ensures sections with fixed offset +# requirements are placed in the correct location. It also places the +# 16bit code as high as possible in the f-segment. +def fitSections(sections, fillsections): + # fixedsections = [(addr, section), ...] + fixedsections = [] + for section in sections: + if section.name.startswith('.fixedaddr.'): + addr = int(section.name[11:], 16) + section.finalloc = addr + fixedsections.append((addr, section)) + if section.align != 1: + print "Error: Fixed section %s has non-zero alignment (%d)" % ( + section.name, section.align) + sys.exit(1) + fixedsections.sort() + firstfixed = fixedsections[0][0] + + # Find freespace in fixed address area + # fixedAddr = [(freespace, section), ...] + fixedAddr = [] + for i in range(len(fixedsections)): + fixedsectioninfo = fixedsections[i] + addr, section = fixedsectioninfo + if i == len(fixedsections) - 1: + nextaddr = BUILD_BIOS_SIZE + else: + nextaddr = fixedsections[i+1][0] + avail = nextaddr - addr - section.size + fixedAddr.append((avail, section)) + fixedAddr.sort() + + # Attempt to fit other sections into fixed area + canrelocate = [(section.size, section.align, section.name, section) + for section in fillsections] + canrelocate.sort() + canrelocate = [section for size, align, name, section in canrelocate] + totalused = 0 + for freespace, fixedsection in fixedAddr: + addpos = fixedsection.finalloc + fixedsection.size + totalused += fixedsection.size + nextfixedaddr = addpos + freespace +# print "Filling section %x uses %d, next=%x, available=%d" % ( +# fixedsection.finalloc, fixedsection.size, nextfixedaddr, freespace) + while 1: + canfit = None + for fitsection in canrelocate: + if addpos + fitsection.size > nextfixedaddr: + # Can't fit and nothing else will fit. + break + fitnextaddr = alignpos(addpos, fitsection.align) + fitsection.size +# print "Test %s - %x vs %x" % ( +# fitsection.name, fitnextaddr, nextfixedaddr) + if fitnextaddr > nextfixedaddr: + # This item can't fit. + continue + canfit = (fitnextaddr, fitsection) + if canfit is None: + break + # Found a section that can fit. + fitnextaddr, fitsection = canfit + canrelocate.remove(fitsection) + fitsection.finalloc = addpos + addpos = fitnextaddr + totalused += fitsection.size +# print " Adding %s (size %d align %d) pos=%x avail=%d" % ( +# fitsection[2], fitsection[0], fitsection[1] +# , fitnextaddr, nextfixedaddr - fitnextaddr) + + # Report stats + total = BUILD_BIOS_SIZE-firstfixed + slack = total - totalused + print ("Fixed space: 0x%x-0x%x total: %d slack: %d" + " Percent slack: %.1f%%" % ( + firstfixed, BUILD_BIOS_SIZE, total, slack, + (float(slack) / total) * 100.0)) + + return firstfixed + +# Return the subset of sections with a given name prefix +def getSectionsPrefix(sections, category, prefix): + return [section for section in sections + if section.category == category and section.name.startswith(prefix)] + +def doLayout(sections): + # Determine 16bit positions + textsections = getSectionsPrefix(sections, '16', '.text.') + rodatasections = (getSectionsPrefix(sections, '16', '.rodata.str1.1') + + getSectionsPrefix(sections, '16', '.rodata.__func__.')) + datasections = getSectionsPrefix(sections, '16', '.data16.') + fixedsections = getSectionsPrefix(sections, '16', '.fixedaddr.') + + firstfixed = fitSections(fixedsections, textsections) + remsections = [s for s in textsections+rodatasections+datasections + if s.finalloc is None] + code16_start = setSectionsStart(remsections, firstfixed) + + # Determine 32seg positions + textsections = getSectionsPrefix(sections, '32seg', '.text.') + rodatasections = (getSectionsPrefix(sections, '32seg', '.rodata.str1.1') + +getSectionsPrefix(sections, '32seg', '.rodata.__func__.')) + datasections = getSectionsPrefix(sections, '32seg', '.data32seg.') + + code32seg_start = setSectionsStart( + textsections + rodatasections + datasections, code16_start) + + # Determine 32flat runtime positions + textsections = getSectionsPrefix(sections, '32flat', '.text.') + rodatasections = getSectionsPrefix(sections, '32flat', '.rodata') + datasections = getSectionsPrefix(sections, '32flat', '.data.') + bsssections = getSectionsPrefix(sections, '32flat', '.bss.') + + code32flat_start = setSectionsStart( + textsections + rodatasections + datasections + bsssections + , code32seg_start + BUILD_BIOS_ADDR, 16) + + # Determine 32flat init positions + textsections = getSectionsPrefix(sections, '32init', '.text.') + rodatasections = getSectionsPrefix(sections, '32init', '.rodata') + datasections = getSectionsPrefix(sections, '32init', '.data.') + bsssections = getSectionsPrefix(sections, '32init', '.bss.') + + code32init_start = setSectionsStart( + textsections + rodatasections + datasections + bsssections + , code32flat_start, 16) + + # Print statistics + size16 = BUILD_BIOS_SIZE - code16_start + size32seg = code16_start - code32seg_start + size32flat = code32seg_start + BUILD_BIOS_ADDR - code32flat_start + size32init = code32flat_start - code32init_start + print "16bit size: %d" % size16 + print "32bit segmented size: %d" % size32seg + print "32bit flat size: %d" % size32flat + print "32bit flat init size: %d" % size32init + + +###################################################################### +# Linker script output +###################################################################### + +# Write LD script includes for the given cross references +def outXRefs(sections): + xrefs = {} + out = "" + for section in sections: + for reloc in section.relocs: + symbol = reloc.symbol + if (symbol.section is None + or (symbol.section.fileid == section.fileid + and symbol.name == reloc.symbolname) + or reloc.symbolname in xrefs): + continue + xrefs[reloc.symbolname] = 1 + addr = symbol.section.finalloc + symbol.offset + if (section.fileid == '32flat' + and symbol.section.fileid in ('16', '32seg')): + addr += BUILD_BIOS_ADDR + out += "%s = 0x%x ;\n" % (reloc.symbolname, addr) + return out + +# Write LD script includes for the given sections using relative offsets +def outRelSections(sections, startsym): + out = "" + for section in sections: + out += ". = ( 0x%x - %s ) ;\n" % (section.finalloc, startsym) + if section.name == '.rodata.str1.1': + out += "_rodata = . ;\n" + out += "*(%s)\n" % (section.name,) + return out + +def getSectionsFile(sections, fileid, defaddr=0): + sections = [(section.finalloc, section) + for section in sections if section.fileid == fileid] + sections.sort() + sections = [section for addr, section in sections] + pos = defaddr + if sections: + pos = sections[0].finalloc + return sections, pos + +# Layout the 32bit segmented code. This places the code as high as possible. +def writeLinkerScripts(sections, entrysym, genreloc, out16, out32seg, out32flat): + # Write 16bit linker script + sections16, code16_start = getSectionsFile(sections, '16') + output = open(out16, 'wb') + output.write(COMMONHEADER + outXRefs(sections16) + """ + code16_start = 0x%x ; + .text16 code16_start : { +""" % (code16_start) + + outRelSections(sections16, 'code16_start') + + """ + } +""" + + COMMONTRAILER) + output.close() + + # Write 32seg linker script + sections32seg, code32seg_start = getSectionsFile( + sections, '32seg', code16_start) + output = open(out32seg, 'wb') + output.write(COMMONHEADER + outXRefs(sections32seg) + """ + code32seg_start = 0x%x ; + .text32seg code32seg_start : { +""" % (code32seg_start) + + outRelSections(sections32seg, 'code32seg_start') + + """ + } +""" + + COMMONTRAILER) + output.close() + + # Write 32flat linker script + sections32flat, code32flat_start = getSectionsFile( + sections, '32flat', code32seg_start) + relocstr = "" + relocminalign = 0 + if genreloc: + # Generate relocations + relocstr, size, relocminalign = genRelocs(sections) + code32flat_start -= size + output = open(out32flat, 'wb') + output.write(COMMONHEADER + + outXRefs(sections32flat) + """ + %s = 0x%x ; + _reloc_min_align = 0x%x ; + code32flat_start = 0x%x ; + .text code32flat_start : { +""" % (entrysym.name, + entrysym.section.finalloc + entrysym.offset + BUILD_BIOS_ADDR, + relocminalign, code32flat_start) + + relocstr + + """ + code32init_start = ABSOLUTE(.) ; +""" + + outRelSections(getSectionsPrefix(sections32flat, '32init', '') + , 'code32flat_start') + + """ + code32init_end = ABSOLUTE(.) ; +""" + + outRelSections(getSectionsPrefix(sections32flat, '32flat', '') + , 'code32flat_start') + + """ + . = ( 0x%x - code32flat_start ) ; + *(.text32seg) + . = ( 0x%x - code32flat_start ) ; + *(.text16) + code32flat_end = ABSOLUTE(.) ; + } :text +""" % (code32seg_start + BUILD_BIOS_ADDR, code16_start + BUILD_BIOS_ADDR) + + COMMONTRAILER + + """ +ENTRY(%s) +PHDRS +{ + text PT_LOAD AT ( code32flat_start ) ; +} +""" % (entrysym.name,)) + output.close() + + +###################################################################### +# Detection of init code +###################################################################### + +# Determine init section relocations +def genRelocs(sections): + absrelocs = [] + relrelocs = [] + initrelocs = [] + minalign = 16 + for section in sections: + if section.category == '32init' and section.align > minalign: + minalign = section.align + for reloc in section.relocs: + symbol = reloc.symbol + if symbol.section is None: + continue + relocpos = section.finalloc + reloc.offset + if (reloc.type == 'R_386_32' and section.category == '32init' + and symbol.section.category == '32init'): + # Absolute relocation + absrelocs.append(relocpos) + elif (reloc.type == 'R_386_PC32' and section.category == '32init' + and symbol.section.category != '32init'): + # Relative relocation + relrelocs.append(relocpos) + elif (section.category != '32init' + and symbol.section.category == '32init'): + # Relocation to the init section + if section.fileid in ('16', '32seg'): + relocpos += BUILD_BIOS_ADDR + initrelocs.append(relocpos) + absrelocs.sort() + relrelocs.sort() + initrelocs.sort() + out = (" _reloc_abs_start = ABSOLUTE(.) ;\n" + + "".join(["LONG(0x%x - code32init_start)\n" % (pos,) + for pos in absrelocs]) + + " _reloc_abs_end = ABSOLUTE(.) ;\n" + + " _reloc_rel_start = ABSOLUTE(.) ;\n" + + "".join(["LONG(0x%x - code32init_start)\n" % (pos,) + for pos in relrelocs]) + + " _reloc_rel_end = ABSOLUTE(.) ;\n" + + " _reloc_init_start = ABSOLUTE(.) ;\n" + + "".join(["LONG(0x%x - code32flat_start)\n" % (pos,) + for pos in initrelocs]) + + " _reloc_init_end = ABSOLUTE(.) ;\n") + return out, len(absrelocs + relrelocs + initrelocs) * 4, minalign + +def markRuntime(section, sections): + if (section is None or not section.keep or section.category is not None + or '.init.' in section.name or section.fileid != '32flat'): + return + section.category = '32flat' + # Recursively mark all sections this section points to + for reloc in section.relocs: + markRuntime(reloc.symbol.section, sections) + +def findInit(sections): + # Recursively find and mark all "runtime" sections. + for section in sections: + if '.runtime.' in section.name or '.export.' in section.name: + markRuntime(section, sections) + for section in sections: + if section.category is not None: + continue + if section.fileid == '32flat': + section.category = '32init' + else: + section.category = section.fileid + + +###################################################################### +# Section garbage collection +###################################################################### + +CFUNCPREFIX = [('_cfunc16_', 0), ('_cfunc32seg_', 1), ('_cfunc32flat_', 2)] + +# Find and keep the section associated with a symbol (if available). +def keepsymbol(reloc, infos, pos, isxref): + symbolname = reloc.symbolname + mustbecfunc = 0 + for symprefix, needpos in CFUNCPREFIX: + if symbolname.startswith(symprefix): + if needpos != pos: + return -1 + symbolname = symbolname[len(symprefix):] + mustbecfunc = 1 + break + symbol = infos[pos][1].get(symbolname) + if (symbol is None or symbol.section is None + or symbol.section.name.startswith('.discard.')): + return -1 + isdestcfunc = (symbol.section.name.startswith('.text.') + and not symbol.section.name.startswith('.text.asm.')) + if ((mustbecfunc and not isdestcfunc) + or (not mustbecfunc and isdestcfunc and isxref)): + return -1 + + reloc.symbol = symbol + keepsection(symbol.section, infos, pos) + return 0 + +# Note required section, and recursively set all referenced sections +# as required. +def keepsection(section, infos, pos=0): + if section.keep: + # Already kept - nothing to do. + return + section.keep = 1 + # Keep all sections that this section points to + for reloc in section.relocs: + ret = keepsymbol(reloc, infos, pos, 0) + if not ret: + continue + # Not in primary sections - it may be a cross 16/32 reference + ret = keepsymbol(reloc, infos, (pos+1)%3, 1) + if not ret: + continue + ret = keepsymbol(reloc, infos, (pos+2)%3, 1) + if not ret: + continue + +# Determine which sections are actually referenced and need to be +# placed into the output file. +def gc(info16, info32seg, info32flat): + # infos = ((sections16, symbols16), (sect32seg, sym32seg) + # , (sect32flat, sym32flat)) + infos = (info16, info32seg, info32flat) + # Start by keeping sections that are globally visible. + for section in info16[0]: + if section.name.startswith('.fixedaddr.') or '.export.' in section.name: + keepsection(section, infos) + return [section for section in info16[0]+info32seg[0]+info32flat[0] + if section.keep] + + +###################################################################### +# Startup and input parsing +###################################################################### + +class Section: + name = size = alignment = fileid = relocs = None + finalloc = category = keep = None +class Reloc: + offset = type = symbolname = symbol = None +class Symbol: + name = offset = section = None + +# Read in output from objdump +def parseObjDump(file, fileid): + # sections = [section, ...] + sections = [] + sectionmap = {} + # symbols[symbolname] = symbol + symbols = {} + + state = None + for line in file.readlines(): + line = line.rstrip() + if line == 'Sections:': + state = 'section' + continue + if line == 'SYMBOL TABLE:': + state = 'symbol' + continue + if line.startswith('RELOCATION RECORDS FOR ['): + sectionname = line[24:-2] + if sectionname.startswith('.debug_'): + # Skip debugging sections (to reduce parsing time) + state = None + continue + state = 'reloc' + relocsection = sectionmap[sectionname] + continue + + if state == 'section': + try: + idx, name, size, vma, lma, fileoff, align = line.split() + if align[:3] != '2**': + continue + section = Section() + section.name = name + section.size = int(size, 16) + section.align = 2**int(align[3:]) + section.fileid = fileid + section.relocs = [] + sections.append(section) + sectionmap[name] = section + except ValueError: + pass + continue + if state == 'symbol': + try: + sectionname, size, name = line[17:].split() + symbol = Symbol() + symbol.size = int(size, 16) + symbol.offset = int(line[:8], 16) + symbol.name = name + symbol.section = sectionmap.get(sectionname) + symbols[name] = symbol + except ValueError: + pass + continue + if state == 'reloc': + try: + off, type, symbolname = line.split() + reloc = Reloc() + reloc.offset = int(off, 16) + reloc.type = type + reloc.symbolname = symbolname + reloc.symbol = symbols.get(symbolname) + if reloc.symbol is None: + # Some binutils (2.20.1) give section name instead + # of a symbol - create a dummy symbol. + reloc.symbol = symbol = Symbol() + symbol.size = 0 + symbol.offset = 0 + symbol.name = symbolname + symbol.section = sectionmap.get(symbolname) + symbols[symbolname] = symbol + relocsection.relocs.append(reloc) + except ValueError: + pass + return sections, symbols + +def main(): + # Get output name + in16, in32seg, in32flat, out16, out32seg, out32flat = sys.argv[1:] + + # Read in the objdump information + infile16 = open(in16, 'rb') + infile32seg = open(in32seg, 'rb') + infile32flat = open(in32flat, 'rb') + + # infoX = (sections, symbols) + info16 = parseObjDump(infile16, '16') + info32seg = parseObjDump(infile32seg, '32seg') + info32flat = parseObjDump(infile32flat, '32flat') + + # Figure out which sections to keep. + sections = gc(info16, info32seg, info32flat) + + # Separate 32bit flat into runtime and init parts + findInit(sections) + + # Determine the final memory locations of each kept section. + doLayout(sections) + + # Write out linker script files. + entrysym = info16[1]['entry_elf'] + genreloc = '_reloc_abs_start' in info32flat[1] + writeLinkerScripts(sections, entrysym, genreloc, out16, out32seg, out32flat) + +if __name__ == '__main__': + main() diff --git a/bios/seabios/tools/layoutrom.pyc b/bios/seabios/tools/layoutrom.pyc new file mode 100644 index 0000000..f0425ce Binary files /dev/null and b/bios/seabios/tools/layoutrom.pyc differ diff --git a/bios/seabios/tools/readserial.py b/bios/seabios/tools/readserial.py new file mode 100755 index 0000000..d85392e --- /dev/null +++ b/bios/seabios/tools/readserial.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python +# Script that can read from a serial device and show timestamps. +# +# Copyright (C) 2009 Kevin O'Connor +# +# This file may be distributed under the terms of the GNU GPLv3 license. + +# Usage: +# tools/readserial.py /dev/ttyUSB0 115200 + +import sys +import time +import select +import optparse + +# Reset time counter after this much idle time. +RESTARTINTERVAL = 60 +# Number of bits in a transmitted byte - 8N1 is 1 start bit + 8 data +# bits + 1 stop bit. +BITSPERBYTE = 10 + +def calibrateserialwrite(outfile, byteadjust): + # Build 4000 bytes of dummy data. + data = "0123456789" * 4 + "012345678" + "\n" + data = data * 80 + while 1: + st = time.time() + outfile.write(data) + outfile.flush() + et = time.time() + sys.stdout.write( + "Wrote %d - %.1fus per char (theory states %.1fus)\n" % ( + len(data), (et-st) / len(data) * 1000000, byteadjust * 1000000)) + sys.stdout.flush() + time.sleep(3) + +def calibrateserialread(infile, byteadjust): + starttime = lasttime = 0 + totalchars = 0 + while 1: + select.select([infile], [], []) + d = infile.read(4096) + curtime = time.time() + if curtime - lasttime > 1.0: + if starttime and totalchars: + sys.stdout.write( + "Calibrating on %d bytes - %.1fus per char" + " (theory states %.1fus)\n" % ( + totalchars, + float(lasttime - starttime) * 1000000 / totalchars, + byteadjust * 1000000)) + totalchars = 0 + starttime = curtime + else: + totalchars += len(d) + lasttime = curtime + +def readserial(infile, logfile, byteadjust): + lasttime = 0 + while 1: + # Read data + try: + res = select.select([infile, sys.stdin], [], []) + except KeyboardInterrupt: + sys.stdout.write("\n") + break + if sys.stdin in res[0]: + # Got keyboard input - force reset on next serial input + sys.stdin.read(1) + lasttime = 0 + if len(res[0]) == 1: + continue + d = infile.read(4096) + if not d: + break + datatime = time.time() + + datatime -= len(d) * byteadjust + + # Reset start time if no data for some time + if datatime - lasttime > RESTARTINTERVAL: + starttime = datatime + charcount = 0 + isnewline = 1 + msg = "\n\n======= %s (adjust=%.1fus)\n" % ( + time.asctime(time.localtime(datatime)), byteadjust * 1000000) + sys.stdout.write(msg) + logfile.write(msg) + lasttime = datatime + + # Translate unprintable chars; add timestamps + out = "" + for c in d: + if isnewline: + delta = datatime - starttime - (charcount * byteadjust) + out += "%06.3f: " % delta + isnewline = 0 + oc = ord(c) + charcount += 1 + datatime += byteadjust + if oc == 0x0d: + continue + if oc == 0x00: + out += "<00>\n" + isnewline = 1 + continue + if oc == 0x0a: + out += "\n" + isnewline = 1 + continue + if oc < 0x20 or oc >= 0x7f and oc != 0x09: + out += "<%02x>" % oc + continue + out += c + + sys.stdout.write(out) + sys.stdout.flush() + logfile.write(out) + logfile.flush() + +def main(): + usage = "%prog [options] [ []]" + opts = optparse.OptionParser(usage) + opts.add_option("-f", "--file", + action="store_false", dest="serial", default=True, + help="read from file instead of serialdevice") + opts.add_option("-n", "--no-adjust", + action="store_false", dest="adjustbaud", default=True, + help="don't adjust times by serial rate") + opts.add_option("-c", "--calibrate-read", + action="store_true", dest="calibrate_read", default=False, + help="read from serial port to calibrate it") + opts.add_option("-C", "--calibrate-write", + action="store_true", dest="calibrate_write", default=False, + help="write to serial port to calibrate it") + opts.add_option("-t", "--time", + type="float", dest="time", default=None, + help="time to write one byte on serial port (in us)") + options, args = opts.parse_args() + serialport = 0 + baud = 115200 + if len(args) > 2: + opts.error("Too many arguments") + if len(args) > 0: + serialport = args[0] + if len(args) > 1: + baud = int(args[1]) + byteadjust = float(BITSPERBYTE) / baud + if options.time is not None: + byteadjust = options.time / 1000000.0 + if not options.adjustbaud: + byteadjust = 0.0 + + if options.serial: + # Read from serial port + try: + import serial + except ImportError: + print """ +Unable to find pyserial package ( http://pyserial.sourceforge.net/ ). +On Linux machines try: yum install pyserial +Or: apt-get install python-serial +""" + sys.exit(1) + ser = serial.Serial(serialport, baud, timeout=0) + else: + # Read from a file + ser = open(serialport, 'rb') + import fcntl + import os + fcntl.fcntl(ser, fcntl.F_SETFL + , fcntl.fcntl(ser, fcntl.F_GETFL) | os.O_NONBLOCK) + + if options.calibrate_read: + calibrateserialread(ser, byteadjust) + return + if options.calibrate_write: + calibrateserialwrite(ser, byteadjust) + return + + logname = time.strftime("seriallog-%Y%m%d_%H%M%S.log") + f = open(logname, 'wb') + readserial(ser, f, byteadjust) + +if __name__ == '__main__': + main() diff --git a/bios/seabios/tools/test-gcc.sh b/bios/seabios/tools/test-gcc.sh new file mode 100755 index 0000000..935f211 --- /dev/null +++ b/bios/seabios/tools/test-gcc.sh @@ -0,0 +1,121 @@ +#!/bin/sh +# Script to test if gcc "-fwhole-program" works properly. + +mkdir -p out +TMPFILE1=out/tmp_testcompile1.c +TMPFILE1o=out/tmp_testcompile1.o +TMPFILE1_ld=out/tmp_testcompile1.lds +TMPFILE2=out/tmp_testcompile2.c +TMPFILE2o=out/tmp_testcompile2.o +TMPFILE3o=out/tmp_testcompile3.o + +# Test if ld's alignment handling is correct. This is a known problem +# with the linker that ships with Ubuntu 11.04. +cat - > $TMPFILE1 < $TMPFILE1_ld < /dev/null 2>&1 +$LD -T $TMPFILE1_ld $TMPFILE1o -o $TMPFILE2o > /dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "The version of LD on this system does not properly handle" > /dev/fd/2 + echo "alignments. As a result, this project can not be built." > /dev/fd/2 + echo "" > /dev/fd/2 + echo "The problem may be the result of this LD bug report:" > /dev/fd/2 + echo " http://sourceware.org/bugzilla/show_bug.cgi?id=12726" > /dev/fd/2 + echo "" > /dev/fd/2 + echo "Please update to a working version of binutils and retry." > /dev/fd/2 + echo -1 + exit 0 +fi + +# Test for "-fwhole-program". Older versions of gcc (pre v4.1) don't +# support the whole-program optimization - detect that. +$CC -fwhole-program -S -o /dev/null -xc /dev/null > /dev/null 2>&1 +if [ $? -ne 0 ]; then + echo " Working around no -fwhole-program" > /dev/fd/2 + echo 2 + exit 0 +fi + +# Test if "visible" variables and functions are marked global. On +# OpenSuse 10.3 "visible" variables declared with "extern" first +# aren't marked as global in the resulting assembler. On Ubuntu 7.10 +# "visible" functions aren't marked as global in the resulting +# assembler. +cat - > $TMPFILE1 < /dev/null 2>&1 +cat - > $TMPFILE2 < /dev/null 2>&1 +$CC -nostdlib -Os $TMPFILE1o $TMPFILE2o -o $TMPFILE3o > /dev/null 2>&1 +if [ $? -ne 0 ]; then + echo " Working around non-functional -fwhole-program" > /dev/fd/2 + echo 2 + exit 0 +fi + +# Test if "-combine" works. On Ubuntu 8.04 the compiler doesn't work +# correctly with combine and the "struct bregs" register due to the +# anonymous unions and structs. On Fedora Core 12 the compiler throws +# an internal compiler error when multiple files access global +# variables with debugging enabled. +cat - > $TMPFILE1 <v=0; +} +EOF +cat - > $TMPFILE2 < /dev/null 2>&1 +if [ $? -eq 0 ]; then + echo 0 +else + echo " Working around non-functional -combine" > /dev/fd/2 + echo 1 +fi + +# Also, on several compilers, -combine fails if code is emitted with a +# reference to an extern variable that is later found to be externally +# visible - the compiler does not mark those variables as global. +# This is being worked around by ordering the compile objects to avoid +# this case. + +# Also, the Ubuntu 8.04 compiler has a bug causing corruption when the +# "ebp" register is clobberred in an "asm" statement. The code has +# been modified to not clobber "ebp" - no test is available yet. + +rm -f $TMPFILE1 $TMPFILE1o $TMPFILE1_ld $TMPFILE2 $TMPFILE2o $TMPFILE3o diff --git a/bios/seabios/tools/transdump.py b/bios/seabios/tools/transdump.py new file mode 100755 index 0000000..4caaeb7 --- /dev/null +++ b/bios/seabios/tools/transdump.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python + +# This script is useful for taking the output of memdump() and +# converting it back into binary output. This can be useful, for +# example, when one wants to push that data into other tools like +# objdump or hexdump. +# +# (C) Copyright 2010 Kevin O'Connor +# +# This file may be distributed under the terms of the GNU GPLv3 license. + +import sys +import struct + +def unhex(str): + return int(str, 16) + +def parseMem(filehdl): + mem = [] + for line in filehdl: + parts = line.split(':') + if len(parts) < 2: + continue + try: + vaddr = unhex(parts[0]) + parts = parts[1].split() + mem.extend([unhex(v) for v in parts]) + except ValueError: + continue + return mem + +def printUsage(): + sys.stderr.write("Usage:\n %s \n" + % (sys.argv[0],)) + sys.exit(1) + +def main(): + if len(sys.argv) != 2: + printUsage() + filename = sys.argv[1] + if filename == '-': + filehdl = sys.stdin + else: + filehdl = open(filename, 'r') + mem = parseMem(filehdl) + for i in mem: + sys.stdout.write(struct.pack(" +// Copyright (c) 2004 Makoto Suzuki (suzu) +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "vgatables.h" // cirrus_init +#include "biosvar.h" // GET_GLOBAL +#include "util.h" // dprintf + +struct cirrus_mode_s { + /* + 0 */ + u16 mode; + u16 width; + u16 height; + u16 depth; + /* + 8 */ + u16 hidden_dac; /* 0x3c6 */ + u16 *seq; /* 0x3c4 */ + u16 *graph; /* 0x3ce */ + u16 *crtc; /* 0x3d4 */ + /* +16 */ + u8 bitsperpixel; + u8 vesacolortype; + u8 vesaredmask; + u8 vesaredpos; + u8 vesagreenmask; + u8 vesagreenpos; + u8 vesabluemask; + u8 vesabluepos; + /* +24 */ + u8 vesareservedmask; + u8 vesareservedpos; +}; + +/* VGA */ +static u16 cseq_vga[] VAR16 = {0x0007,0xffff}; +static u16 cgraph_vga[] VAR16 = {0x0009,0x000a,0x000b,0xffff}; +static u16 ccrtc_vga[] VAR16 = {0x001a,0x001b,0x001d,0xffff}; + +/* extensions */ +static u16 cgraph_svgacolor[] VAR16 = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x4005,0x0506,0x0f07,0xff08, + 0x0009,0x000a,0x000b, + 0xffff +}; +/* 640x480x8 */ +static u16 cseq_640x480x8[] VAR16 = { + 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107, + 0x580b,0x580c,0x580d,0x580e, + 0x0412,0x0013,0x2017, + 0x331b,0x331c,0x331d,0x331e, + 0xffff +}; +static u16 ccrtc_640x480x8[] VAR16 = { + 0x2c11, + 0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07, + 0x4009,0x000c,0x000d, + 0xea10,0xdf12,0x5013,0x4014,0xdf15,0x0b16,0xc317,0xff18, + 0x001a,0x221b,0x001d, + 0xffff +}; +/* 640x480x16 */ +static u16 cseq_640x480x16[] VAR16 = { + 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707, + 0x580b,0x580c,0x580d,0x580e, + 0x0412,0x0013,0x2017, + 0x331b,0x331c,0x331d,0x331e, + 0xffff +}; +static u16 ccrtc_640x480x16[] VAR16 = { + 0x2c11, + 0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07, + 0x4009,0x000c,0x000d, + 0xea10,0xdf12,0xa013,0x4014,0xdf15,0x0b16,0xc317,0xff18, + 0x001a,0x221b,0x001d, + 0xffff +}; +/* 640x480x24 */ +static u16 cseq_640x480x24[] VAR16 = { + 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507, + 0x580b,0x580c,0x580d,0x580e, + 0x0412,0x0013,0x2017, + 0x331b,0x331c,0x331d,0x331e, + 0xffff +}; +static u16 ccrtc_640x480x24[] VAR16 = { + 0x2c11, + 0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07, + 0x4009,0x000c,0x000d, + 0xea10,0xdf12,0x0013,0x4014,0xdf15,0x0b16,0xc317,0xff18, + 0x001a,0x321b,0x001d, + 0xffff +}; +/* 800x600x8 */ +static u16 cseq_800x600x8[] VAR16 = { + 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107, + 0x230b,0x230c,0x230d,0x230e, + 0x0412,0x0013,0x2017, + 0x141b,0x141c,0x141d,0x141e, + 0xffff +}; +static u16 ccrtc_800x600x8[] VAR16 = { + 0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007, + 0x6009,0x000c,0x000d, + 0x7d10,0x5712,0x6413,0x4014,0x5715,0x9816,0xc317,0xff18, + 0x001a,0x221b,0x001d, + 0xffff +}; +/* 800x600x16 */ +static u16 cseq_800x600x16[] VAR16 = { + 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707, + 0x230b,0x230c,0x230d,0x230e, + 0x0412,0x0013,0x2017, + 0x141b,0x141c,0x141d,0x141e, + 0xffff +}; +static u16 ccrtc_800x600x16[] VAR16 = { + 0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007, + 0x6009,0x000c,0x000d, + 0x7d10,0x5712,0xc813,0x4014,0x5715,0x9816,0xc317,0xff18, + 0x001a,0x221b,0x001d, + 0xffff +}; +/* 800x600x24 */ +static u16 cseq_800x600x24[] VAR16 = { + 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507, + 0x230b,0x230c,0x230d,0x230e, + 0x0412,0x0013,0x2017, + 0x141b,0x141c,0x141d,0x141e, + 0xffff +}; +static u16 ccrtc_800x600x24[] VAR16 = { + 0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007, + 0x6009,0x000c,0x000d, + 0x7d10,0x5712,0x2c13,0x4014,0x5715,0x9816,0xc317,0xff18, + 0x001a,0x321b,0x001d, + 0xffff +}; +/* 1024x768x8 */ +static u16 cseq_1024x768x8[] VAR16 = { + 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107, + 0x760b,0x760c,0x760d,0x760e, + 0x0412,0x0013,0x2017, + 0x341b,0x341c,0x341d,0x341e, + 0xffff +}; +static u16 ccrtc_1024x768x8[] VAR16 = { + 0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507, + 0x6009,0x000c,0x000d, + 0x0310,0xff12,0x8013,0x4014,0xff15,0x2416,0xc317,0xff18, + 0x001a,0x221b,0x001d, + 0xffff +}; +/* 1024x768x16 */ +static u16 cseq_1024x768x16[] VAR16 = { + 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707, + 0x760b,0x760c,0x760d,0x760e, + 0x0412,0x0013,0x2017, + 0x341b,0x341c,0x341d,0x341e, + 0xffff +}; +static u16 ccrtc_1024x768x16[] VAR16 = { + 0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507, + 0x6009,0x000c,0x000d, + 0x0310,0xff12,0x0013,0x4014,0xff15,0x2416,0xc317,0xff18, + 0x001a,0x321b,0x001d, + 0xffff +}; +/* 1024x768x24 */ +static u16 cseq_1024x768x24[] VAR16 = { + 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507, + 0x760b,0x760c,0x760d,0x760e, + 0x0412,0x0013,0x2017, + 0x341b,0x341c,0x341d,0x341e, + 0xffff +}; +static u16 ccrtc_1024x768x24[] VAR16 = { + 0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507, + 0x6009,0x000c,0x000d, + 0x0310,0xff12,0x8013,0x4014,0xff15,0x2416,0xc317,0xff18, + 0x001a,0x321b,0x001d, + 0xffff +}; +/* 1280x1024x8 */ +static u16 cseq_1280x1024x8[] VAR16 = { + 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107, + 0x760b,0x760c,0x760d,0x760e, + 0x0412,0x0013,0x2017, + 0x341b,0x341c,0x341d,0x341e, + 0xffff +}; +static u16 ccrtc_1280x1024x8[] VAR16 = { + 0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707, + 0x6009,0x000c,0x000d, + 0x0310,0xff12,0xa013,0x4014,0xff15,0x2416,0xc317,0xff18, + 0x001a,0x221b,0x001d, + 0xffff +}; +/* 1280x1024x16 */ +static u16 cseq_1280x1024x16[] VAR16 = { + 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707, + 0x760b,0x760c,0x760d,0x760e, + 0x0412,0x0013,0x2017, + 0x341b,0x341c,0x341d,0x341e, + 0xffff +}; +static u16 ccrtc_1280x1024x16[] VAR16 = { + 0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707, + 0x6009,0x000c,0x000d, + 0x0310,0xff12,0x4013,0x4014,0xff15,0x2416,0xc317,0xff18, + 0x001a,0x321b,0x001d, + 0xffff +}; + +/* 1600x1200x8 */ +static u16 cseq_1600x1200x8[] VAR16 = { + 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107, + 0x760b,0x760c,0x760d,0x760e, + 0x0412,0x0013,0x2017, + 0x341b,0x341c,0x341d,0x341e, + 0xffff +}; +static u16 ccrtc_1600x1200x8[] VAR16 = { + 0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707, + 0x6009,0x000c,0x000d, + 0x0310,0xff12,0xa013,0x4014,0xff15,0x2416,0xc317,0xff18, + 0x001a,0x221b,0x001d, + 0xffff +}; + +static struct cirrus_mode_s cirrus_modes[] VAR16 = { + {0x5f,640,480,8,0x00, + cseq_640x480x8,cgraph_svgacolor,ccrtc_640x480x8,8, + 4,0,0,0,0,0,0,0,0}, + {0x64,640,480,16,0xe1, + cseq_640x480x16,cgraph_svgacolor,ccrtc_640x480x16,16, + 6,5,11,6,5,5,0,0,0}, + {0x66,640,480,15,0xf0, + cseq_640x480x16,cgraph_svgacolor,ccrtc_640x480x16,16, + 6,5,10,5,5,5,0,1,15}, + {0x71,640,480,24,0xe5, + cseq_640x480x24,cgraph_svgacolor,ccrtc_640x480x24,24, + 6,8,16,8,8,8,0,0,0}, + + {0x5c,800,600,8,0x00, + cseq_800x600x8,cgraph_svgacolor,ccrtc_800x600x8,8, + 4,0,0,0,0,0,0,0,0}, + {0x65,800,600,16,0xe1, + cseq_800x600x16,cgraph_svgacolor,ccrtc_800x600x16,16, + 6,5,11,6,5,5,0,0,0}, + {0x67,800,600,15,0xf0, + cseq_800x600x16,cgraph_svgacolor,ccrtc_800x600x16,16, + 6,5,10,5,5,5,0,1,15}, + + {0x60,1024,768,8,0x00, + cseq_1024x768x8,cgraph_svgacolor,ccrtc_1024x768x8,8, + 4,0,0,0,0,0,0,0,0}, + {0x74,1024,768,16,0xe1, + cseq_1024x768x16,cgraph_svgacolor,ccrtc_1024x768x16,16, + 6,5,11,6,5,5,0,0,0}, + {0x68,1024,768,15,0xf0, + cseq_1024x768x16,cgraph_svgacolor,ccrtc_1024x768x16,16, + 6,5,10,5,5,5,0,1,15}, + + {0x78,800,600,24,0xe5, + cseq_800x600x24,cgraph_svgacolor,ccrtc_800x600x24,24, + 6,8,16,8,8,8,0,0,0}, + {0x79,1024,768,24,0xe5, + cseq_1024x768x24,cgraph_svgacolor,ccrtc_1024x768x24,24, + 6,8,16,8,8,8,0,0,0}, + + {0x6d,1280,1024,8,0x00, + cseq_1280x1024x8,cgraph_svgacolor,ccrtc_1280x1024x8,8, + 4,0,0,0,0,0,0,0,0}, + {0x69,1280,1024,15,0xf0, + cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16, + 6,5,10,5,5,5,0,1,15}, + {0x75,1280,1024,16,0xe1, + cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16, + 6,5,11,6,5,5,0,0,0}, + + {0x7b,1600,1200,8,0x00, + cseq_1600x1200x8,cgraph_svgacolor,ccrtc_1600x1200x8,8, + 4,0,0,0,0,0,0,0,0}, + + {0xfe,0,0,0,0,cseq_vga,cgraph_vga,ccrtc_vga,0, + 0xff,0,0,0,0,0,0,0,0}, +}; + +static struct cirrus_mode_s * +cirrus_get_modeentry(u8 mode) +{ + struct cirrus_mode_s *table_g = cirrus_modes; + while (table_g < &cirrus_modes[ARRAY_SIZE(cirrus_modes)]) { + u16 tmode = GET_GLOBAL(table_g->mode); + if (tmode == mode) + return table_g; + table_g++; + } + return NULL; +} + +static void +cirrus_switch_mode_setregs(u16 *data, u16 port) +{ + for (;;) { + u16 val = GET_GLOBAL(*data); + if (val == 0xffff) + return; + outw(val, port); + data++; + } +} + +static u16 +cirrus_get_crtc(void) +{ + if (inb(VGAREG_READ_MISC_OUTPUT) & 1) + return VGAREG_VGA_CRTC_ADDRESS; + return VGAREG_MDA_CRTC_ADDRESS; +} + +static void +cirrus_switch_mode(struct cirrus_mode_s *table) +{ + // Unlock cirrus special + outw(0x1206, VGAREG_SEQU_ADDRESS); + cirrus_switch_mode_setregs(GET_GLOBAL(table->seq), VGAREG_SEQU_ADDRESS); + cirrus_switch_mode_setregs(GET_GLOBAL(table->graph), VGAREG_GRDC_ADDRESS); + cirrus_switch_mode_setregs(GET_GLOBAL(table->crtc), cirrus_get_crtc()); + + outb(0x00, VGAREG_PEL_MASK); + inb(VGAREG_PEL_MASK); + inb(VGAREG_PEL_MASK); + inb(VGAREG_PEL_MASK); + inb(VGAREG_PEL_MASK); + outb(GET_GLOBAL(table->hidden_dac), VGAREG_PEL_MASK); + outb(0xff, VGAREG_PEL_MASK); + + u8 vesacolortype = GET_GLOBAL(table->vesacolortype); + u8 v = vgahw_get_single_palette_reg(0x10) & 0xfe; + if (vesacolortype == 3) + v |= 0x41; + else if (vesacolortype) + v |= 0x01; + vgahw_set_single_palette_reg(0x10, v); +} + +void +cirrus_set_video_mode(u8 mode) +{ + dprintf(1, "cirrus mode %d\n", mode); + SET_BDA(vbe_mode, 0); + struct cirrus_mode_s *table_g = cirrus_get_modeentry(mode & 0x7f); + if (table_g) { + //XXX - cirrus_set_video_mode_extended(table); + return; + } + table_g = cirrus_get_modeentry(0xfe); + cirrus_switch_mode(table_g); + dprintf(1, "cirrus mode switch regular\n"); +} + +static int +cirrus_check(void) +{ + outw(0x9206, VGAREG_SEQU_ADDRESS); + return inb(VGAREG_SEQU_DATA) == 0x12; +} + +void +cirrus_init(void) +{ + dprintf(1, "cirrus init\n"); + if (! cirrus_check()) + return; + dprintf(1, "cirrus init 2\n"); + + // memory setup + outb(0x0f, VGAREG_SEQU_ADDRESS); + u8 v = inb(VGAREG_SEQU_DATA); + outb(((v & 0x18) << 8) | 0x0a, VGAREG_SEQU_ADDRESS); + // set vga mode + outw(0x0007, VGAREG_SEQU_ADDRESS); + // reset bitblt + outw(0x0431, VGAREG_GRDC_ADDRESS); + outw(0x0031, VGAREG_GRDC_ADDRESS); +} diff --git a/bios/seabios/vgasrc/vga.c b/bios/seabios/vgasrc/vga.c new file mode 100644 index 0000000..d734e23 --- /dev/null +++ b/bios/seabios/vgasrc/vga.c @@ -0,0 +1,1387 @@ +// VGA bios implementation +// +// Copyright (C) 2009 Kevin O'Connor +// Copyright (C) 2001-2008 the LGPL VGABios developers Team +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + + +// TODO: +// * review correctness of converted asm by comparing with RBIL +// +// * convert vbe/clext code + +#include "bregs.h" // struct bregs +#include "biosvar.h" // GET_BDA +#include "util.h" // memset +#include "vgatables.h" // find_vga_entry + +// XXX +#define CONFIG_VBE 0 +#define CONFIG_CIRRUS 0 + +// XXX +#define DEBUG_VGA_POST 1 +#define DEBUG_VGA_10 3 + +#define SET_VGA(var, val) SET_FARVAR(get_global_seg(), (var), (val)) + + +/**************************************************************** + * Helper functions + ****************************************************************/ + +static inline void +call16_vgaint(u32 eax, u32 ebx) +{ + asm volatile( + "int $0x10\n" + "cli\n" + "cld" + : + : "a"(eax), "b"(ebx) + : "cc", "memory"); +} + +static void +perform_gray_scale_summing(u16 start, u16 count) +{ + vgahw_screen_disable(); + int i; + for (i = start; i < start+count; i++) { + u8 rgb[3]; + vgahw_get_dac_regs(GET_SEG(SS), rgb, i, 1); + + // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue ) + u16 intensity = ((77 * rgb[0] + 151 * rgb[1] + 28 * rgb[2]) + 0x80) >> 8; + if (intensity > 0x3f) + intensity = 0x3f; + + vgahw_set_dac_regs(GET_SEG(SS), rgb, i, 1); + } + vgahw_screen_enable(); +} + +static void +set_cursor_shape(u8 start, u8 end) +{ + start &= 0x3f; + end &= 0x1f; + + u16 curs = (start << 8) + end; + SET_BDA(cursor_type, curs); + + u8 modeset_ctl = GET_BDA(modeset_ctl); + u16 cheight = GET_BDA(char_height); + if ((modeset_ctl & 0x01) && (cheight > 8) && (end < 8) && (start < 0x20)) { + if (end != (start + 1)) + start = ((start + 1) * cheight / 8) - 1; + else + start = ((end + 1) * cheight / 8) - 2; + end = ((end + 1) * cheight / 8) - 1; + } + vgahw_set_cursor_shape(start, end); +} + +static u16 +get_cursor_shape(u8 page) +{ + if (page > 7) + return 0; + // FIXME should handle VGA 14/16 lines + return GET_BDA(cursor_type); +} + +static void +set_cursor_pos(struct cursorpos cp) +{ + // Should not happen... + if (cp.page > 7) + return; + + // Bios cursor pos + SET_BDA(cursor_pos[cp.page], (cp.y << 8) | cp.x); + + // Set the hardware cursor + u8 current = GET_BDA(video_page); + if (cp.page != current) + return; + + // Get the dimensions + u16 nbcols = GET_BDA(video_cols); + u16 nbrows = GET_BDA(video_rows) + 1; + + // Calculate the address knowing nbcols nbrows and page num + u16 address = (SCREEN_IO_START(nbcols, nbrows, cp.page) + + cp.x + cp.y * nbcols); + + vgahw_set_cursor_pos(address); +} + +static struct cursorpos +get_cursor_pos(u8 page) +{ + if (page == 0xff) + // special case - use current page + page = GET_BDA(video_page); + if (page > 7) { + struct cursorpos cp = { 0, 0, 0xfe }; + return cp; + } + // FIXME should handle VGA 14/16 lines + u16 xy = GET_BDA(cursor_pos[page]); + struct cursorpos cp = {xy, xy>>8, page}; + return cp; +} + +static void +set_active_page(u8 page) +{ + if (page > 7) + return; + + // Get the mode + struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode)); + if (!vmode_g) + return; + + // Get pos curs pos for the right page + struct cursorpos cp = get_cursor_pos(page); + + u16 address; + if (GET_GLOBAL(vmode_g->memmodel) & TEXT) { + // Get the dimensions + u16 nbcols = GET_BDA(video_cols); + u16 nbrows = GET_BDA(video_rows) + 1; + + // Calculate the address knowing nbcols nbrows and page num + address = SCREEN_MEM_START(nbcols, nbrows, page); + SET_BDA(video_pagestart, address); + + // Start address + address = SCREEN_IO_START(nbcols, nbrows, page); + } else { + struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam); + address = page * GET_GLOBAL(vparam_g->slength); + } + + vgahw_set_active_page(address); + + // And change the BIOS page + SET_BDA(video_page, page); + + dprintf(1, "Set active page %02x address %04x\n", page, address); + + // Display the cursor, now the page is active + set_cursor_pos(cp); +} + +static void +set_scan_lines(u8 lines) +{ + vgahw_set_scan_lines(lines); + if (lines == 8) + set_cursor_shape(0x06, 0x07); + else + set_cursor_shape(lines - 4, lines - 3); + SET_BDA(char_height, lines); + u16 vde = vgahw_get_vde(); + u8 rows = vde / lines; + SET_BDA(video_rows, rows - 1); + u16 cols = GET_BDA(video_cols); + SET_BDA(video_pagesize, rows * cols * 2); +} + + +/**************************************************************** + * Character writing + ****************************************************************/ + +// Scroll the screen one line. This function is designed to be called +// tail-recursive to reduce stack usage. +static void noinline +scroll_one(u16 nbrows, u16 nbcols, u8 page) +{ + struct cursorpos ul = {0, 0, page}; + struct cursorpos lr = {nbcols-1, nbrows-1, page}; + vgafb_scroll(1, -1, ul, lr); +} + +// Write a character to the screen at a given position. Implement +// special characters and scroll the screen if necessary. +static void +write_teletype(struct cursorpos *pcp, struct carattr ca) +{ + struct cursorpos cp = *pcp; + + // Get the dimensions + u16 nbrows = GET_BDA(video_rows) + 1; + u16 nbcols = GET_BDA(video_cols); + + switch (ca.car) { + case 7: + //FIXME should beep + break; + case 8: + if (cp.x > 0) + cp.x--; + break; + case '\r': + cp.x = 0; + break; + case '\n': + cp.y++; + break; + case '\t': + do { + struct carattr dummyca = {' ', ca.attr, ca.use_attr}; + vgafb_write_char(cp, dummyca); + cp.x++; + } while (cp.x < nbcols && cp.x % 8); + break; + default: + vgafb_write_char(cp, ca); + cp.x++; + } + + // Do we need to wrap ? + if (cp.x == nbcols) { + cp.x = 0; + cp.y++; + } + // Do we need to scroll ? + if (cp.y < nbrows) { + *pcp = cp; + return; + } + // Scroll screen + cp.y--; + *pcp = cp; + scroll_one(nbrows, nbcols, cp.page); +} + +// Write out a buffer of alternating characters and attributes. +static void +write_attr_string(struct cursorpos *pcp, u16 count, u16 seg, u8 *offset_far) +{ + while (count--) { + u8 car = GET_FARVAR(seg, *offset_far); + offset_far++; + u8 attr = GET_FARVAR(seg, *offset_far); + offset_far++; + + struct carattr ca = {car, attr, 1}; + write_teletype(pcp, ca); + } +} + +// Write out a buffer of characters. +static void +write_string(struct cursorpos *pcp, u8 attr, u16 count, u16 seg, u8 *offset_far) +{ + while (count--) { + u8 car = GET_FARVAR(seg, *offset_far); + offset_far++; + + struct carattr ca = {car, attr, 1}; + write_teletype(pcp, ca); + } +} + + +/**************************************************************** + * Save and restore bda state + ****************************************************************/ + +static void +save_bda_state(u16 seg, struct saveBDAstate *info) +{ + SET_FARVAR(seg, info->video_mode, GET_BDA(video_mode)); + SET_FARVAR(seg, info->video_cols, GET_BDA(video_cols)); + SET_FARVAR(seg, info->video_pagesize, GET_BDA(video_pagesize)); + SET_FARVAR(seg, info->crtc_address, GET_BDA(crtc_address)); + SET_FARVAR(seg, info->video_rows, GET_BDA(video_rows)); + SET_FARVAR(seg, info->char_height, GET_BDA(char_height)); + SET_FARVAR(seg, info->video_ctl, GET_BDA(video_ctl)); + SET_FARVAR(seg, info->video_switches, GET_BDA(video_switches)); + SET_FARVAR(seg, info->modeset_ctl, GET_BDA(modeset_ctl)); + SET_FARVAR(seg, info->cursor_type, GET_BDA(cursor_type)); + u16 i; + for (i=0; i<8; i++) + SET_FARVAR(seg, info->cursor_pos[i], GET_BDA(cursor_pos[i])); + SET_FARVAR(seg, info->video_pagestart, GET_BDA(video_pagestart)); + SET_FARVAR(seg, info->video_page, GET_BDA(video_page)); + /* current font */ + SET_FARVAR(seg, info->font0, GET_IVT(0x1f)); + SET_FARVAR(seg, info->font1, GET_IVT(0x43)); +} + +static void +restore_bda_state(u16 seg, struct saveBDAstate *info) +{ + SET_BDA(video_mode, GET_FARVAR(seg, info->video_mode)); + SET_BDA(video_cols, GET_FARVAR(seg, info->video_cols)); + SET_BDA(video_pagesize, GET_FARVAR(seg, info->video_pagesize)); + SET_BDA(crtc_address, GET_FARVAR(seg, info->crtc_address)); + SET_BDA(video_rows, GET_FARVAR(seg, info->video_rows)); + SET_BDA(char_height, GET_FARVAR(seg, info->char_height)); + SET_BDA(video_ctl, GET_FARVAR(seg, info->video_ctl)); + SET_BDA(video_switches, GET_FARVAR(seg, info->video_switches)); + SET_BDA(modeset_ctl, GET_FARVAR(seg, info->modeset_ctl)); + SET_BDA(cursor_type, GET_FARVAR(seg, info->cursor_type)); + u16 i; + for (i = 0; i < 8; i++) + SET_BDA(cursor_pos[i], GET_FARVAR(seg, info->cursor_pos[i])); + SET_BDA(video_pagestart, GET_FARVAR(seg, info->video_pagestart)); + SET_BDA(video_page, GET_FARVAR(seg, info->video_page)); + /* current font */ + SET_IVT(0x1f, GET_FARVAR(seg, info->font0)); + SET_IVT(0x43, GET_FARVAR(seg, info->font1)); +} + + +/**************************************************************** + * VGA int 10 handler + ****************************************************************/ + +// set video mode +static void +handle_1000(struct bregs *regs) +{ + u8 noclearmem = regs->al & 0x80; + u8 mode = regs->al & 0x7f; + + // Set regs->al + if (mode > 7) + regs->al = 0x20; + else if (mode == 6) + regs->al = 0x3f; + else + regs->al = 0x30; + + if (CONFIG_CIRRUS) + cirrus_set_video_mode(mode); + + if (CONFIG_VBE) + if (vbe_has_vbe_display()) + dispi_set_enable(VBE_DISPI_DISABLED); + + // find the entry in the video modes + struct vgamode_s *vmode_g = find_vga_entry(mode); + dprintf(1, "mode search %02x found %p\n", mode, vmode_g); + if (!vmode_g) + return; + + // Read the bios mode set control + u8 modeset_ctl = GET_BDA(modeset_ctl); + + // Then we know the number of lines +// FIXME + + // if palette loading (bit 3 of modeset ctl = 0) + if ((modeset_ctl & 0x08) == 0) { // Set the PEL mask + vgahw_set_pel_mask(GET_GLOBAL(vmode_g->pelmask)); + + // From which palette + u8 *palette_g = GET_GLOBAL(vmode_g->dac); + u16 palsize = GET_GLOBAL(vmode_g->dacsize) / 3; + + // Always 256*3 values + vgahw_set_dac_regs(get_global_seg(), palette_g, 0, palsize); + u16 i; + for (i = palsize; i < 0x0100; i++) { + static u8 rgb[3] VAR16; + vgahw_set_dac_regs(get_global_seg(), rgb, i, 1); + } + + if ((modeset_ctl & 0x02) == 0x02) + perform_gray_scale_summing(0x00, 0x100); + } + + struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam); + vgahw_set_mode(vparam_g); + + if (noclearmem == 0x00) + clear_screen(vmode_g); + + // Set CRTC address VGA or MDA + u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS; + if (GET_GLOBAL(vmode_g->memmodel) == MTEXT) + crtc_addr = VGAREG_MDA_CRTC_ADDRESS; + + // Set the BIOS mem + u16 cheight = GET_GLOBAL(vparam_g->cheight); + SET_BDA(video_mode, mode); + SET_BDA(video_cols, GET_GLOBAL(vparam_g->twidth)); + SET_BDA(video_pagesize, GET_GLOBAL(vparam_g->slength)); + SET_BDA(crtc_address, crtc_addr); + SET_BDA(video_rows, GET_GLOBAL(vparam_g->theightm1)); + SET_BDA(char_height, cheight); + SET_BDA(video_ctl, (0x60 | noclearmem)); + SET_BDA(video_switches, 0xF9); + SET_BDA(modeset_ctl, GET_BDA(modeset_ctl) & 0x7f); + + // FIXME We nearly have the good tables. to be reworked + SET_BDA(dcc_index, 0x08); // 8 is VGA should be ok for now + SET_BDA(video_savetable + , SEGOFF(get_global_seg(), (u32)video_save_pointer_table)); + + // FIXME + SET_BDA(video_msr, 0x00); // Unavailable on vanilla vga, but... + SET_BDA(video_pal, 0x00); // Unavailable on vanilla vga, but... + + // Set cursor shape + if (GET_GLOBAL(vmode_g->memmodel) & TEXT) + set_cursor_shape(0x06, 0x07); + // Set cursor pos for page 0..7 + int i; + for (i = 0; i < 8; i++) { + struct cursorpos cp = {0, 0, i}; + set_cursor_pos(cp); + } + + // Set active page 0 + set_active_page(0x00); + + // Write the fonts in memory + if (GET_GLOBAL(vmode_g->memmodel) & TEXT) { + call16_vgaint(0x1104, 0); + call16_vgaint(0x1103, 0); + } + // Set the ints 0x1F and 0x43 + SET_IVT(0x1f, SEGOFF(get_global_seg(), (u32)&vgafont8[128 * 8])); + + switch (cheight) { + case 8: + SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont8)); + break; + case 14: + SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont14)); + break; + case 16: + SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont16)); + break; + } +} + +static void +handle_1001(struct bregs *regs) +{ + set_cursor_shape(regs->ch, regs->cl); +} + +static void +handle_1002(struct bregs *regs) +{ + struct cursorpos cp = {regs->dl, regs->dh, regs->bh}; + set_cursor_pos(cp); +} + +static void +handle_1003(struct bregs *regs) +{ + regs->cx = get_cursor_shape(regs->bh); + struct cursorpos cp = get_cursor_pos(regs->bh); + regs->dl = cp.x; + regs->dh = cp.y; +} + +// Read light pen pos (unimplemented) +static void +handle_1004(struct bregs *regs) +{ + debug_stub(regs); + regs->ax = regs->bx = regs->cx = regs->dx = 0; +} + +static void +handle_1005(struct bregs *regs) +{ + set_active_page(regs->al); +} + +static void +verify_scroll(struct bregs *regs, int dir) +{ + u8 page = GET_BDA(video_page); + struct cursorpos ul = {regs->cl, regs->ch, page}; + struct cursorpos lr = {regs->dl, regs->dh, page}; + + u16 nbrows = GET_BDA(video_rows) + 1; + if (lr.y >= nbrows) + lr.y = nbrows - 1; + u16 nbcols = GET_BDA(video_cols); + if (lr.x >= nbcols) + lr.x = nbcols - 1; + + if (ul.x > lr.x || ul.y > lr.y) + return; + + u16 nblines = regs->al; + if (!nblines || nblines > lr.y - ul.y + 1) + nblines = lr.y - ul.y + 1; + + vgafb_scroll(dir * nblines, regs->bh, ul, lr); +} + +static void +handle_1006(struct bregs *regs) +{ + verify_scroll(regs, 1); +} + +static void +handle_1007(struct bregs *regs) +{ + verify_scroll(regs, -1); +} + +static void +handle_1008(struct bregs *regs) +{ + struct carattr ca = vgafb_read_char(get_cursor_pos(regs->bh)); + regs->al = ca.car; + regs->ah = ca.attr; +} + +static void noinline +write_chars(u8 page, struct carattr ca, u16 count) +{ + struct cursorpos cp = get_cursor_pos(page); + while (count--) { + vgafb_write_char(cp, ca); + cp.x++; + } +} + +static void +handle_1009(struct bregs *regs) +{ + struct carattr ca = {regs->al, regs->bl, 1}; + write_chars(regs->bh, ca, regs->cx); +} + +static void +handle_100a(struct bregs *regs) +{ + struct carattr ca = {regs->al, regs->bl, 0}; + write_chars(regs->bh, ca, regs->cx); +} + + +static void +handle_100b00(struct bregs *regs) +{ + vgahw_set_border_color(regs->bl); +} + +static void +handle_100b01(struct bregs *regs) +{ + vgahw_set_palette(regs->bl); +} + +static void +handle_100bXX(struct bregs *regs) +{ + debug_stub(regs); +} + +static void +handle_100b(struct bregs *regs) +{ + switch (regs->bh) { + case 0x00: handle_100b00(regs); break; + case 0x01: handle_100b01(regs); break; + default: handle_100bXX(regs); break; + } +} + + +static void +handle_100c(struct bregs *regs) +{ + // XXX - page (regs->bh) is unused + vgafb_write_pixel(regs->al, regs->cx, regs->dx); +} + +static void +handle_100d(struct bregs *regs) +{ + // XXX - page (regs->bh) is unused + regs->al = vgafb_read_pixel(regs->cx, regs->dx); +} + +static void noinline +handle_100e(struct bregs *regs) +{ + // Ralf Brown Interrupt list is WRONG on bh(page) + // We do output only on the current page ! + struct carattr ca = {regs->al, regs->bl, 0}; + struct cursorpos cp = get_cursor_pos(0xff); + write_teletype(&cp, ca); + set_cursor_pos(cp); +} + +static void +handle_100f(struct bregs *regs) +{ + regs->bh = GET_BDA(video_page); + regs->al = GET_BDA(video_mode) | (GET_BDA(video_ctl) & 0x80); + regs->ah = GET_BDA(video_cols); +} + + +static void +handle_101000(struct bregs *regs) +{ + if (regs->bl > 0x14) + return; + vgahw_set_single_palette_reg(regs->bl, regs->bh); +} + +static void +handle_101001(struct bregs *regs) +{ + vgahw_set_overscan_border_color(regs->bh); +} + +static void +handle_101002(struct bregs *regs) +{ + vgahw_set_all_palette_reg(regs->es, (u8*)(regs->dx + 0)); +} + +static void +handle_101003(struct bregs *regs) +{ + vgahw_toggle_intensity(regs->bl); +} + +static void +handle_101007(struct bregs *regs) +{ + if (regs->bl > 0x14) + return; + regs->bh = vgahw_get_single_palette_reg(regs->bl); +} + +static void +handle_101008(struct bregs *regs) +{ + regs->bh = vgahw_get_overscan_border_color(); +} + +static void +handle_101009(struct bregs *regs) +{ + vgahw_get_all_palette_reg(regs->es, (u8*)(regs->dx + 0)); +} + +static void noinline +handle_101010(struct bregs *regs) +{ + u8 rgb[3] = {regs->dh, regs->ch, regs->cl}; + vgahw_set_dac_regs(GET_SEG(SS), rgb, regs->bx, 1); +} + +static void +handle_101012(struct bregs *regs) +{ + vgahw_set_dac_regs(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx); +} + +static void +handle_101013(struct bregs *regs) +{ + vgahw_select_video_dac_color_page(regs->bl, regs->bh); +} + +static void noinline +handle_101015(struct bregs *regs) +{ + u8 rgb[3]; + vgahw_get_dac_regs(GET_SEG(SS), rgb, regs->bx, 1); + regs->dh = rgb[0]; + regs->ch = rgb[1]; + regs->cl = rgb[2]; +} + +static void +handle_101017(struct bregs *regs) +{ + vgahw_get_dac_regs(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx); +} + +static void +handle_101018(struct bregs *regs) +{ + vgahw_set_pel_mask(regs->bl); +} + +static void +handle_101019(struct bregs *regs) +{ + regs->bl = vgahw_get_pel_mask(); +} + +static void +handle_10101a(struct bregs *regs) +{ + vgahw_read_video_dac_state(®s->bl, ®s->bh); +} + +static void +handle_10101b(struct bregs *regs) +{ + perform_gray_scale_summing(regs->bx, regs->cx); +} + +static void +handle_1010XX(struct bregs *regs) +{ + debug_stub(regs); +} + +static void +handle_1010(struct bregs *regs) +{ + switch (regs->al) { + case 0x00: handle_101000(regs); break; + case 0x01: handle_101001(regs); break; + case 0x02: handle_101002(regs); break; + case 0x03: handle_101003(regs); break; + case 0x07: handle_101007(regs); break; + case 0x08: handle_101008(regs); break; + case 0x09: handle_101009(regs); break; + case 0x10: handle_101010(regs); break; + case 0x12: handle_101012(regs); break; + case 0x13: handle_101013(regs); break; + case 0x15: handle_101015(regs); break; + case 0x17: handle_101017(regs); break; + case 0x18: handle_101018(regs); break; + case 0x19: handle_101019(regs); break; + case 0x1a: handle_10101a(regs); break; + case 0x1b: handle_10101b(regs); break; + default: handle_1010XX(regs); break; + } +} + + +static void +handle_101100(struct bregs *regs) +{ + vgafb_load_font(regs->es, (void*)(regs->bp+0), regs->cx + , regs->dx, regs->bl, regs->bh); +} + +static void +handle_101101(struct bregs *regs) +{ + vgafb_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14); +} + +static void +handle_101102(struct bregs *regs) +{ + vgafb_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8); +} + +static void +handle_101103(struct bregs *regs) +{ + vgahw_set_text_block_specifier(regs->bl); +} + +static void +handle_101104(struct bregs *regs) +{ + vgafb_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16); +} + +static void +handle_101110(struct bregs *regs) +{ + vgafb_load_font(regs->es, (void*)(regs->bp+0), regs->cx + , regs->dx, regs->bl, regs->bh); + set_scan_lines(regs->bh); +} + +static void +handle_101111(struct bregs *regs) +{ + vgafb_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14); + set_scan_lines(14); +} + +static void +handle_101112(struct bregs *regs) +{ + vgafb_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8); + set_scan_lines(8); +} + +static void +handle_101114(struct bregs *regs) +{ + vgafb_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16); + set_scan_lines(16); +} + +static void +handle_101130(struct bregs *regs) +{ + switch (regs->bh) { + case 0x00: { + struct segoff_s so = GET_IVT(0x1f); + regs->es = so.seg; + regs->bp = so.offset; + break; + } + case 0x01: { + struct segoff_s so = GET_IVT(0x43); + regs->es = so.seg; + regs->bp = so.offset; + break; + } + case 0x02: + regs->es = get_global_seg(); + regs->bp = (u32)vgafont14; + break; + case 0x03: + regs->es = get_global_seg(); + regs->bp = (u32)vgafont8; + break; + case 0x04: + regs->es = get_global_seg(); + regs->bp = (u32)vgafont8 + 128 * 8; + break; + case 0x05: + regs->es = get_global_seg(); + regs->bp = (u32)vgafont14alt; + break; + case 0x06: + regs->es = get_global_seg(); + regs->bp = (u32)vgafont16; + break; + case 0x07: + regs->es = get_global_seg(); + regs->bp = (u32)vgafont16alt; + break; + default: + dprintf(1, "Get font info BH(%02x) was discarded\n", regs->bh); + return; + } + // Set byte/char of on screen font + regs->cx = GET_BDA(char_height) & 0xff; + + // Set Highest char row + regs->dx = GET_BDA(video_rows); +} + +static void +handle_1011XX(struct bregs *regs) +{ + debug_stub(regs); +} + +static void +handle_1011(struct bregs *regs) +{ + switch (regs->al) { + case 0x00: handle_101100(regs); break; + case 0x01: handle_101101(regs); break; + case 0x02: handle_101102(regs); break; + case 0x03: handle_101103(regs); break; + case 0x04: handle_101104(regs); break; + case 0x10: handle_101110(regs); break; + case 0x11: handle_101111(regs); break; + case 0x12: handle_101112(regs); break; + case 0x14: handle_101114(regs); break; + case 0x30: handle_101130(regs); break; + default: handle_1011XX(regs); break; + } +} + + +static void +handle_101210(struct bregs *regs) +{ + u16 crtc_addr = GET_BDA(crtc_address); + if (crtc_addr == VGAREG_MDA_CRTC_ADDRESS) + regs->bx = 0x0103; + else + regs->bx = 0x0003; + regs->cx = GET_BDA(video_switches) & 0x0f; +} + +static void +handle_101230(struct bregs *regs) +{ + u8 mctl = GET_BDA(modeset_ctl); + u8 vswt = GET_BDA(video_switches); + switch (regs->al) { + case 0x00: + // 200 lines + mctl = (mctl & ~0x10) | 0x80; + vswt = (vswt & ~0x0f) | 0x08; + break; + case 0x01: + // 350 lines + mctl &= ~0x90; + vswt = (vswt & ~0x0f) | 0x09; + break; + case 0x02: + // 400 lines + mctl = (mctl & ~0x80) | 0x10; + vswt = (vswt & ~0x0f) | 0x09; + break; + default: + dprintf(1, "Select vert res (%02x) was discarded\n", regs->al); + break; + } + SET_BDA(modeset_ctl, mctl); + SET_BDA(video_switches, vswt); + regs->al = 0x12; +} + +static void +handle_101231(struct bregs *regs) +{ + u8 v = (regs->al & 0x01) << 3; + u8 mctl = GET_BDA(video_ctl) & ~0x08; + SET_BDA(video_ctl, mctl | v); + regs->al = 0x12; +} + +static void +handle_101232(struct bregs *regs) +{ + vgahw_enable_video_addressing(regs->al); + regs->al = 0x12; +} + +static void +handle_101233(struct bregs *regs) +{ + u8 v = ((regs->al << 1) & 0x02) ^ 0x02; + u8 v2 = GET_BDA(modeset_ctl) & ~0x02; + SET_BDA(modeset_ctl, v | v2); + regs->al = 0x12; +} + +static void +handle_101234(struct bregs *regs) +{ + u8 v = (regs->al & 0x01) ^ 0x01; + u8 v2 = GET_BDA(modeset_ctl) & ~0x01; + SET_BDA(modeset_ctl, v | v2); + regs->al = 0x12; +} + +static void +handle_101235(struct bregs *regs) +{ + debug_stub(regs); + regs->al = 0x12; +} + +static void +handle_101236(struct bregs *regs) +{ + debug_stub(regs); + regs->al = 0x12; +} + +static void +handle_1012XX(struct bregs *regs) +{ + debug_stub(regs); +} + +static void +handle_1012(struct bregs *regs) +{ + switch (regs->bl) { + case 0x10: handle_101210(regs); break; + case 0x30: handle_101230(regs); break; + case 0x31: handle_101231(regs); break; + case 0x32: handle_101232(regs); break; + case 0x33: handle_101233(regs); break; + case 0x34: handle_101234(regs); break; + case 0x35: handle_101235(regs); break; + case 0x36: handle_101236(regs); break; + default: handle_1012XX(regs); break; + } + + // XXX - cirrus has 1280, 1281, 1282, 1285, 129a, 12a0, 12a1, 12a2, 12ae +} + + +// Write string +static void noinline +handle_1013(struct bregs *regs) +{ + struct cursorpos cp = {regs->dl, regs->dh, regs->bh}; + // if row=0xff special case : use current cursor position + if (cp.y == 0xff) + cp = get_cursor_pos(cp.page); + u8 flag = regs->al; + if (flag & 2) + write_attr_string(&cp, regs->cx, regs->es, (void*)(regs->bp + 0)); + else + write_string(&cp, regs->bl, regs->cx, regs->es, (void*)(regs->bp + 0)); + + if (flag & 1) + set_cursor_pos(cp); +} + + +static void +handle_101a00(struct bregs *regs) +{ + regs->bx = GET_BDA(dcc_index); + regs->al = 0x1a; +} + +static void +handle_101a01(struct bregs *regs) +{ + SET_BDA(dcc_index, regs->bl); + dprintf(1, "Alternate Display code (%02x) was discarded\n", regs->bh); + regs->al = 0x1a; +} + +static void +handle_101aXX(struct bregs *regs) +{ + debug_stub(regs); +} + +static void +handle_101a(struct bregs *regs) +{ + switch (regs->al) { + case 0x00: handle_101a00(regs); break; + case 0x01: handle_101a01(regs); break; + default: handle_101aXX(regs); break; + } +} + + +struct funcInfo { + u16 static_functionality_off; + u16 static_functionality_seg; + u8 bda_0x49[30]; + u8 bda_0x84[3]; + u8 dcc_index; + u8 dcc_alt; + u16 colors; + u8 pages; + u8 scan_lines; + u8 primary_char; + u8 secondar_char; + u8 misc; + u8 non_vga_mode; + u8 reserved_2f[2]; + u8 video_mem; + u8 save_flags; + u8 disp_info; + u8 reserved_34[12]; +}; + +static void +handle_101b(struct bregs *regs) +{ + u16 seg = regs->es; + struct funcInfo *info = (void*)(regs->di+0); + memset_far(seg, info, 0, sizeof(*info)); + // Address of static functionality table + SET_FARVAR(seg, info->static_functionality_off, (u32)static_functionality); + SET_FARVAR(seg, info->static_functionality_seg, get_global_seg()); + + // Hard coded copy from BIOS area. Should it be cleaner ? + memcpy_far(seg, info->bda_0x49, SEG_BDA, (void*)0x49 + , sizeof(info->bda_0x49)); + memcpy_far(seg, info->bda_0x84, SEG_BDA, (void*)0x84 + , sizeof(info->bda_0x84)); + + SET_FARVAR(seg, info->dcc_index, GET_BDA(dcc_index)); + SET_FARVAR(seg, info->colors, 16); + SET_FARVAR(seg, info->pages, 8); + SET_FARVAR(seg, info->scan_lines, 2); + SET_FARVAR(seg, info->video_mem, 3); + regs->al = 0x1B; +} + + +static void +handle_101c00(struct bregs *regs) +{ + u16 flags = regs->cx; + u16 size = 0; + if (flags & 1) + size += sizeof(struct saveVideoHardware); + if (flags & 2) + size += sizeof(struct saveBDAstate); + if (flags & 4) + size += sizeof(struct saveDACcolors); + regs->bx = size; + regs->al = 0x1c; +} + +static void +handle_101c01(struct bregs *regs) +{ + u16 flags = regs->cx; + u16 seg = regs->es; + void *data = (void*)(regs->bx+0); + if (flags & 1) { + vgahw_save_state(seg, data); + data += sizeof(struct saveVideoHardware); + } + if (flags & 2) { + save_bda_state(seg, data); + data += sizeof(struct saveBDAstate); + } + if (flags & 4) + vgahw_save_dac_state(seg, data); + regs->al = 0x1c; +} + +static void +handle_101c02(struct bregs *regs) +{ + u16 flags = regs->cx; + u16 seg = regs->es; + void *data = (void*)(regs->bx+0); + if (flags & 1) { + vgahw_restore_state(seg, data); + data += sizeof(struct saveVideoHardware); + } + if (flags & 2) { + restore_bda_state(seg, data); + data += sizeof(struct saveBDAstate); + } + if (flags & 4) + vgahw_restore_dac_state(seg, data); + regs->al = 0x1c; +} + +static void +handle_101cXX(struct bregs *regs) +{ + debug_stub(regs); +} + +static void +handle_101c(struct bregs *regs) +{ + switch (regs->al) { + case 0x00: handle_101c00(regs); break; + case 0x01: handle_101c01(regs); break; + case 0x02: handle_101c02(regs); break; + default: handle_101cXX(regs); break; + } +} + + +static void +handle_104f00(struct bregs *regs) +{ + // XXX - vbe_biosfn_return_controller_information(&AX,ES,DI); + // XXX - OR cirrus_vesa_00h +} + +static void +handle_104f01(struct bregs *regs) +{ + // XXX - vbe_biosfn_return_mode_information(&AX,CX,ES,DI); + // XXX - OR cirrus_vesa_01h +} + +static void +handle_104f02(struct bregs *regs) +{ + // XXX - vbe_biosfn_set_mode(&AX,BX,ES,DI); + // XXX - OR cirrus_vesa_02h +} + +static void +handle_104f03(struct bregs *regs) +{ + // XXX - vbe_biosfn_return_current_mode + // XXX - OR cirrus_vesa_03h +} + +static void +handle_104f04(struct bregs *regs) +{ + // XXX - vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX); +} + +static void +handle_104f05(struct bregs *regs) +{ + // XXX - vbe_biosfn_display_window_control + // XXX - OR cirrus_vesa_05h +} + +static void +handle_104f06(struct bregs *regs) +{ + // XXX - vbe_biosfn_set_get_logical_scan_line_length + // XXX - OR cirrus_vesa_06h +} + +static void +handle_104f07(struct bregs *regs) +{ + // XXX - vbe_biosfn_set_get_display_start + // XXX - OR cirrus_vesa_07h +} + +static void +handle_104f08(struct bregs *regs) +{ + // XXX - vbe_biosfn_set_get_dac_palette_format +} + +static void +handle_104f0a(struct bregs *regs) +{ + // XXX - vbe_biosfn_return_protected_mode_interface +} + +static void +handle_104fXX(struct bregs *regs) +{ + debug_stub(regs); + regs->ax = 0x0100; +} + +static void +handle_104f(struct bregs *regs) +{ + if (! CONFIG_VBE || !vbe_has_vbe_display()) { + handle_104fXX(regs); + return; + } + + switch (regs->al) { + case 0x00: handle_104f00(regs); break; + case 0x01: handle_104f01(regs); break; + case 0x02: handle_104f02(regs); break; + case 0x03: handle_104f03(regs); break; + case 0x04: handle_104f04(regs); break; + case 0x05: handle_104f05(regs); break; + case 0x06: handle_104f06(regs); break; + case 0x07: handle_104f07(regs); break; + case 0x08: handle_104f08(regs); break; + case 0x0a: handle_104f0a(regs); break; + default: handle_104fXX(regs); break; + } +} + + +static void +handle_10XX(struct bregs *regs) +{ + debug_stub(regs); +} + +// INT 10h Video Support Service Entry Point +void VISIBLE16 +handle_10(struct bregs *regs) +{ + debug_enter(regs, DEBUG_VGA_10); + switch (regs->ah) { + case 0x00: handle_1000(regs); break; + case 0x01: handle_1001(regs); break; + case 0x02: handle_1002(regs); break; + case 0x03: handle_1003(regs); break; + case 0x04: handle_1004(regs); break; + case 0x05: handle_1005(regs); break; + case 0x06: handle_1006(regs); break; + case 0x07: handle_1007(regs); break; + case 0x08: handle_1008(regs); break; + case 0x09: handle_1009(regs); break; + case 0x0a: handle_100a(regs); break; + case 0x0b: handle_100b(regs); break; + case 0x0c: handle_100c(regs); break; + case 0x0d: handle_100d(regs); break; + case 0x0e: handle_100e(regs); break; + case 0x0f: handle_100f(regs); break; + case 0x10: handle_1010(regs); break; + case 0x11: handle_1011(regs); break; + case 0x12: handle_1012(regs); break; + case 0x13: handle_1013(regs); break; + case 0x1a: handle_101a(regs); break; + case 0x1b: handle_101b(regs); break; + case 0x1c: handle_101c(regs); break; + case 0x4f: handle_104f(regs); break; + default: handle_10XX(regs); break; + } +} + + +/**************************************************************** + * VGA post + ****************************************************************/ + +static void +init_bios_area(void) +{ + // init detected hardware BIOS Area + // set 80x25 color (not clear from RBIL but usual) + u16 eqf = GET_BDA(equipment_list_flags); + SET_BDA(equipment_list_flags, (eqf & 0xffcf) | 0x20); + + // Just for the first int10 find its children + + // the default char height + SET_BDA(char_height, 0x10); + + // Clear the screen + SET_BDA(video_ctl, 0x60); + + // Set the basic screen we have + SET_BDA(video_switches, 0xf9); + + // Set the basic modeset options + SET_BDA(modeset_ctl, 0x51); + + // Set the default MSR + SET_BDA(video_msr, 0x09); +} + +void VISIBLE16 +vga_post(struct bregs *regs) +{ + debug_enter(regs, DEBUG_VGA_POST); + + vgahw_init(); + + init_bios_area(); + + if (CONFIG_VBE) + vbe_init(); + + extern void entry_10(void); + SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10)); + + if (CONFIG_CIRRUS) + cirrus_init(); + + // XXX - clear screen and display info + + // XXX: fill it + SET_VGA(video_save_pointer_table[0], (u32)video_param_table); + SET_VGA(video_save_pointer_table[1], get_global_seg()); + + // Fixup checksum + extern u8 _rom_header_size, _rom_header_checksum; + SET_VGA(_rom_header_checksum, 0); + u8 sum = -checksum_far(get_global_seg(), 0, _rom_header_size * 512); + SET_VGA(_rom_header_checksum, sum); +} diff --git a/bios/seabios/vgasrc/vgaentry.S b/bios/seabios/vgasrc/vgaentry.S new file mode 100644 index 0000000..fbfa9f7 --- /dev/null +++ b/bios/seabios/vgasrc/vgaentry.S @@ -0,0 +1,48 @@ +// Rom layout and bios assembler to C interface. +// +// Copyright (C) 2009 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + + +/**************************************************************** + * Include of 16bit C code + ****************************************************************/ + + .code16gcc +#include "vgaccode.16.s" + +#include "entryfuncs.S" // ENTRY_* + + +/**************************************************************** + * Rom Header + ****************************************************************/ + + .section .rom.header + .global _rom_header, _rom_header_size, _rom_header_checksum +_rom_header: + .word 0xaa55 +_rom_header_size: + .byte 0 +_rom_header_entry: + jmp _optionrom_entry +_rom_header_checksum: + .byte 0 +_rom_header_other: + .space 21 + + +/**************************************************************** + * Entry points + ****************************************************************/ + + DECLFUNC _optionrom_entry +_optionrom_entry: + ENTRY_ARG vga_post + lretw + + DECLFUNC entry_10 +entry_10: + ENTRY_ARG handle_10 + iretw diff --git a/bios/seabios/vgasrc/vgafb.c b/bios/seabios/vgasrc/vgafb.c new file mode 100644 index 0000000..866f7f8 --- /dev/null +++ b/bios/seabios/vgasrc/vgafb.c @@ -0,0 +1,512 @@ +// Code for manipulating VGA framebuffers. +// +// Copyright (C) 2009 Kevin O'Connor +// Copyright (C) 2001-2008 the LGPL VGABios developers Team +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "biosvar.h" // GET_BDA +#include "util.h" // memset_far +#include "vgatables.h" // find_vga_entry + + +/**************************************************************** + * Screen scrolling + ****************************************************************/ + +static inline void * +memcpy_stride(u16 seg, void *dst, void *src, int copylen, int stride, int lines) +{ + for (; lines; lines--, dst+=stride, src+=stride) + memcpy_far(seg, dst, seg, src, copylen); + return dst; +} + +static inline void +memset_stride(u16 seg, void *dst, u8 val, int setlen, int stride, int lines) +{ + for (; lines; lines--, dst+=stride) + memset_far(seg, dst, val, setlen); +} + +static inline void +memset16_stride(u16 seg, void *dst, u16 val, int setlen, int stride, int lines) +{ + for (; lines; lines--, dst+=stride) + memset16_far(seg, dst, val, setlen); +} + +static void +scroll_pl4(struct vgamode_s *vmode_g, int nblines, int attr + , struct cursorpos ul, struct cursorpos lr) +{ + struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam); + u8 cheight = GET_GLOBAL(vparam_g->cheight); + int stride = GET_BDA(video_cols); + void *src_far, *dest_far; + if (nblines >= 0) { + dest_far = (void*)(ul.y * cheight * stride + ul.x); + src_far = dest_far + nblines * cheight * stride; + } else { + // Scroll down + nblines = -nblines; + dest_far = (void*)(lr.y * cheight * stride + ul.x); + src_far = dest_far - nblines * cheight * stride; + stride = -stride; + } + int cols = lr.x - ul.x + 1; + int rows = lr.y - ul.y + 1; + if (nblines < rows) { + vgahw_grdc_write(0x05, 0x01); + dest_far = memcpy_stride(SEG_GRAPH, dest_far, src_far, cols, stride + , (rows - nblines) * cheight); + } + if (attr < 0) + attr = 0; + vgahw_grdc_write(0x05, 0x02); + memset_stride(SEG_GRAPH, dest_far, attr, cols, stride, nblines * cheight); + vgahw_grdc_write(0x05, 0x00); +} + +static void +scroll_cga(struct vgamode_s *vmode_g, int nblines, int attr + , struct cursorpos ul, struct cursorpos lr) +{ + struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam); + u8 cheight = GET_GLOBAL(vparam_g->cheight); + u8 bpp = GET_GLOBAL(vmode_g->pixbits); + int stride = GET_BDA(video_cols) * bpp; + void *src_far, *dest_far; + if (nblines >= 0) { + dest_far = (void*)(ul.y * cheight * stride + ul.x * bpp); + src_far = dest_far + nblines * cheight * stride; + } else { + // Scroll down + nblines = -nblines; + dest_far = (void*)(lr.y * cheight * stride + ul.x * bpp); + src_far = dest_far - nblines * cheight * stride; + stride = -stride; + } + int cols = (lr.x - ul.x + 1) * bpp; + int rows = lr.y - ul.y + 1; + if (nblines < rows) { + memcpy_stride(SEG_CTEXT, dest_far + 0x2000, src_far + 0x2000, cols + , stride, (rows - nblines) * cheight / 2); + dest_far = memcpy_stride(SEG_CTEXT, dest_far, src_far, cols + , stride, (rows - nblines) * cheight / 2); + } + if (attr < 0) + attr = 0; + memset_stride(SEG_CTEXT, dest_far + 0x2000, attr, cols + , stride, nblines * cheight / 2); + memset_stride(SEG_CTEXT, dest_far, attr, cols + , stride, nblines * cheight / 2); +} + +static void +scroll_text(struct vgamode_s *vmode_g, int nblines, int attr + , struct cursorpos ul, struct cursorpos lr) +{ + u16 nbrows = GET_BDA(video_rows) + 1; + u16 nbcols = GET_BDA(video_cols); + void *src_far, *dest_far = (void*)SCREEN_MEM_START(nbcols, nbrows, ul.page); + int stride = nbcols * 2; + if (nblines >= 0) { + dest_far += ul.y * stride + ul.x * 2; + src_far = dest_far + nblines * stride; + } else { + // Scroll down + nblines = -nblines; + dest_far += lr.y * stride + ul.x * 2; + src_far = dest_far - nblines * stride; + stride = -stride; + } + int cols = (lr.x - ul.x + 1) * 2; + int rows = lr.y - ul.y + 1; + u16 seg = GET_GLOBAL(vmode_g->sstart); + if (nblines < rows) + dest_far = memcpy_stride(seg, dest_far, src_far, cols, stride + , (rows - nblines)); + if (attr < 0) + attr = 0x07; + attr = (attr << 8) | ' '; + memset16_stride(seg, dest_far, attr, cols, stride, nblines); +} + +void +vgafb_scroll(int nblines, int attr, struct cursorpos ul, struct cursorpos lr) +{ + // Get the mode + struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode)); + if (!vmode_g) + return; + + // FIXME gfx mode not complete + switch (GET_GLOBAL(vmode_g->memmodel)) { + case CTEXT: + case MTEXT: + scroll_text(vmode_g, nblines, attr, ul, lr); + break; + case PLANAR4: + case PLANAR1: + scroll_pl4(vmode_g, nblines, attr, ul, lr); + break; + case CGA: + scroll_cga(vmode_g, nblines, attr, ul, lr); + break; + default: + dprintf(1, "Scroll in graphics mode\n"); + } +} + +void +clear_screen(struct vgamode_s *vmode_g) +{ + switch (GET_GLOBAL(vmode_g->memmodel)) { + case CTEXT: + case MTEXT: + memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024); + break; + case CGA: + memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024); + break; + default: + // XXX - old code gets/sets/restores sequ register 2 to 0xf - + // but it should always be 0xf anyway. + memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024); + } +} + + +/**************************************************************** + * Read/write characters to screen + ****************************************************************/ + +static void +write_gfx_char_pl4(struct vgamode_s *vmode_g + , struct cursorpos cp, struct carattr ca) +{ + u16 nbcols = GET_BDA(video_cols); + if (cp.x >= nbcols) + return; + + struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam); + u8 cheight = GET_GLOBAL(vparam_g->cheight); + u8 *fdata_g; + switch (cheight) { + case 14: + fdata_g = vgafont14; + break; + case 16: + fdata_g = vgafont16; + break; + default: + fdata_g = vgafont8; + } + u16 addr = cp.x + cp.y * cheight * nbcols; + u16 src = ca.car * cheight; + vgahw_sequ_write(0x02, 0x0f); + vgahw_grdc_write(0x05, 0x02); + if (ca.attr & 0x80) + vgahw_grdc_write(0x03, 0x18); + else + vgahw_grdc_write(0x03, 0x00); + u8 i; + for (i = 0; i < cheight; i++) { + u8 *dest_far = (void*)(addr + i * nbcols); + u8 j; + for (j = 0; j < 8; j++) { + u8 mask = 0x80 >> j; + vgahw_grdc_write(0x08, mask); + GET_FARVAR(SEG_GRAPH, *dest_far); + if (GET_GLOBAL(fdata_g[src + i]) & mask) + SET_FARVAR(SEG_GRAPH, *dest_far, ca.attr & 0x0f); + else + SET_FARVAR(SEG_GRAPH, *dest_far, 0x00); + } + } + vgahw_grdc_write(0x08, 0xff); + vgahw_grdc_write(0x05, 0x00); + vgahw_grdc_write(0x03, 0x00); +} + +static void +write_gfx_char_cga(struct vgamode_s *vmode_g + , struct cursorpos cp, struct carattr ca) +{ + u16 nbcols = GET_BDA(video_cols); + if (cp.x >= nbcols) + return; + + u8 *fdata_g = vgafont8; + u8 bpp = GET_GLOBAL(vmode_g->pixbits); + u16 addr = (cp.x * bpp) + cp.y * 320; + u16 src = ca.car * 8; + u8 i; + for (i = 0; i < 8; i++) { + u8 *dest_far = (void*)(addr + (i >> 1) * 80); + if (i & 1) + dest_far += 0x2000; + u8 mask = 0x80; + if (bpp == 1) { + u8 data = 0; + if (ca.attr & 0x80) + data = GET_FARVAR(SEG_CTEXT, *dest_far); + u8 j; + for (j = 0; j < 8; j++) { + if (GET_GLOBAL(fdata_g[src + i]) & mask) { + if (ca.attr & 0x80) + data ^= (ca.attr & 0x01) << (7 - j); + else + data |= (ca.attr & 0x01) << (7 - j); + } + mask >>= 1; + } + SET_FARVAR(SEG_CTEXT, *dest_far, data); + } else { + while (mask > 0) { + u8 data = 0; + if (ca.attr & 0x80) + data = GET_FARVAR(SEG_CTEXT, *dest_far); + u8 j; + for (j = 0; j < 4; j++) { + if (GET_GLOBAL(fdata_g[src + i]) & mask) { + if (ca.attr & 0x80) + data ^= (ca.attr & 0x03) << ((3 - j) * 2); + else + data |= (ca.attr & 0x03) << ((3 - j) * 2); + } + mask >>= 1; + } + SET_FARVAR(SEG_CTEXT, *dest_far, data); + dest_far += 1; + } + } + } +} + +static void +write_gfx_char_lin(struct vgamode_s *vmode_g + , struct cursorpos cp, struct carattr ca) +{ + // Get the dimensions + u16 nbcols = GET_BDA(video_cols); + if (cp.x >= nbcols) + return; + + u8 *fdata_g = vgafont8; + u16 addr = cp.x * 8 + cp.y * nbcols * 64; + u16 src = ca.car * 8; + u8 i; + for (i = 0; i < 8; i++) { + u8 *dest_far = (void*)(addr + i * nbcols * 8); + u8 mask = 0x80; + u8 j; + for (j = 0; j < 8; j++) { + u8 data = 0x00; + if (GET_GLOBAL(fdata_g[src + i]) & mask) + data = ca.attr; + SET_FARVAR(SEG_GRAPH, dest_far[j], data); + mask >>= 1; + } + } +} + +static void +write_text_char(struct vgamode_s *vmode_g + , struct cursorpos cp, struct carattr ca) +{ + // Get the dimensions + u16 nbrows = GET_BDA(video_rows) + 1; + u16 nbcols = GET_BDA(video_cols); + + // Compute the address + void *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page) + + (cp.x + cp.y * nbcols) * 2); + + if (ca.use_attr) { + u16 dummy = (ca.attr << 8) | ca.car; + SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u16*)address_far, dummy); + } else { + SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)address_far, ca.car); + } +} + +void +vgafb_write_char(struct cursorpos cp, struct carattr ca) +{ + // Get the mode + struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode)); + if (!vmode_g) + return; + + // FIXME gfx mode not complete + switch (GET_GLOBAL(vmode_g->memmodel)) { + case CTEXT: + case MTEXT: + write_text_char(vmode_g, cp, ca); + break; + case PLANAR4: + case PLANAR1: + write_gfx_char_pl4(vmode_g, cp, ca); + break; + case CGA: + write_gfx_char_cga(vmode_g, cp, ca); + break; + case LINEAR8: + write_gfx_char_lin(vmode_g, cp, ca); + break; + } +} + +struct carattr +vgafb_read_char(struct cursorpos cp) +{ + // Get the mode + struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode)); + if (!vmode_g) + goto fail; + + if (!(GET_GLOBAL(vmode_g->memmodel) & TEXT)) { + // FIXME gfx mode + dprintf(1, "Read char in graphics mode\n"); + goto fail; + } + + // Get the dimensions + u16 nbrows = GET_BDA(video_rows) + 1; + u16 nbcols = GET_BDA(video_cols); + + // Compute the address + u16 *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page) + + (cp.x + cp.y * nbcols) * 2); + u16 v = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far); + struct carattr ca = {v, v>>8, 0}; + return ca; + +fail: ; + struct carattr ca2 = {0, 0, 0}; + return ca2; +} + + +/**************************************************************** + * Read/write pixels + ****************************************************************/ + +void +vgafb_write_pixel(u8 color, u16 x, u16 y) +{ + // Get the mode + struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode)); + if (!vmode_g) + return; + if (GET_GLOBAL(vmode_g->memmodel) & TEXT) + return; + + u8 *addr_far, mask, attr, data; + switch (GET_GLOBAL(vmode_g->memmodel)) { + case PLANAR4: + case PLANAR1: + addr_far = (void*)(x / 8 + y * GET_BDA(video_cols)); + mask = 0x80 >> (x & 0x07); + vgahw_grdc_write(0x08, mask); + vgahw_grdc_write(0x05, 0x02); + data = GET_FARVAR(SEG_GRAPH, *addr_far); + if (color & 0x80) + vgahw_grdc_write(0x03, 0x18); + SET_FARVAR(SEG_GRAPH, *addr_far, color); + vgahw_grdc_write(0x08, 0xff); + vgahw_grdc_write(0x05, 0x00); + vgahw_grdc_write(0x03, 0x00); + break; + case CGA: + if (GET_GLOBAL(vmode_g->pixbits) == 2) + addr_far = (void*)((x >> 2) + (y >> 1) * 80); + else + addr_far = (void*)((x >> 3) + (y >> 1) * 80); + if (y & 1) + addr_far += 0x2000; + data = GET_FARVAR(SEG_CTEXT, *addr_far); + if (GET_GLOBAL(vmode_g->pixbits) == 2) { + attr = (color & 0x03) << ((3 - (x & 0x03)) * 2); + mask = 0x03 << ((3 - (x & 0x03)) * 2); + } else { + attr = (color & 0x01) << (7 - (x & 0x07)); + mask = 0x01 << (7 - (x & 0x07)); + } + if (color & 0x80) { + data ^= attr; + } else { + data &= ~mask; + data |= attr; + } + SET_FARVAR(SEG_CTEXT, *addr_far, data); + break; + case LINEAR8: + addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8)); + SET_FARVAR(SEG_GRAPH, *addr_far, color); + break; + } +} + +u8 +vgafb_read_pixel(u16 x, u16 y) +{ + // Get the mode + struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode)); + if (!vmode_g) + return 0; + if (GET_GLOBAL(vmode_g->memmodel) & TEXT) + return 0; + + u8 *addr_far, mask, attr=0, data, i; + switch (GET_GLOBAL(vmode_g->memmodel)) { + case PLANAR4: + case PLANAR1: + addr_far = (void*)(x / 8 + y * GET_BDA(video_cols)); + mask = 0x80 >> (x & 0x07); + attr = 0x00; + for (i = 0; i < 4; i++) { + vgahw_grdc_write(0x04, i); + data = GET_FARVAR(SEG_GRAPH, *addr_far) & mask; + if (data > 0) + attr |= (0x01 << i); + } + break; + case CGA: + addr_far = (void*)((x >> 2) + (y >> 1) * 80); + if (y & 1) + addr_far += 0x2000; + data = GET_FARVAR(SEG_CTEXT, *addr_far); + if (GET_GLOBAL(vmode_g->pixbits) == 2) + attr = (data >> ((3 - (x & 0x03)) * 2)) & 0x03; + else + attr = (data >> (7 - (x & 0x07))) & 0x01; + break; + case LINEAR8: + addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8)); + attr = GET_FARVAR(SEG_GRAPH, *addr_far); + break; + } + return attr; +} + + +/**************************************************************** + * Font loading + ****************************************************************/ + +void +vgafb_load_font(u16 seg, void *src_far, u16 count + , u16 start, u8 destflags, u8 fontsize) +{ + get_font_access(); + u16 blockaddr = ((destflags & 0x03) << 14) + ((destflags & 0x04) << 11); + void *dest_far = (void*)(blockaddr + start*32); + u16 i; + for (i = 0; i < count; i++) + memcpy_far(SEG_GRAPH, dest_far + i*32 + , seg, src_far + i*fontsize, fontsize); + release_font_access(); +} diff --git a/bios/seabios/vgasrc/vgafonts.c b/bios/seabios/vgasrc/vgafonts.c new file mode 100644 index 0000000..8c1752c --- /dev/null +++ b/bios/seabios/vgasrc/vgafonts.c @@ -0,0 +1,785 @@ +#include "vgatables.h" // vgafont8 + +/* + * These fonts come from ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip + * The package is (c) by Joseph Gil + * The individual fonts are public domain + */ +u8 vgafont8[256 * 8] VAR16 = { + 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, + 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78, + 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, + 0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, + 0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00, + 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, + 0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, + 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, + 0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38, + 0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00, + 0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, + 0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, + 0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, + 0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00, + 0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00, + 0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00, + 0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00, + 0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, + 0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, + 0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, + 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, + 0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, + 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, + 0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00, + 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, + 0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18, + 0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00, + 0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30, + 0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7, + 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70, + 0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, + 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, + 0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, + 0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00, + 0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00, + 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, + 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, + 0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00, + 0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f, + 0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03, + 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00, + 0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00, + 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, + 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, + 0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, + 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, + 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, + 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, + 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, + 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, + 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, + 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, + 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, + 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00, + 0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0, + 0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, + 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, + 0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00, + 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0, + 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00, + 0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc, + 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00, + 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00, + 0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00, + 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00, + 0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0, + 0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00, + 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, + 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00, + 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00, + 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00, + 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00, + 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, + 0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00, + 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, + 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c, + 0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, + 0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +u8 vgafont14[256 * 14] VAR16 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x7e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x06, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x66, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe6, 0x66, 0x6c, 0x6c, 0x78, 0x6c, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x7c, 0x6c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc6, 0x8c, 0x18, 0x30, 0x60, 0xc2, 0xc6, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, + 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6, 0xd6, 0xd6, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x70, 0x1c, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x66, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, + 0x00, 0x00, 0xcc, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0xc6, 0xc6, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xcc, 0x76, 0x36, 0x7e, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, + 0x00, 0xc6, 0xc6, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, + 0x00, 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0xcc, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0xcc, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, + 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xc0, 0xc6, 0xcc, 0xd8, 0x30, 0x60, 0xdc, 0x86, 0x0c, 0x18, 0x3e, 0x00, + 0x00, 0xc0, 0xc0, 0xc6, 0xcc, 0xd8, 0x30, 0x66, 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, + 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, + 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfc, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0x40, 0x00, + 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +u8 vgafont16[256 * 16] VAR16 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, + 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00, + 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, + 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, + 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +u8 vgafont14alt[1] VAR16; +u8 vgafont16alt[1] VAR16; diff --git a/bios/seabios/vgasrc/vgaio.c b/bios/seabios/vgasrc/vgaio.c new file mode 100644 index 0000000..ffded34 --- /dev/null +++ b/bios/seabios/vgasrc/vgaio.c @@ -0,0 +1,555 @@ +// VGA io port access +// +// Copyright (C) 2009 Kevin O'Connor +// Copyright (C) 2001-2008 the LGPL VGABios developers Team +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "ioport.h" // outb +#include "farptr.h" // SET_FARVAR +#include "biosvar.h" // GET_BDA +#include "vgatables.h" // VGAREG_* + +// TODO +// * replace direct in/out calls with wrapper functions + + +/**************************************************************** + * Attribute control + ****************************************************************/ + +void +vgahw_screen_disable(void) +{ + inb(VGAREG_ACTL_RESET); + outb(0x00, VGAREG_ACTL_ADDRESS); +} + +void +vgahw_screen_enable(void) +{ + inb(VGAREG_ACTL_RESET); + outb(0x20, VGAREG_ACTL_ADDRESS); +} + +void +vgahw_set_border_color(u8 color) +{ + inb(VGAREG_ACTL_RESET); + outb(0x00, VGAREG_ACTL_ADDRESS); + u8 v1 = color & 0x0f; + if (v1 & 0x08) + v1 += 0x08; + outb(v1, VGAREG_ACTL_WRITE_DATA); + + u8 v2 = color & 0x10; + int i; + for (i = 1; i < 4; i++) { + outb(i, VGAREG_ACTL_ADDRESS); + + u8 cur = inb(VGAREG_ACTL_READ_DATA); + cur &= 0xef; + cur |= v2; + outb(cur, VGAREG_ACTL_WRITE_DATA); + } + outb(0x20, VGAREG_ACTL_ADDRESS); +} + +void +vgahw_set_overscan_border_color(u8 color) +{ + inb(VGAREG_ACTL_RESET); + outb(0x11, VGAREG_ACTL_ADDRESS); + outb(color, VGAREG_ACTL_WRITE_DATA); + outb(0x20, VGAREG_ACTL_ADDRESS); +} + +u8 +vgahw_get_overscan_border_color(void) +{ + inb(VGAREG_ACTL_RESET); + outb(0x11, VGAREG_ACTL_ADDRESS); + u8 v = inb(VGAREG_ACTL_READ_DATA); + inb(VGAREG_ACTL_RESET); + outb(0x20, VGAREG_ACTL_ADDRESS); + return v; +} + +void +vgahw_set_palette(u8 palid) +{ + inb(VGAREG_ACTL_RESET); + palid &= 0x01; + int i; + for (i = 1; i < 4; i++) { + outb(i, VGAREG_ACTL_ADDRESS); + + u8 v = inb(VGAREG_ACTL_READ_DATA); + v &= 0xfe; + v |= palid; + outb(v, VGAREG_ACTL_WRITE_DATA); + } + outb(0x20, VGAREG_ACTL_ADDRESS); +} + +void +vgahw_set_single_palette_reg(u8 reg, u8 val) +{ + inb(VGAREG_ACTL_RESET); + outb(reg, VGAREG_ACTL_ADDRESS); + outb(val, VGAREG_ACTL_WRITE_DATA); + outb(0x20, VGAREG_ACTL_ADDRESS); +} + +u8 +vgahw_get_single_palette_reg(u8 reg) +{ + inb(VGAREG_ACTL_RESET); + outb(reg, VGAREG_ACTL_ADDRESS); + u8 v = inb(VGAREG_ACTL_READ_DATA); + inb(VGAREG_ACTL_RESET); + outb(0x20, VGAREG_ACTL_ADDRESS); + return v; +} + +void +vgahw_set_all_palette_reg(u16 seg, u8 *data_far) +{ + inb(VGAREG_ACTL_RESET); + int i; + for (i = 0; i < 0x10; i++) { + outb(i, VGAREG_ACTL_ADDRESS); + u8 val = GET_FARVAR(seg, *data_far); + outb(val, VGAREG_ACTL_WRITE_DATA); + data_far++; + } + outb(0x11, VGAREG_ACTL_ADDRESS); + outb(GET_FARVAR(seg, *data_far), VGAREG_ACTL_WRITE_DATA); + outb(0x20, VGAREG_ACTL_ADDRESS); +} + +void +vgahw_get_all_palette_reg(u16 seg, u8 *data_far) +{ + int i; + for (i = 0; i < 0x10; i++) { + inb(VGAREG_ACTL_RESET); + outb(i, VGAREG_ACTL_ADDRESS); + SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA)); + data_far++; + } + inb(VGAREG_ACTL_RESET); + outb(0x11, VGAREG_ACTL_ADDRESS); + SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA)); + inb(VGAREG_ACTL_RESET); + outb(0x20, VGAREG_ACTL_ADDRESS); +} + +void +vgahw_toggle_intensity(u8 flag) +{ + inb(VGAREG_ACTL_RESET); + outb(0x10, VGAREG_ACTL_ADDRESS); + u8 val = (inb(VGAREG_ACTL_READ_DATA) & 0xf7) | ((flag & 0x01) << 3); + outb(val, VGAREG_ACTL_WRITE_DATA); + outb(0x20, VGAREG_ACTL_ADDRESS); +} + +void +vgahw_select_video_dac_color_page(u8 flag, u8 data) +{ + inb(VGAREG_ACTL_RESET); + outb(0x10, VGAREG_ACTL_ADDRESS); + u8 val = inb(VGAREG_ACTL_READ_DATA); + if (!(flag & 0x01)) { + // select paging mode + val = (val & 0x7f) | (data << 7); + outb(val, VGAREG_ACTL_WRITE_DATA); + outb(0x20, VGAREG_ACTL_ADDRESS); + return; + } + // select page + inb(VGAREG_ACTL_RESET); + outb(0x14, VGAREG_ACTL_ADDRESS); + if (!(val & 0x80)) + data <<= 2; + data &= 0x0f; + outb(data, VGAREG_ACTL_WRITE_DATA); + outb(0x20, VGAREG_ACTL_ADDRESS); +} + +void +vgahw_read_video_dac_state(u8 *pmode, u8 *curpage) +{ + inb(VGAREG_ACTL_RESET); + outb(0x10, VGAREG_ACTL_ADDRESS); + u8 val1 = inb(VGAREG_ACTL_READ_DATA) >> 7; + + inb(VGAREG_ACTL_RESET); + outb(0x14, VGAREG_ACTL_ADDRESS); + u8 val2 = inb(VGAREG_ACTL_READ_DATA) & 0x0f; + if (!(val1 & 0x01)) + val2 >>= 2; + + inb(VGAREG_ACTL_RESET); + outb(0x20, VGAREG_ACTL_ADDRESS); + + *pmode = val1; + *curpage = val2; +} + + +/**************************************************************** + * DAC control + ****************************************************************/ + +void +vgahw_set_dac_regs(u16 seg, u8 *data_far, u8 start, int count) +{ + outb(start, VGAREG_DAC_WRITE_ADDRESS); + while (count) { + outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA); + data_far++; + outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA); + data_far++; + outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA); + data_far++; + count--; + } +} + +void +vgahw_get_dac_regs(u16 seg, u8 *data_far, u8 start, int count) +{ + outb(start, VGAREG_DAC_READ_ADDRESS); + while (count) { + SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA)); + data_far++; + SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA)); + data_far++; + SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA)); + data_far++; + count--; + } +} + +void +vgahw_set_pel_mask(u8 val) +{ + outb(val, VGAREG_PEL_MASK); +} + +u8 +vgahw_get_pel_mask(void) +{ + return inb(VGAREG_PEL_MASK); +} + +void +vgahw_save_dac_state(u16 seg, struct saveDACcolors *info) +{ + /* XXX: check this */ + SET_FARVAR(seg, info->rwmode, inb(VGAREG_DAC_STATE)); + SET_FARVAR(seg, info->peladdr, inb(VGAREG_DAC_WRITE_ADDRESS)); + SET_FARVAR(seg, info->pelmask, inb(VGAREG_PEL_MASK)); + vgahw_get_dac_regs(seg, info->dac, 0, 256); + SET_FARVAR(seg, info->color_select, 0); +} + +void +vgahw_restore_dac_state(u16 seg, struct saveDACcolors *info) +{ + outb(GET_FARVAR(seg, info->pelmask), VGAREG_PEL_MASK); + vgahw_set_dac_regs(seg, info->dac, 0, 256); + outb(GET_FARVAR(seg, info->peladdr), VGAREG_DAC_WRITE_ADDRESS); +} + + +/**************************************************************** + * Memory control + ****************************************************************/ + +void +vgahw_sequ_write(u8 index, u8 value) +{ + outw((value<<8) | index, VGAREG_SEQU_ADDRESS); +} + +void +vgahw_grdc_write(u8 index, u8 value) +{ + outw((value<<8) | index, VGAREG_GRDC_ADDRESS); +} + +void +vgahw_set_text_block_specifier(u8 spec) +{ + outw((spec << 8) | 0x03, VGAREG_SEQU_ADDRESS); +} + +void +get_font_access(void) +{ + outw(0x0100, VGAREG_SEQU_ADDRESS); + outw(0x0402, VGAREG_SEQU_ADDRESS); + outw(0x0704, VGAREG_SEQU_ADDRESS); + outw(0x0300, VGAREG_SEQU_ADDRESS); + outw(0x0204, VGAREG_GRDC_ADDRESS); + outw(0x0005, VGAREG_GRDC_ADDRESS); + outw(0x0406, VGAREG_GRDC_ADDRESS); +} + +void +release_font_access(void) +{ + outw(0x0100, VGAREG_SEQU_ADDRESS); + outw(0x0302, VGAREG_SEQU_ADDRESS); + outw(0x0304, VGAREG_SEQU_ADDRESS); + outw(0x0300, VGAREG_SEQU_ADDRESS); + u16 v = (inw(VGAREG_READ_MISC_OUTPUT) & 0x01) ? 0x0e : 0x0a; + outw((v << 8) | 0x06, VGAREG_GRDC_ADDRESS); + outw(0x0004, VGAREG_GRDC_ADDRESS); + outw(0x1005, VGAREG_GRDC_ADDRESS); +} + + +/**************************************************************** + * CRTC registers + ****************************************************************/ + +static u16 +get_crtc(void) +{ + return GET_BDA(crtc_address); +} + +void +vgahw_set_cursor_shape(u8 start, u8 end) +{ + u16 crtc_addr = get_crtc(); + outb(0x0a, crtc_addr); + outb(start, crtc_addr + 1); + outb(0x0b, crtc_addr); + outb(end, crtc_addr + 1); +} + +void +vgahw_set_active_page(u16 address) +{ + u16 crtc_addr = get_crtc(); + outb(0x0c, crtc_addr); + outb((address & 0xff00) >> 8, crtc_addr + 1); + outb(0x0d, crtc_addr); + outb(address & 0x00ff, crtc_addr + 1); +} + +void +vgahw_set_cursor_pos(u16 address) +{ + u16 crtc_addr = get_crtc(); + outb(0x0e, crtc_addr); + outb((address & 0xff00) >> 8, crtc_addr + 1); + outb(0x0f, crtc_addr); + outb(address & 0x00ff, crtc_addr + 1); +} + +void +vgahw_set_scan_lines(u8 lines) +{ + u16 crtc_addr = get_crtc(); + outb(0x09, crtc_addr); + u8 crtc_r9 = inb(crtc_addr + 1); + crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1); + outb(crtc_r9, crtc_addr + 1); +} + +// Get vertical display end +u16 +vgahw_get_vde(void) +{ + u16 crtc_addr = get_crtc(); + outb(0x12, crtc_addr); + u16 vde = inb(crtc_addr + 1); + outb(0x07, crtc_addr); + u8 ovl = inb(crtc_addr + 1); + vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1); + return vde; +} + + +/**************************************************************** + * Save/Restore/Set state + ****************************************************************/ + +void +vgahw_save_state(u16 seg, struct saveVideoHardware *info) +{ + u16 crtc_addr = get_crtc(); + SET_FARVAR(seg, info->sequ_index, inb(VGAREG_SEQU_ADDRESS)); + SET_FARVAR(seg, info->crtc_index, inb(crtc_addr)); + SET_FARVAR(seg, info->grdc_index, inb(VGAREG_GRDC_ADDRESS)); + inb(VGAREG_ACTL_RESET); + u16 ar_index = inb(VGAREG_ACTL_ADDRESS); + SET_FARVAR(seg, info->actl_index, ar_index); + SET_FARVAR(seg, info->feature, inb(VGAREG_READ_FEATURE_CTL)); + + u16 i; + for (i=0; i<4; i++) { + outb(i+1, VGAREG_SEQU_ADDRESS); + SET_FARVAR(seg, info->sequ_regs[i], inb(VGAREG_SEQU_DATA)); + } + outb(0, VGAREG_SEQU_ADDRESS); + SET_FARVAR(seg, info->sequ0, inb(VGAREG_SEQU_DATA)); + + for (i=0; i<25; i++) { + outb(i, crtc_addr); + SET_FARVAR(seg, info->crtc_regs[i], inb(crtc_addr + 1)); + } + + for (i=0; i<20; i++) { + inb(VGAREG_ACTL_RESET); + outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS); + SET_FARVAR(seg, info->actl_regs[i], inb(VGAREG_ACTL_READ_DATA)); + } + inb(VGAREG_ACTL_RESET); + + for (i=0; i<9; i++) { + outb(i, VGAREG_GRDC_ADDRESS); + SET_FARVAR(seg, info->grdc_regs[i], inb(VGAREG_GRDC_DATA)); + } + + SET_FARVAR(seg, info->crtc_addr, crtc_addr); + + /* XXX: read plane latches */ + for (i=0; i<4; i++) + SET_FARVAR(seg, info->plane_latch[i], 0); +} + +void +vgahw_restore_state(u16 seg, struct saveVideoHardware *info) +{ + // Reset Attribute Ctl flip-flop + inb(VGAREG_ACTL_RESET); + + u16 crtc_addr = GET_FARVAR(seg, info->crtc_addr); + + u16 i; + for (i=0; i<4; i++) { + outb(i+1, VGAREG_SEQU_ADDRESS); + outb(GET_FARVAR(seg, info->sequ_regs[i]), VGAREG_SEQU_DATA); + } + outb(0, VGAREG_SEQU_ADDRESS); + outb(GET_FARVAR(seg, info->sequ0), VGAREG_SEQU_DATA); + + // Disable CRTC write protection + outw(0x0011, crtc_addr); + // Set CRTC regs + for (i=0; i<25; i++) + if (i != 0x11) { + outb(i, crtc_addr); + outb(GET_FARVAR(seg, info->crtc_regs[i]), crtc_addr + 1); + } + // select crtc base address + u16 v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01; + if (crtc_addr == VGAREG_VGA_CRTC_ADDRESS) + v |= 0x01; + outb(v, VGAREG_WRITE_MISC_OUTPUT); + + // enable write protection if needed + outb(0x11, crtc_addr); + outb(GET_FARVAR(seg, info->crtc_regs[0x11]), crtc_addr + 1); + + // Set Attribute Ctl + u16 ar_index = GET_FARVAR(seg, info->actl_index); + inb(VGAREG_ACTL_RESET); + for (i=0; i<20; i++) { + outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS); + outb(GET_FARVAR(seg, info->actl_regs[i]), VGAREG_ACTL_WRITE_DATA); + } + outb(ar_index, VGAREG_ACTL_ADDRESS); + inb(VGAREG_ACTL_RESET); + + for (i=0; i<9; i++) { + outb(i, VGAREG_GRDC_ADDRESS); + outb(GET_FARVAR(seg, info->grdc_regs[i]), VGAREG_GRDC_DATA); + } + + outb(GET_FARVAR(seg, info->sequ_index), VGAREG_SEQU_ADDRESS); + outb(GET_FARVAR(seg, info->crtc_index), crtc_addr); + outb(GET_FARVAR(seg, info->grdc_index), VGAREG_GRDC_ADDRESS); + outb(GET_FARVAR(seg, info->feature), crtc_addr - 0x4 + 0xa); +} + +void +vgahw_set_mode(struct VideoParam_s *vparam_g) +{ + // Reset Attribute Ctl flip-flop + inb(VGAREG_ACTL_RESET); + + // Set Attribute Ctl + u16 i; + for (i = 0; i <= 0x13; i++) { + outb(i, VGAREG_ACTL_ADDRESS); + outb(GET_GLOBAL(vparam_g->actl_regs[i]), VGAREG_ACTL_WRITE_DATA); + } + outb(0x14, VGAREG_ACTL_ADDRESS); + outb(0x00, VGAREG_ACTL_WRITE_DATA); + + // Set Sequencer Ctl + outb(0, VGAREG_SEQU_ADDRESS); + outb(0x03, VGAREG_SEQU_DATA); + for (i = 1; i <= 4; i++) { + outb(i, VGAREG_SEQU_ADDRESS); + outb(GET_GLOBAL(vparam_g->sequ_regs[i - 1]), VGAREG_SEQU_DATA); + } + + // Set Grafx Ctl + for (i = 0; i <= 8; i++) { + outb(i, VGAREG_GRDC_ADDRESS); + outb(GET_GLOBAL(vparam_g->grdc_regs[i]), VGAREG_GRDC_DATA); + } + + // Set CRTC address VGA or MDA + u8 miscreg = GET_GLOBAL(vparam_g->miscreg); + u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS; + if (!(miscreg & 1)) + crtc_addr = VGAREG_MDA_CRTC_ADDRESS; + + // Disable CRTC write protection + outw(0x0011, crtc_addr); + // Set CRTC regs + for (i = 0; i <= 0x18; i++) { + outb(i, crtc_addr); + outb(GET_GLOBAL(vparam_g->crtc_regs[i]), crtc_addr + 1); + } + + // Set the misc register + outb(miscreg, VGAREG_WRITE_MISC_OUTPUT); + + // Enable video + outb(0x20, VGAREG_ACTL_ADDRESS); + inb(VGAREG_ACTL_RESET); +} + + +/**************************************************************** + * Misc + ****************************************************************/ + +void +vgahw_enable_video_addressing(u8 disable) +{ + u8 v = (disable & 1) ? 0x00 : 0x02; + u8 v2 = inb(VGAREG_READ_MISC_OUTPUT) & ~0x02; + outb(v | v2, VGAREG_WRITE_MISC_OUTPUT); +} + +void +vgahw_init(void) +{ + // switch to color mode and enable CPU access 480 lines + outb(0xc3, VGAREG_WRITE_MISC_OUTPUT); + // more than 64k 3C4/04 + outb(0x04, VGAREG_SEQU_ADDRESS); + outb(0x02, VGAREG_SEQU_DATA); +} diff --git a/bios/seabios/vgasrc/vgalayout.lds.S b/bios/seabios/vgasrc/vgalayout.lds.S new file mode 100644 index 0000000..08a5f32 --- /dev/null +++ b/bios/seabios/vgasrc/vgalayout.lds.S @@ -0,0 +1,24 @@ +// Linker definitions for an option rom +// +// Copyright (C) 2009 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH("i386") +ENTRY(_optionrom_entry) +SECTIONS +{ + .text 0 : { + KEEP(*(.rom.header)) + *(.text.*) + _rodata = . ; + *(.rodata.__func__.*) + *(.rodata.str1.1) + *(.data16.*) + } + + // Discard regular data sections to force a link error if + // 16bit code attempts to access data not marked with VAR16. + /DISCARD/ : { *(.text*) *(.rodata*) *(.data*) *(.bss*) *(COMMON) } +} diff --git a/bios/seabios/vgasrc/vgatables.c b/bios/seabios/vgasrc/vgatables.c new file mode 100644 index 0000000..0587e65 --- /dev/null +++ b/bios/seabios/vgasrc/vgatables.c @@ -0,0 +1,438 @@ +// Tables used by VGA bios +// +// Copyright (C) 2009 Kevin O'Connor +// Copyright (C) 2001-2008 the LGPL VGABios developers Team +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "vgatables.h" // struct VideoParamTableEntry_s +#include "biosvar.h" // GET_GLOBAL + + +/**************************************************************** + * Video parameter table + ****************************************************************/ + +struct VideoParam_s video_param_table[] VAR16 = { + // index=0x00 no mode defined + {}, + // index=0x01 no mode defined + {}, + // index=0x02 no mode defined + {}, + // index=0x03 no mode defined + {}, + // index=0x04 vga mode 0x04 + { 40, 24, 8, 0x0800, /* tw, th-1, ch, slength */ + { 0x09, 0x03, 0x00, 0x02 }, /* sequ_regs */ + 0x63, /* miscreg */ + { 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f, + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2, + 0xff }, /* crtc_regs */ + { 0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x03, 0x00 }, /* actl_regs */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x0f, 0xff }, /* grdc_regs */ + }, + /* index=0x05 vga mode 0x05 */ + { 40, 24, 8, 0x0800, /* tw, th-1, ch, slength */ + { 0x09, 0x03, 0x00, 0x02 }, /* sequ_regs */ + 0x63, /* miscreg */ + { 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f, + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2, + 0xff }, /* crtc_regs */ + { 0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x03, 0x00 }, /* actl_regs */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x0f, 0xff }, /* grdc_regs */ + }, + /* index=0x06 vga mode 0x06 */ + { 80, 24, 8, 0x1000, /* tw, th-1, ch, slength */ + { 0x01, 0x01, 0x00, 0x06 }, /* sequ_regs */ + 0x63, /* miscreg */ + { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xc2, + 0xff }, /* crtc_regs */ + { 0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x01, 0x00, 0x01, 0x00 }, /* actl_regs */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x0f, 0xff }, /* grdc_regs */ + }, + /* index=0x07 vga mode 0x07 */ + { 80, 24, 16, 0x1000, /* tw, th-1, ch, slength */ + { 0x00, 0x03, 0x00, 0x02 }, /* sequ_regs */ + 0x66, /* miscreg */ + { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3, + 0xff }, /* crtc_regs */ + { 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x0e, 0x00, 0x0f, 0x08 }, /* actl_regs */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x0f, 0xff }, /* grdc_regs */ + }, + /* index=0x08 no mode defined */ + {}, + /* index=0x09 no mode defined */ + {}, + /* index=0x0a no mode defined */ + {}, + /* index=0x0b no mode defined */ + {}, + /* index=0x0c no mode defined */ + {}, + /* index=0x0d vga mode 0x0d */ + { 40, 24, 8, 0x2000, /* tw, th-1, ch, slength */ + { 0x09, 0x0f, 0x00, 0x06 }, /* sequ_regs */ + 0x63, /* miscreg */ + { 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xe3, + 0xff }, /* crtc_regs */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x0f, 0x00 }, /* actl_regs */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */ + }, + /* index=0x0e vga mode 0x0e */ + { 80, 24, 8, 0x4000, /* tw, th-1, ch, slength */ + { 0x01, 0x0f, 0x00, 0x06 }, /* sequ_regs */ + 0x63, /* miscreg */ + { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xe3, + 0xff }, /* crtc_regs */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x0f, 0x00 }, /* actl_regs */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */ + }, + /* index=0x0f no mode defined */ + {}, + /* index=0x10 no mode defined */ + {}, + /* index=0x11 vga mode 0x0f */ + { 80, 24, 14, 0x8000, /* tw, th-1, ch, slength */ + { 0x01, 0x0f, 0x00, 0x06 }, /* sequ_regs */ + 0xa3, /* miscreg */ + { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3, + 0xff }, /* crtc_regs */ + { 0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00 }, /* actl_regs */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */ + }, + /* index=0x12 vga mode 0x10 */ + { 80, 24, 14, 0x8000, /* tw, th-1, ch, slength */ + { 0x01, 0x0f, 0x00, 0x06 }, /* sequ_regs */ + 0xa3, /* miscreg */ + { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3, + 0xff }, /* crtc_regs */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x01, 0x00, 0x0f, 0x00 }, /* actl_regs */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */ + }, + /* index=0x13 no mode defined */ + {}, + /* index=0x14 no mode defined */ + {}, + /* index=0x15 no mode defined */ + {}, + /* index=0x16 no mode defined */ + {}, + /* index=0x17 vga mode 0x01 */ + { 40, 24, 16, 0x0800, /* tw, th-1, ch, slength */ + { 0x08, 0x03, 0x00, 0x02 }, /* sequ_regs */ + 0x67, /* miscreg */ + { 0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, + 0xff }, /* crtc_regs */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x0c, 0x00, 0x0f, 0x08 }, /* actl_regs */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x0f, 0xff }, /* grdc_regs */ + }, + /* index=0x18 vga mode 0x03 */ + { 80, 24, 16, 0x1000, /* tw, th-1, ch, slength */ + { 0x00, 0x03, 0x00, 0x02 }, /* sequ_regs */ + 0x67, /* miscreg */ + { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff }, /* crtc_regs */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x0c, 0x00, 0x0f, 0x08 }, /* actl_regs */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x0f, 0xff }, /* grdc_regs */ + }, + /* index=0x19 vga mode 0x07 */ + { 80, 24, 16, 0x1000, /* tw, th-1, ch, slength */ + { 0x00, 0x03, 0x00, 0x02 }, /* sequ_regs */ + 0x66, /* miscreg */ + { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3, + 0xff }, /* crtc_regs */ + { 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x0e, 0x00, 0x0f, 0x08 }, /* actl_regs */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x0f, 0xff }, /* grdc_regs */ + }, + /* index=0x1a vga mode 0x11 */ + { 80, 29, 16, 0x0000, /* tw, th-1, ch, slength */ + { 0x01, 0x0f, 0x00, 0x06 }, /* sequ_regs */ + 0xe3, /* miscreg */ + { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3, + 0xff }, /* crtc_regs */ + { 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, + 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, + 0x01, 0x00, 0x0f, 0x00 }, /* actl_regs */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */ + }, + /* index=0x1b vga mode 0x12 */ + { 80, 29, 16, 0x0000, /* tw, th-1, ch, slength */ + { 0x01, 0x0f, 0x00, 0x06 }, /* sequ_regs */ + 0xe3, /* miscreg */ + { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3, + 0xff }, /* crtc_regs */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x01, 0x00, 0x0f, 0x00 }, /* actl_regs */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */ + }, + /* index=0x1c vga mode 0x13 */ + { 40, 24, 8, 0x0000, /* tw, th-1, ch, slength */ + { 0x01, 0x0f, 0x00, 0x0e }, /* sequ_regs */ + 0x63, /* miscreg */ + { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, + 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3, + 0xff }, /* crtc_regs */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x41, 0x00, 0x0f, 0x00 }, /* actl_regs */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff }, /* grdc_regs */ + }, + /* index=0x1d vga mode 0x6a */ + { 100, 36, 16, 0x0000, /* tw, th-1, ch, slength */ + { 0x01, 0x0f, 0x00, 0x06 }, /* sequ_regs */ + 0xe3, /* miscreg */ + { 0x7f, 0x63, 0x63, 0x83, 0x6b, 0x1b, 0x72, 0xf0, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x59, 0x8d, 0x57, 0x32, 0x00, 0x57, 0x73, 0xe3, + 0xff }, /* crtc_regs */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x01, 0x00, 0x0f, 0x00 }, /* actl_regs */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */ + }, +}; + + +/**************************************************************** + * Palette definitions + ****************************************************************/ + +/* Mono */ +static u8 palette0[] VAR16 = { + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, + 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, + 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, + 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, + 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, + 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, + 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, + 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, + 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f +}; + +static u8 palette1[] VAR16 = { + 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, + 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a, + 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, + 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a, + 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, + 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f, + 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, + 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f, + 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, + 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a, + 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, + 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a, + 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, + 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f, + 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, + 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f +}; + +static u8 palette2[] VAR16 = { + 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, + 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x2a,0x00, 0x2a,0x2a,0x2a, + 0x00,0x00,0x15, 0x00,0x00,0x3f, 0x00,0x2a,0x15, 0x00,0x2a,0x3f, + 0x2a,0x00,0x15, 0x2a,0x00,0x3f, 0x2a,0x2a,0x15, 0x2a,0x2a,0x3f, + 0x00,0x15,0x00, 0x00,0x15,0x2a, 0x00,0x3f,0x00, 0x00,0x3f,0x2a, + 0x2a,0x15,0x00, 0x2a,0x15,0x2a, 0x2a,0x3f,0x00, 0x2a,0x3f,0x2a, + 0x00,0x15,0x15, 0x00,0x15,0x3f, 0x00,0x3f,0x15, 0x00,0x3f,0x3f, + 0x2a,0x15,0x15, 0x2a,0x15,0x3f, 0x2a,0x3f,0x15, 0x2a,0x3f,0x3f, + 0x15,0x00,0x00, 0x15,0x00,0x2a, 0x15,0x2a,0x00, 0x15,0x2a,0x2a, + 0x3f,0x00,0x00, 0x3f,0x00,0x2a, 0x3f,0x2a,0x00, 0x3f,0x2a,0x2a, + 0x15,0x00,0x15, 0x15,0x00,0x3f, 0x15,0x2a,0x15, 0x15,0x2a,0x3f, + 0x3f,0x00,0x15, 0x3f,0x00,0x3f, 0x3f,0x2a,0x15, 0x3f,0x2a,0x3f, + 0x15,0x15,0x00, 0x15,0x15,0x2a, 0x15,0x3f,0x00, 0x15,0x3f,0x2a, + 0x3f,0x15,0x00, 0x3f,0x15,0x2a, 0x3f,0x3f,0x00, 0x3f,0x3f,0x2a, + 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, + 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f +}; + +static u8 palette3[] VAR16 = { + 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, + 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a, + 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, + 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f, + 0x00,0x00,0x00, 0x05,0x05,0x05, 0x08,0x08,0x08, 0x0b,0x0b,0x0b, + 0x0e,0x0e,0x0e, 0x11,0x11,0x11, 0x14,0x14,0x14, 0x18,0x18,0x18, + 0x1c,0x1c,0x1c, 0x20,0x20,0x20, 0x24,0x24,0x24, 0x28,0x28,0x28, + 0x2d,0x2d,0x2d, 0x32,0x32,0x32, 0x38,0x38,0x38, 0x3f,0x3f,0x3f, + 0x00,0x00,0x3f, 0x10,0x00,0x3f, 0x1f,0x00,0x3f, 0x2f,0x00,0x3f, + 0x3f,0x00,0x3f, 0x3f,0x00,0x2f, 0x3f,0x00,0x1f, 0x3f,0x00,0x10, + 0x3f,0x00,0x00, 0x3f,0x10,0x00, 0x3f,0x1f,0x00, 0x3f,0x2f,0x00, + 0x3f,0x3f,0x00, 0x2f,0x3f,0x00, 0x1f,0x3f,0x00, 0x10,0x3f,0x00, + 0x00,0x3f,0x00, 0x00,0x3f,0x10, 0x00,0x3f,0x1f, 0x00,0x3f,0x2f, + 0x00,0x3f,0x3f, 0x00,0x2f,0x3f, 0x00,0x1f,0x3f, 0x00,0x10,0x3f, + 0x1f,0x1f,0x3f, 0x27,0x1f,0x3f, 0x2f,0x1f,0x3f, 0x37,0x1f,0x3f, + 0x3f,0x1f,0x3f, 0x3f,0x1f,0x37, 0x3f,0x1f,0x2f, 0x3f,0x1f,0x27, + + 0x3f,0x1f,0x1f, 0x3f,0x27,0x1f, 0x3f,0x2f,0x1f, 0x3f,0x37,0x1f, + 0x3f,0x3f,0x1f, 0x37,0x3f,0x1f, 0x2f,0x3f,0x1f, 0x27,0x3f,0x1f, + 0x1f,0x3f,0x1f, 0x1f,0x3f,0x27, 0x1f,0x3f,0x2f, 0x1f,0x3f,0x37, + 0x1f,0x3f,0x3f, 0x1f,0x37,0x3f, 0x1f,0x2f,0x3f, 0x1f,0x27,0x3f, + 0x2d,0x2d,0x3f, 0x31,0x2d,0x3f, 0x36,0x2d,0x3f, 0x3a,0x2d,0x3f, + 0x3f,0x2d,0x3f, 0x3f,0x2d,0x3a, 0x3f,0x2d,0x36, 0x3f,0x2d,0x31, + 0x3f,0x2d,0x2d, 0x3f,0x31,0x2d, 0x3f,0x36,0x2d, 0x3f,0x3a,0x2d, + 0x3f,0x3f,0x2d, 0x3a,0x3f,0x2d, 0x36,0x3f,0x2d, 0x31,0x3f,0x2d, + 0x2d,0x3f,0x2d, 0x2d,0x3f,0x31, 0x2d,0x3f,0x36, 0x2d,0x3f,0x3a, + 0x2d,0x3f,0x3f, 0x2d,0x3a,0x3f, 0x2d,0x36,0x3f, 0x2d,0x31,0x3f, + 0x00,0x00,0x1c, 0x07,0x00,0x1c, 0x0e,0x00,0x1c, 0x15,0x00,0x1c, + 0x1c,0x00,0x1c, 0x1c,0x00,0x15, 0x1c,0x00,0x0e, 0x1c,0x00,0x07, + 0x1c,0x00,0x00, 0x1c,0x07,0x00, 0x1c,0x0e,0x00, 0x1c,0x15,0x00, + 0x1c,0x1c,0x00, 0x15,0x1c,0x00, 0x0e,0x1c,0x00, 0x07,0x1c,0x00, + 0x00,0x1c,0x00, 0x00,0x1c,0x07, 0x00,0x1c,0x0e, 0x00,0x1c,0x15, + 0x00,0x1c,0x1c, 0x00,0x15,0x1c, 0x00,0x0e,0x1c, 0x00,0x07,0x1c, + + 0x0e,0x0e,0x1c, 0x11,0x0e,0x1c, 0x15,0x0e,0x1c, 0x18,0x0e,0x1c, + 0x1c,0x0e,0x1c, 0x1c,0x0e,0x18, 0x1c,0x0e,0x15, 0x1c,0x0e,0x11, + 0x1c,0x0e,0x0e, 0x1c,0x11,0x0e, 0x1c,0x15,0x0e, 0x1c,0x18,0x0e, + 0x1c,0x1c,0x0e, 0x18,0x1c,0x0e, 0x15,0x1c,0x0e, 0x11,0x1c,0x0e, + 0x0e,0x1c,0x0e, 0x0e,0x1c,0x11, 0x0e,0x1c,0x15, 0x0e,0x1c,0x18, + 0x0e,0x1c,0x1c, 0x0e,0x18,0x1c, 0x0e,0x15,0x1c, 0x0e,0x11,0x1c, + 0x14,0x14,0x1c, 0x16,0x14,0x1c, 0x18,0x14,0x1c, 0x1a,0x14,0x1c, + 0x1c,0x14,0x1c, 0x1c,0x14,0x1a, 0x1c,0x14,0x18, 0x1c,0x14,0x16, + 0x1c,0x14,0x14, 0x1c,0x16,0x14, 0x1c,0x18,0x14, 0x1c,0x1a,0x14, + 0x1c,0x1c,0x14, 0x1a,0x1c,0x14, 0x18,0x1c,0x14, 0x16,0x1c,0x14, + 0x14,0x1c,0x14, 0x14,0x1c,0x16, 0x14,0x1c,0x18, 0x14,0x1c,0x1a, + 0x14,0x1c,0x1c, 0x14,0x1a,0x1c, 0x14,0x18,0x1c, 0x14,0x16,0x1c, + 0x00,0x00,0x10, 0x04,0x00,0x10, 0x08,0x00,0x10, 0x0c,0x00,0x10, + 0x10,0x00,0x10, 0x10,0x00,0x0c, 0x10,0x00,0x08, 0x10,0x00,0x04, + 0x10,0x00,0x00, 0x10,0x04,0x00, 0x10,0x08,0x00, 0x10,0x0c,0x00, + 0x10,0x10,0x00, 0x0c,0x10,0x00, 0x08,0x10,0x00, 0x04,0x10,0x00, + + 0x00,0x10,0x00, 0x00,0x10,0x04, 0x00,0x10,0x08, 0x00,0x10,0x0c, + 0x00,0x10,0x10, 0x00,0x0c,0x10, 0x00,0x08,0x10, 0x00,0x04,0x10, + 0x08,0x08,0x10, 0x0a,0x08,0x10, 0x0c,0x08,0x10, 0x0e,0x08,0x10, + 0x10,0x08,0x10, 0x10,0x08,0x0e, 0x10,0x08,0x0c, 0x10,0x08,0x0a, + 0x10,0x08,0x08, 0x10,0x0a,0x08, 0x10,0x0c,0x08, 0x10,0x0e,0x08, + 0x10,0x10,0x08, 0x0e,0x10,0x08, 0x0c,0x10,0x08, 0x0a,0x10,0x08, + 0x08,0x10,0x08, 0x08,0x10,0x0a, 0x08,0x10,0x0c, 0x08,0x10,0x0e, + 0x08,0x10,0x10, 0x08,0x0e,0x10, 0x08,0x0c,0x10, 0x08,0x0a,0x10, + 0x0b,0x0b,0x10, 0x0c,0x0b,0x10, 0x0d,0x0b,0x10, 0x0f,0x0b,0x10, + 0x10,0x0b,0x10, 0x10,0x0b,0x0f, 0x10,0x0b,0x0d, 0x10,0x0b,0x0c, + 0x10,0x0b,0x0b, 0x10,0x0c,0x0b, 0x10,0x0d,0x0b, 0x10,0x0f,0x0b, + 0x10,0x10,0x0b, 0x0f,0x10,0x0b, 0x0d,0x10,0x0b, 0x0c,0x10,0x0b, + 0x0b,0x10,0x0b, 0x0b,0x10,0x0c, 0x0b,0x10,0x0d, 0x0b,0x10,0x0f, + 0x0b,0x10,0x10, 0x0b,0x0f,0x10, 0x0b,0x0d,0x10, 0x0b,0x0c,0x10, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00 +}; + + +/**************************************************************** + * Video mode list + ****************************************************************/ + +#define PAL(x) x, sizeof(x) +#define VPARAM(x) &video_param_table[x] + +static struct vgamode_s vga_modes[] VAR16 = { + //mode vparam model bits sstart pelm dac + {0x00, VPARAM(0x17), CTEXT, 4, SEG_CTEXT, 0xFF, PAL(palette2)}, + {0x01, VPARAM(0x17), CTEXT, 4, SEG_CTEXT, 0xFF, PAL(palette2)}, + {0x02, VPARAM(0x18), CTEXT, 4, SEG_CTEXT, 0xFF, PAL(palette2)}, + {0x03, VPARAM(0x18), CTEXT, 4, SEG_CTEXT, 0xFF, PAL(palette2)}, + {0x04, VPARAM(0x04), CGA, 2, SEG_CTEXT, 0xFF, PAL(palette1)}, + {0x05, VPARAM(0x05), CGA, 2, SEG_CTEXT, 0xFF, PAL(palette1)}, + {0x06, VPARAM(0x06), CGA, 1, SEG_CTEXT, 0xFF, PAL(palette1)}, + {0x07, VPARAM(0x07), MTEXT, 4, SEG_MTEXT, 0xFF, PAL(palette0)}, + {0x0D, VPARAM(0x0d), PLANAR4, 4, SEG_GRAPH, 0xFF, PAL(palette1)}, + {0x0E, VPARAM(0x0e), PLANAR4, 4, SEG_GRAPH, 0xFF, PAL(palette1)}, + {0x0F, VPARAM(0x11), PLANAR1, 1, SEG_GRAPH, 0xFF, PAL(palette0)}, + {0x10, VPARAM(0x12), PLANAR4, 4, SEG_GRAPH, 0xFF, PAL(palette2)}, + {0x11, VPARAM(0x1a), PLANAR1, 1, SEG_GRAPH, 0xFF, PAL(palette2)}, + {0x12, VPARAM(0x1b), PLANAR4, 4, SEG_GRAPH, 0xFF, PAL(palette2)}, + {0x13, VPARAM(0x1c), LINEAR8, 8, SEG_GRAPH, 0xFF, PAL(palette3)}, + {0x6A, VPARAM(0x1d), PLANAR4, 4, SEG_GRAPH, 0xFF, PAL(palette2)}, +}; + +struct vgamode_s * +find_vga_entry(u8 mode) +{ + int i; + for (i = 0; i < ARRAY_SIZE(vga_modes); i++) { + struct vgamode_s *vmode_g = &vga_modes[i]; + if (GET_GLOBAL(vmode_g->svgamode) == mode) + return vmode_g; + } + return NULL; +} + +u16 video_save_pointer_table[14] VAR16; + + +/**************************************************************** + * Static functionality table + ****************************************************************/ + +u8 static_functionality[0x10] VAR16 = { + /* 0 */ 0xff, // All modes supported #1 + /* 1 */ 0xe0, // All modes supported #2 + /* 2 */ 0x0f, // All modes supported #3 + /* 3 */ 0x00, 0x00, 0x00, 0x00, // reserved + /* 7 */ 0x07, // 200, 350, 400 scan lines + /* 8 */ 0x02, // mamimum number of visible charsets in text mode + /* 9 */ 0x08, // total number of charset blocks in text mode + /* a */ 0xe7, // Change to add new functions + /* b */ 0x0c, // Change to add new functions + /* c */ 0x00, // reserved + /* d */ 0x00, // reserved + /* e */ 0x00, // Change to add new functions + /* f */ 0x00 // reserved +}; diff --git a/bios/seabios/vgasrc/vgatables.h b/bios/seabios/vgasrc/vgatables.h new file mode 100644 index 0000000..1e76b3a --- /dev/null +++ b/bios/seabios/vgasrc/vgatables.h @@ -0,0 +1,217 @@ +#ifndef __VGATABLES_H +#define __VGATABLES_H + +#include "types.h" // u8 +#include "farptr.h" // struct segoff_s + +/* + * + * VGA registers + * + */ +#define VGAREG_ACTL_ADDRESS 0x3c0 +#define VGAREG_ACTL_WRITE_DATA 0x3c0 +#define VGAREG_ACTL_READ_DATA 0x3c1 + +#define VGAREG_INPUT_STATUS 0x3c2 +#define VGAREG_WRITE_MISC_OUTPUT 0x3c2 +#define VGAREG_VIDEO_ENABLE 0x3c3 +#define VGAREG_SEQU_ADDRESS 0x3c4 +#define VGAREG_SEQU_DATA 0x3c5 + +#define VGAREG_PEL_MASK 0x3c6 +#define VGAREG_DAC_STATE 0x3c7 +#define VGAREG_DAC_READ_ADDRESS 0x3c7 +#define VGAREG_DAC_WRITE_ADDRESS 0x3c8 +#define VGAREG_DAC_DATA 0x3c9 + +#define VGAREG_READ_FEATURE_CTL 0x3ca +#define VGAREG_READ_MISC_OUTPUT 0x3cc + +#define VGAREG_GRDC_ADDRESS 0x3ce +#define VGAREG_GRDC_DATA 0x3cf + +#define VGAREG_MDA_CRTC_ADDRESS 0x3b4 +#define VGAREG_MDA_CRTC_DATA 0x3b5 +#define VGAREG_VGA_CRTC_ADDRESS 0x3d4 +#define VGAREG_VGA_CRTC_DATA 0x3d5 + +#define VGAREG_MDA_WRITE_FEATURE_CTL 0x3ba +#define VGAREG_VGA_WRITE_FEATURE_CTL 0x3da +#define VGAREG_ACTL_RESET 0x3da + +#define VGAREG_MDA_MODECTL 0x3b8 +#define VGAREG_CGA_MODECTL 0x3d8 +#define VGAREG_CGA_PALETTE 0x3d9 + +/* Video memory */ +#define SEG_GRAPH 0xA000 +#define SEG_CTEXT 0xB800 +#define SEG_MTEXT 0xB000 + +/* + * Tables of default values for each mode + */ +#define TEXT 0x80 + +#define CTEXT (0x00 | TEXT) +#define MTEXT (0x01 | TEXT) +#define CGA 0x02 +#define PLANAR1 0x03 +#define PLANAR4 0x04 +#define LINEAR8 0x05 + +// for SVGA +#define LINEAR15 0x10 +#define LINEAR16 0x11 +#define LINEAR24 0x12 +#define LINEAR32 0x13 + +#define SCREEN_IO_START(x,y,p) (((((x)*(y)) | 0x00ff) + 1) * (p)) +#define SCREEN_MEM_START(x,y,p) SCREEN_IO_START(((x)*2),(y),(p)) + +/* standard BIOS Video Parameter Table */ +struct VideoParam_s { + u8 twidth; + u8 theightm1; + u8 cheight; + u16 slength; + u8 sequ_regs[4]; + u8 miscreg; + u8 crtc_regs[25]; + u8 actl_regs[20]; + u8 grdc_regs[9]; +} PACKED; + +struct vgamode_s { + u8 svgamode; + struct VideoParam_s *vparam; + u8 memmodel; /* CTEXT,MTEXT,CGA,PL1,PL2,PL4,P8,P15,P16,P24,P32 */ + u8 pixbits; + u16 sstart; + u8 pelmask; + u8 *dac; + u16 dacsize; +}; + +struct saveVideoHardware { + u8 sequ_index; + u8 crtc_index; + u8 grdc_index; + u8 actl_index; + u8 feature; + u8 sequ_regs[4]; + u8 sequ0; + u8 crtc_regs[25]; + u8 actl_regs[20]; + u8 grdc_regs[9]; + u16 crtc_addr; + u8 plane_latch[4]; +}; + +struct saveBDAstate { + u8 video_mode; + u16 video_cols; + u16 video_pagesize; + u16 crtc_address; + u8 video_rows; + u16 char_height; + u8 video_ctl; + u8 video_switches; + u8 modeset_ctl; + u16 cursor_type; + u16 cursor_pos[8]; + u16 video_pagestart; + u8 video_page; + /* current font */ + struct segoff_s font0; + struct segoff_s font1; +}; + +struct saveDACcolors { + u8 rwmode; + u8 peladdr; + u8 pelmask; + u8 dac[768]; + u8 color_select; +}; + +// vgatables.c +struct vgamode_s *find_vga_entry(u8 mode); +extern u16 video_save_pointer_table[]; +extern struct VideoParam_s video_param_table[]; +extern u8 static_functionality[]; + +// vgafonts.c +extern u8 vgafont8[]; +extern u8 vgafont14[]; +extern u8 vgafont16[]; +extern u8 vgafont14alt[]; +extern u8 vgafont16alt[]; + +// vga.c +struct carattr { + u8 car, attr, use_attr; +}; +struct cursorpos { + u8 x, y, page; +}; + +// vgafb.c +void clear_screen(struct vgamode_s *vmode_g); +void vgafb_scroll(int nblines, int attr + , struct cursorpos ul, struct cursorpos lr); +void vgafb_write_char(struct cursorpos cp, struct carattr ca); +struct carattr vgafb_read_char(struct cursorpos cp); +void vgafb_write_pixel(u8 color, u16 x, u16 y); +u8 vgafb_read_pixel(u16 x, u16 y); +void vgafb_load_font(u16 seg, void *src_far, u16 count + , u16 start, u8 destflags, u8 fontsize); + +// vgaio.c +void vgahw_screen_disable(void); +void vgahw_screen_enable(void); +void vgahw_set_border_color(u8 color); +void vgahw_set_overscan_border_color(u8 color); +u8 vgahw_get_overscan_border_color(void); +void vgahw_set_palette(u8 palid); +void vgahw_set_single_palette_reg(u8 reg, u8 val); +u8 vgahw_get_single_palette_reg(u8 reg); +void vgahw_set_all_palette_reg(u16 seg, u8 *data_far); +void vgahw_get_all_palette_reg(u16 seg, u8 *data_far); +void vgahw_toggle_intensity(u8 flag); +void vgahw_select_video_dac_color_page(u8 flag, u8 data); +void vgahw_read_video_dac_state(u8 *pmode, u8 *curpage); +void vgahw_set_dac_regs(u16 seg, u8 *data_far, u8 start, int count); +void vgahw_get_dac_regs(u16 seg, u8 *data_far, u8 start, int count); +void vgahw_set_pel_mask(u8 val); +u8 vgahw_get_pel_mask(void); +void vgahw_save_dac_state(u16 seg, struct saveDACcolors *info); +void vgahw_restore_dac_state(u16 seg, struct saveDACcolors *info); +void vgahw_sequ_write(u8 index, u8 value); +void vgahw_grdc_write(u8 index, u8 value); +void vgahw_set_text_block_specifier(u8 spec); +void get_font_access(void); +void release_font_access(void); +void vgahw_set_cursor_shape(u8 start, u8 end); +void vgahw_set_active_page(u16 address); +void vgahw_set_cursor_pos(u16 address); +void vgahw_set_scan_lines(u8 lines); +u16 vgahw_get_vde(void); +void vgahw_save_state(u16 seg, struct saveVideoHardware *info); +void vgahw_restore_state(u16 seg, struct saveVideoHardware *info); +void vgahw_set_mode(struct VideoParam_s *vparam_g); +void vgahw_enable_video_addressing(u8 disable); +void vgahw_init(void); + +// clext.c +void cirrus_set_video_mode(u8 mode); +void cirrus_init(void); + +// vbe.c -- not implemented yet. +#define VBE_DISPI_DISABLED 0x00 +void dispi_set_enable(int enable); +void vbe_init(void); +int vbe_has_vbe_display(void); + +#endif // vgatables.h