x86: source code to build two binaries: bios.bin and vgabios-cirrus.bin,
which are required for x86 emulation in the Android x86 emulator.
Change-Id: I0e3b59ad67df20a690504336bdafe7b22bc7fb3f
Signed-off-by: Xiaohui Xin <xiaohui.xin@intel.com>
Signed-off-by: Jun Nakajima <jun.nakajima@intel.com>
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..20a227e
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,50 @@
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# this is a set of definitions that allow the usage of Makefile.android
+# even if we're not using the Android build system.
+#
+
+CC := gcc
+BCC := bcc
+AS86 ;= as86
+MAKE := make
+CP := cp
+
+all: bios.bin vgabios-cirrus.bin
+
+bochs/bios/Makefile:
+ cd bochs && ./configure
+
+bios.bin: bochs/bios/Makefile
+ $(MAKE) -C bochs/bios
+ $(CP) bochs/bios/rombios16.bin $@
+
+vgabios-cirrus.bin:
+ $(MAKE) -C vgabios
+ $(CP) vgabios/VGABIOS-lgpl-latest.cirrus.bin $@
+
+clean:
+ rm -rf bochs/Makefile bochs/build bochs/config.h bochs/config.log \
+ bochs/config.status bochs/instrument bochs/ltdlconf.h
+ $(MAKE) -C bochs/bios bios-clean
+ $(MAKE) -C bochs/bios dist-clean
+ $(MAKE) -C vgabios bios-clean
+ $(MAKE) -C vgabios dist-clean
+ rm -rf bios.bin vgabios-cirrus.bin
+
+
+
+
diff --git a/README b/README
new file mode 100644
index 0000000..9fb7113
--- /dev/null
+++ b/README
@@ -0,0 +1,52 @@
+This project has the source code to build two binaries: bios.bin and
+vgabios-cirrus.bin, which are required for x86 emulation in the
+Android emulator: platform/external/qemu.
+
+
+SOURCE CODE
+
++ bios.bin: git://git.kernel.org/pub/scm/virt/bochs/bochs.git
+
+ The file bios.bin is actually rombios16.bin, which is built from
+bochs/bios. We used the following commit in the bochs git tree so that
+it can match with the qemu tree in platform/external/qemu:
+
+ commit 04387139e3b5ac97b5633cd40b3d87cdf45efd6c
+ Author: sshwarts <sshwarts>
+ Date: Mon Feb 9 19:46:34 2009 +0000
+
+ Fixed compilation error + x86-64 correctness fix
+
+ Since our purpose is to build only rombios16.bin, we populated part
+of the bochs tree in the git tree above.
+
++ vgabios-cirrus.bin: git://git.kernel.org/pub/scm/virt/vgabios/vgabios.git
+
+ The file vgabios-cirrus.bin is VGABIOS-lgpl-latest.cirrus.bin, which
+is built by the tree, and we used the following commit.
+
+ commit 33636cbdd93da79c903b91b50ae087bb814b9332
+ Author: vruppert <vruppert>
+ Date: Mon Jan 31 17:28:09 2011 +0000
+
+ - added HDTV resolutions (patch by Tristan Schmelcher)
+
+TOOLS REQUIRED TO BUILD
+
+ The build requires dev86 rpm or bin86 & bcc debs version >= 0.16.14.
+(visit http://www.debath.co.uk/dev86/ for more information)
+
+HOW TO BUILD
+
+ Just run make like,
+ $ make
+
+ To clean up,
+ $ make clean
+
+OUTPUT
+
+ The two binaries rombios16.bin and VGABIOS-lgpl-latest.cirrus.binare
+copied from the directories accordingly, and renamed to bios.bin and
+vgabios-cirrus.bin.
+
diff --git a/bochs/COPYING b/bochs/COPYING
new file mode 100644
index 0000000..654ead3
--- /dev/null
+++ b/bochs/COPYING
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+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 this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. 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 not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+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
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the 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
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/bochs/Makefile.in b/bochs/Makefile.in
new file mode 100644
index 0000000..5227d74
--- /dev/null
+++ b/bochs/Makefile.in
@@ -0,0 +1,739 @@
+# Copyright (C) 2002 MandrakeSoft S.A.
+#
+# MandrakeSoft S.A.
+# 43, rue d'Aboukir
+# 75002 Paris - France
+# http://www.linux-mandrake.com/
+# http://www.mandrakesoft.com/
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+####################################################
+# NOTE: To be compatibile with nmake (microsoft vc++) please follow
+# the following rules:
+# use $(VAR) not ${VAR}
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+srcdir = @srcdir@
+VPATH = @srcdir@
+bindir = @bindir@
+libdir = @libdir@
+plugdir = @libdir@/bochs/plugins
+datarootdir = @datarootdir@
+mandir = @mandir@
+man1dir = $(mandir)/man1
+man5dir = $(mandir)/man5
+docdir = $(datarootdir)/doc/bochs
+sharedir = $(datarootdir)/bochs
+top_builddir = .
+top_srcdir = $(srcdir)
+
+DESTDIR =
+
+VERSION=@VERSION@
+VER_STRING=@VER_STRING@
+REL_STRING=@REL_STRING@
+MAN_PAGE_1_LIST=bochs bximage bxcommit bochs-dlx
+MAN_PAGE_5_LIST=bochsrc
+INSTALL_LIST_SHARE=bios/BIOS-bochs-* bios/VGABIOS* @INSTALL_LIST_FOR_PLATFORM@
+INSTALL_LIST_DOC=CHANGES COPYING README TODO
+INSTALL_LIST_BIN=bochs@EXE@ bximage@EXE@ bxcommit@EXE@
+INSTALL_LIST_BIN_OPTIONAL=bochsdbg@EXE@
+INSTALL_LIST_WIN32=$(INSTALL_LIST_SHARE) $(INSTALL_LIST_DOC) $(INSTALL_LIST_BIN) $(INSTALL_LIST_BIN_OPTIONAL) niclist@EXE@
+INSTALL_LIST_MACOSX=$(INSTALL_LIST_SHARE) $(INSTALL_LIST_DOC) bochs.scpt
+# for win32 and macosx, these files get renamed to *.txt in install process
+TEXT_FILE_LIST=README CHANGES COPYING TODO VGABIOS-elpin-LICENSE VGABIOS-lgpl-README
+CP=cp
+CAT=cat
+RM=rm
+MV=mv
+LN_S=ln -sf
+DLXLINUX_TAR=dlxlinux4.tar.gz
+DLXLINUX_TAR_URL=http://bochs.sourceforge.net/guestos/$(DLXLINUX_TAR)
+DLXLINUX_ROMFILE=BIOS-bochs-latest
+GUNZIP=gunzip
+WGET=@WGET@
+SED=sed
+MKDIR=mkdir
+RMDIR=rmdir
+TAR=tar
+CHMOD=chmod
+# the GZIP variable is reserved by gzip program
+GZIP_BIN=gzip -9
+GUNZIP=gunzip
+ZIP=zip
+UNIX2DOS=unix2dos
+LIBTOOL=@LIBTOOL@
+DLLTOOL=dlltool
+RC_CMD=@RC_CMD@
+
+@SUFFIX_LINE@
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+SHELL = /bin/sh
+
+@SET_MAKE@
+
+CC = @CC@
+CXX = @CXX@
+CFLAGS = @CFLAGS@ @GUI_CFLAGS@ $(MCH_CFLAGS) $(FLA_FLAGS) @DEFINE_PLUGIN_PATH@ -DBX_SHARE_PATH='"$(sharedir)"'
+CXXFLAGS = @CXXFLAGS@ @GUI_CXXFLAGS@ $(MCH_CFLAGS) $(FLA_FLAGS) @DEFINE_PLUGIN_PATH@ -DBX_SHARE_PATH='"$(sharedir)"'
+
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+# To compile with readline:
+# linux needs just -lreadline
+# solaris needs -lreadline -lcurses
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+XPM_LIB = @XPM_LIB@
+GUI_LINK_OPTS_X = $(X_LIBS) $(X_PRE_LIBS) -lX11 $(XPM_LIB)
+GUI_LINK_OPTS_SDL = `sdl-config --cflags --libs`
+GUI_LINK_OPTS_SVGA = -lvga -lvgagl
+GUI_LINK_OPTS_BEOS = -lbe
+GUI_LINK_OPTS_RFB = @RFB_LIBS@
+GUI_LINK_OPTS_AMIGAOS =
+GUI_LINK_OPTS_WIN32 = -luser32 -lgdi32 -lcomdlg32 -lcomctl32 -lwsock32 -lshell32
+GUI_LINK_OPTS_WIN32_VCPP = user32.lib gdi32.lib winmm.lib \
+ comdlg32.lib comctl32.lib wsock32.lib advapi32.lib shell32.lib
+GUI_LINK_OPTS_MACOS =
+GUI_LINK_OPTS_CARBON = -framework Carbon
+GUI_LINK_OPTS_NOGUI =
+GUI_LINK_OPTS_TERM = @GUI_LINK_OPTS_TERM@
+GUI_LINK_OPTS_WX = @GUI_LINK_OPTS_WX@
+GUI_LINK_OPTS = @GUI_LINK_OPTS@ @DEVICE_LINK_OPTS@
+RANLIB = @RANLIB@
+
+CFLAGS_CONSOLE = @CFLAGS@ $(MCH_CFLAGS) $(FLA_FLAGS)
+CXXFLAGS_CONSOLE = @CXXFLAGS@ $(MCH_CFLAGS) $(FLA_FLAGS)
+BXIMAGE_LINK_OPTS = @BXIMAGE_LINK_OPTS@
+
+BX_INCDIRS = -I. -I$(srcdir)/. -I@INSTRUMENT_DIR@ -I$(srcdir)/@INSTRUMENT_DIR@
+
+#SUBDIRS = iodev bx_debug
+
+#all install uninstall: config.h#
+# for subdir in $(SUBDIRS); do #
+# echo making $@ in $$subdir; #
+# ($(MAKE) -C $$subdir $(MDEFINES) $@) || exit 1; #
+# done#
+
+
+
+# gnu flags for clean up
+#CFLAGS = -ansi -O -g -Wunused -Wuninitialized
+
+
+NONINLINE_OBJS = \
+ logio.o \
+ main.o \
+ config.o \
+ load32bitOShack.o \
+ pc_system.o \
+ osdep.o \
+ plugin.o \
+ crc.o \
+ @EXTRA_BX_OBJS@
+
+EXTERN_ENVIRONMENT_OBJS = \
+ main.o \
+ config.o \
+ load32bitOShack.o \
+ pc_system.o
+
+DEBUGGER_LIB = bx_debug/libdebug.a
+DISASM_LIB = disasm/libdisasm.a
+INSTRUMENT_LIB = @INSTRUMENT_DIR@/libinstrument.a
+FPU_LIB = fpu/libfpu.a
+READLINE_LIB = @READLINE_LIB@
+EXTRA_LINK_OPTS = @EXTRA_LINK_OPTS@
+
+GDBSTUB_OBJS = gdbstub.o
+
+BX_OBJS = @NONINLINE_VAR@
+
+BX_INCLUDES = bochs.h config.h osdep.h
+
+
+.@CPP_SUFFIX@.o:
+ $(CXX) @DASH@c $(BX_INCDIRS) $(CXXFLAGS) @CXXFP@$< @OFP@$@
+.c.o:
+ $(CC) @DASH@c $(BX_INCDIRS) $(CFLAGS) $(FPU_FLAGS) $< @OFP@$@
+
+
+all: @PRIMARY_TARGET@ @PLUGIN_TARGET@ bximage@EXE@ bxcommit@EXE@ @BUILD_DOCBOOK_VAR@
+
+@EXTERNAL_DEPENDENCY@
+
+bochs@EXE@: @IODEV_LIB_VAR@ @DEBUGGER_VAR@ \
+ cpu/libcpu.a memory/libmemory.a gui/libgui.a \
+ @DISASM_VAR@ @INSTRUMENT_VAR@ $(BX_OBJS) \
+ $(SIMX86_OBJS) @FPU_VAR@ @GDBSTUB_VAR@ @PLUGIN_VAR@
+ @LINK@ @EXPORT_DYNAMIC@ $(BX_OBJS) $(SIMX86_OBJS) \
+ @IODEV_LIB_VAR@ @DEBUGGER_VAR@ cpu/libcpu.a memory/libmemory.a gui/libgui.a \
+ @DISASM_VAR@ @INSTRUMENT_VAR@ @PLUGIN_VAR@ \
+ @GDBSTUB_VAR@ @FPU_VAR@ \
+ @NONPLUGIN_GUI_LINK_OPTS@ \
+ $(MCH_LINK_FLAGS) \
+ $(SIMX86_LINK_FLAGS) \
+ $(READLINE_LIB) \
+ $(EXTRA_LINK_OPTS) \
+ $(LIBS)
+
+# Special make target for cygwin/mingw using dlltool instead of
+# libtool. This creates a .DEF file, and exports file, an import library,
+# and then links bochs.exe with the exports file.
+.win32_dll_plugin_target: @IODEV_LIB_VAR@ @DEBUGGER_VAR@ \
+ cpu/libcpu.a memory/libmemory.a gui/libgui.a \
+ @DISASM_VAR@ @INSTRUMENT_VAR@ $(BX_OBJS) \
+ $(SIMX86_OBJS) @FPU_VAR@ @GDBSTUB_VAR@ @PLUGIN_VAR@
+ $(DLLTOOL) --export-all-symbols --output-def bochs.def \
+ $(BX_OBJS) $(SIMX86_OBJS) \
+ @IODEV_LIB_VAR@ cpu/libcpu.a memory/libmemory.a gui/libgui.a \
+ @DEBUGGER_VAR@ @DISASM_VAR@ @INSTRUMENT_VAR@ @PLUGIN_VAR@ \
+ @GDBSTUB_VAR@ @FPU_VAR@
+ $(DLLTOOL) --dllname bochs.exe --def bochs.def --output-lib dllexports.a
+ $(DLLTOOL) --dllname bochs.exe --output-exp bochs.exp --def bochs.def
+ $(CXX) -o bochs.exe $(CXXFLAGS) $(LDFLAGS) -export-dynamic \
+ $(BX_OBJS) bochs.exp $(SIMX86_OBJS) \
+ @IODEV_LIB_VAR@ cpu/libcpu.a memory/libmemory.a gui/libgui.a \
+ @DEBUGGER_VAR@ @DISASM_VAR@ @INSTRUMENT_VAR@ @PLUGIN_VAR@ \
+ @GDBSTUB_VAR@ @FPU_VAR@ \
+ $(GUI_LINK_OPTS) \
+ $(MCH_LINK_FLAGS) \
+ $(SIMX86_LINK_FLAGS) \
+ $(READLINE_LIB) \
+ $(EXTRA_LINK_OPTS) \
+ $(LIBS)
+ touch .win32_dll_plugin_target
+
+bochs_plugins:
+ cd gui @COMMAND_SEPARATOR@
+ $(MAKE) plugins
+ @CD_UP_ONE@
+ cd iodev @COMMAND_SEPARATOR@
+ $(MAKE) plugins
+ @CD_UP_ONE@
+
+bximage@EXE@: misc/bximage.o
+ @LINK_CONSOLE@ $(BXIMAGE_LINK_OPTS) misc/bximage.o
+
+bxcommit@EXE@: misc/bxcommit.o
+ @LINK_CONSOLE@ misc/bxcommit.o
+
+niclist@EXE@: misc/niclist.o
+ @LINK_CONSOLE@ misc/niclist.o
+
+# compile with console CXXFLAGS, not gui CXXFLAGS
+misc/bximage.o: $(srcdir)/misc/bximage.c $(srcdir)/iodev/hdimage.h
+ $(CC) @DASH@c $(BX_INCDIRS) $(CFLAGS_CONSOLE) $(srcdir)/misc/bximage.c @OFP@$@
+
+misc/bxcommit.o: $(srcdir)/misc/bxcommit.c $(srcdir)/iodev/hdimage.h
+ $(CC) @DASH@c $(BX_INCDIRS) $(CFLAGS_CONSOLE) $(srcdir)/misc/bxcommit.c @OFP@$@
+
+misc/niclist.o: $(srcdir)/misc/niclist.c
+ $(CC) @DASH@c $(BX_INCDIRS) $(CFLAGS_CONSOLE) $(srcdir)/misc/niclist.c @OFP@$@
+
+$(BX_OBJS): $(BX_INCLUDES)
+
+# cannot use -C option to be compatible with Microsoft nmake
+iodev/libiodev.a::
+ cd iodev @COMMAND_SEPARATOR@
+ $(MAKE) $(MDEFINES) libiodev.a
+ @CD_UP_ONE@
+
+bx_debug/libdebug.a::
+ cd bx_debug @COMMAND_SEPARATOR@
+ $(MAKE) $(MDEFINES) libdebug.a
+ @CD_UP_ONE@
+
+cpu/libcpu.a::
+ cd cpu @COMMAND_SEPARATOR@
+ $(MAKE) $(MDEFINES) libcpu.a
+ @CD_UP_ONE@
+
+memory/libmemory.a::
+ cd memory @COMMAND_SEPARATOR@
+ $(MAKE) $(MDEFINES) libmemory.a
+ @CD_UP_ONE@
+
+gui/libgui.a::
+ cd gui @COMMAND_SEPARATOR@
+ $(MAKE) $(MDEFINES) libgui.a
+ @CD_UP_ONE@
+
+disasm/libdisasm.a::
+ cd disasm @COMMAND_SEPARATOR@
+ $(MAKE) $(MDEFINES) libdisasm.a
+ @CD_UP_ONE@
+
+@INSTRUMENT_DIR@/libinstrument.a::
+ cd @INSTRUMENT_DIR@ @COMMAND_SEPARATOR@
+ $(MAKE) $(MDEFINES) libinstrument.a
+ @CD_UP_TWO@
+
+fpu/libfpu.a::
+ cd fpu @COMMAND_SEPARATOR@
+ $(MAKE) $(MDEFINES) libfpu.a
+ @CD_UP_ONE@
+
+libbochs.a:
+ -rm -f libbochs.a
+ ar rv libbochs.a $(EXTERN_ENVIRONMENT_OBJS)
+ $(RANLIB) libbochs.a
+
+libbochs_cpu.a: @DEBUGGER_VAR@ $(BX_OBJS)
+ -rm -f libbochs_cpu.a
+ ar rv libbochs_cpu.a $(BX_OBJS)
+ $(RANLIB) libbochs_cpu.a
+
+# for wxWidgets port, on win32 platform
+wxbochs_resources.o: wxbochs.rc
+ windres $(srcdir)/wxbochs.rc -o $@ --include-dir=`@WX_CONFIG@ --prefix`/include
+
+# for win32 gui
+win32res.o: win32res.rc bxversion.rc
+ $(RC_CMD)$@ $(srcdir)/win32res.rc
+
+#####################################################################
+# Install target for all platforms.
+#####################################################################
+
+install: all @INSTALL_TARGET@
+
+#####################################################################
+# Install target for win32
+#
+# This is intended to be run in cygwin, since it has better scripting
+# tools.
+#####################################################################
+
+install_win32: download_dlx @INSTALL_DOCBOOK_VAR@
+ -mkdir -p $(prefix)
+ cp obj-release/*.exe .
+ for i in $(INSTALL_LIST_WIN32); do if test -f $$i; then cp $$i $(prefix); else cp $(srcdir)/$$i $(prefix); fi; done
+ cp $(srcdir)/misc/sb16/sb16ctrl.example $(prefix)/sb16ctrl.txt
+ cp $(srcdir)/misc/sb16/sb16ctrl.exe $(prefix)
+ #cat $(srcdir)/build/win32/DOC-win32.htm | $(SED) -e 's/@VERSION@/$(VERSION)/g' > $(prefix)/DOC-win32.htm
+ cp $(srcdir)/.bochsrc $(prefix)/bochsrc-sample.txt
+ -mkdir $(prefix)/keymaps
+ cp $(srcdir)/gui/keymaps/*.map $(prefix)/keymaps
+ cat $(DLXLINUX_TAR) | (cd $(prefix) && tar xzvf -)
+ echo '..\bochs' > $(prefix)/dlxlinux/start.bat
+ dlxrc=$(prefix)/dlxlinux/bochsrc.txt; mv $$dlxrc $$dlxrc.orig && sed < $$dlxrc.orig 's/\/usr\/local\/bochs\/latest/../' > $$dlxrc && rm -f $$dlxrc.orig
+ mv $(prefix)/README $(prefix)/README.orig
+ cat $(srcdir)/build/win32/README.win32-binary $(prefix)/README.orig > $(prefix)/README
+ rm -f $(prefix)/README.orig
+ for i in $(TEXT_FILE_LIST); do mv $(prefix)/$$i $(prefix)/$$i.txt; done
+ cd $(prefix); $(UNIX2DOS) *.txt */*.txt
+ cd $(prefix); NAME=`pwd|$(SED) 's/.*\///'`; (cd ..; $(ZIP) $$NAME.zip -r $$NAME); ls -l ../$$NAME.zip
+
+#####################################################################
+# install target for unix
+#####################################################################
+
+install_unix: install_bin @INSTALL_PLUGINS_VAR@ install_man install_share install_doc @INSTALL_DOCBOOK_VAR@
+
+install_bin::
+ for i in $(DESTDIR)$(bindir); do mkdir -p $$i && test -d $$i && test -w $$i; done
+ for i in $(INSTALL_LIST_BIN); do if test -f $$i; then install $$i $(DESTDIR)$(bindir); else install $(srcdir)/$$i $(DESTDIR)$(bindir); fi; done
+ -for i in $(INSTALL_LIST_BIN_OPTIONAL); do if test -f $$i; then install $$i $(DESTDIR)$(bindir); else install $(srcdir)/$$i $(DESTDIR)$(bindir); fi; done
+
+install_libtool_plugins::
+ for i in $(DESTDIR)$(plugdir); do mkdir -p $$i && test -d $$i && test -w $$i; done
+ list=`cd gui && echo *.la`; for i in $$list; do $(LIBTOOL) --mode=install install gui/$$i $(DESTDIR)$(plugdir); done
+ list=`cd iodev && echo *.la`; for i in $$list; do $(LIBTOOL) --mode=install install iodev/$$i $(DESTDIR)$(plugdir); done
+ $(LIBTOOL) --finish $(DESTDIR)$(plugdir)
+
+install_dll_plugins::
+ for i in $(DESTDIR)$(plugdir); do mkdir -p $$i && test -d $$i && test -w $$i; done
+ list=`cd gui && echo *.dll`; for i in $$list; do cp gui/$$i $(DESTDIR)$(plugdir); done
+ list=`cd iodev && echo *.dll`; for i in $$list; do cp iodev/$$i $(DESTDIR)$(plugdir); done
+
+install_share::
+ for i in $(DESTDIR)$(sharedir); do mkdir -p $$i && test -d $$i && test -w $$i; done
+ for i in $(INSTALL_LIST_SHARE); do if test -f $$i; then install -m 644 $$i $(DESTDIR)$(sharedir); else install -m 644 $(srcdir)/$$i $(DESTDIR)$(sharedir); fi; done
+ -mkdir $(DESTDIR)$(sharedir)/keymaps
+ for i in $(srcdir)/gui/keymaps/*.map; do install -m 644 $$i $(DESTDIR)$(sharedir)/keymaps/; done
+
+install_doc::
+ for i in $(DESTDIR)$(docdir); do mkdir -p $$i && test -d $$i && test -w $$i; done
+ for i in $(INSTALL_LIST_DOC); do if test -f $$i; then install -m 644 $$i $(DESTDIR)$(docdir); else install -m 644 $(srcdir)/$$i $(DESTDIR)$(docdir); fi; done
+ $(RM) -f $(DESTDIR)$(docdir)/README
+ $(CAT) $(srcdir)/build/linux/README.linux-binary $(srcdir)/README > $(DESTDIR)$(docdir)/README
+ install -m 644 $(srcdir)/.bochsrc $(DESTDIR)$(docdir)/bochsrc-sample.txt
+
+
+build_docbook::
+ cd doc/docbook; make
+
+dl_docbook::
+ cd doc/docbook; make dl_docs
+
+install_docbook: build_docbook
+ cd doc/docbook; make install
+
+install_man::
+ -mkdir -p $(DESTDIR)$(man1dir)
+ -mkdir -p $(DESTDIR)$(man5dir)
+ for i in $(MAN_PAGE_1_LIST); do cat $(srcdir)/doc/man/$$i.1 | $(SED) 's/@version@/$(VERSION)/g' | $(GZIP_BIN) -c > $(DESTDIR)$(man1dir)/$$i.1.gz; chmod 644 $(DESTDIR)$(man1dir)/$$i.1.gz; done
+ for i in $(MAN_PAGE_5_LIST); do cat $(srcdir)/doc/man/$$i.5 | $(GZIP_BIN) -c > $(DESTDIR)$(man5dir)/$$i.5.gz; chmod 644 $(DESTDIR)$(man5dir)/$$i.5.gz; done
+
+download_dlx: $(DLXLINUX_TAR)
+
+$(DLXLINUX_TAR):
+ $(RM) -f $(DLXLINUX_TAR)
+ $(WGET) $(DLXLINUX_TAR_URL)
+ test -f $(DLXLINUX_TAR)
+
+unpack_dlx: $(DLXLINUX_TAR)
+ rm -rf dlxlinux
+ $(GUNZIP) -c $(DLXLINUX_TAR) | $(TAR) -xvf -
+ test -d dlxlinux
+ (cd dlxlinux; $(MV) bochsrc.txt bochsrc.txt.orig; $(SED) -e "s/1\.1\.2/$(VERSION)/g" -e 's,/usr/local/bochs/latest,$(prefix)/share/bochs,g' < bochsrc.txt.orig > bochsrc.txt; rm -f bochsrc.txt.orig)
+
+install_dlx:
+ $(RM) -rf $(DESTDIR)$(sharedir)/dlxlinux
+ cp -r dlxlinux $(DESTDIR)$(sharedir)/dlxlinux
+ $(CHMOD) 755 $(DESTDIR)$(sharedir)/dlxlinux
+ $(GZIP_BIN) $(DESTDIR)$(sharedir)/dlxlinux/hd10meg.img
+ $(CHMOD) 644 $(DESTDIR)$(sharedir)/dlxlinux/*
+ for i in bochs-dlx; do cp $(srcdir)/build/linux/$$i $(DESTDIR)$(bindir)/$$i; $(CHMOD) 755 $(DESTDIR)$(bindir)/$$i; done
+
+uninstall::
+ $(RM) -rf $(DESTDIR)$(sharedir)
+ $(RM) -rf $(DESTDIR)$(docdir)
+ $(RM) -rf $(DESTDIR)$(libdir)/bochs
+ for i in bochs bximage bxcommit bochs-dlx; do rm -f $(DESTDIR)$(bindir)/$$i; done
+ for i in $(MAN_PAGE_1_LIST); do $(RM) -f $(man1dir)/$$i.1.gz; done
+ for i in $(MAN_PAGE_5_LIST); do $(RM) -f $(man5dir)/$$i.5.gz; done
+
+V6WORKSPACE_ZIP=build/win32/workspace.zip
+V6WORKSPACE_FILES=bochs.dsw bochs.dsp bochs.opt cpu/cpu.dsp \
+ memory/memory.dsp iodev/iodev.dsp instrument/stubs/stubs.dsp \
+ gui/gui.dsp fpu/fpu.dsp disasm/disasm.dsp bx_debug/bx_debug.dsp \
+ misc/niclist.dsp bximage.dsp bxcommit.dsp
+
+v6workspace:
+ zip $(V6WORKSPACE_ZIP) $(V6WORKSPACE_FILES)
+
+########
+# the win32_snap target is used to create a ZIP of bochs sources configured
+# for VC++. This ZIP is stuck on the website every once in a while to make
+# it easier for VC++ users to compile bochs. First, you should
+# run "sh .conf.win32-vcpp" to configure the source code, then do
+# "make win32_snap" to unzip the workspace files and create the ZIP.
+########
+win32_snap:
+ unzip $(V6WORKSPACE_ZIP)
+ $(SHELL) ./build/win32/cc2cpp
+ $(MAKE) zip
+ $(SHELL) ./build/win32/cpp2cc
+
+tar:
+ NAME=`pwd|$(SED) 's/.*\///'`; (cd ..; $(RM) -f $$NAME.zip; tar cf - $$NAME | $(GZIP_BIN) > $$NAME.tar.gz); ls -l ../$$NAME.tar.gz
+
+zip:
+ NAME=`pwd|$(SED) 's/.*\///'`; (cd ..; $(RM) -f $$NAME.zip; $(ZIP) $$NAME.zip -r $$NAME -x \*CVS\* -x \*.cvsignore ); ls -l ../$$NAME.zip
+
+clean:
+ @RMCOMMAND@ *.o
+ @RMCOMMAND@ *.a
+ @RMCOMMAND@ bochs
+ @RMCOMMAND@ bochs.exe
+ @RMCOMMAND@ bximage
+ @RMCOMMAND@ bximage.exe
+ @RMCOMMAND@ bxcommit
+ @RMCOMMAND@ bxcommit.exe
+ @RMCOMMAND@ niclist
+ @RMCOMMAND@ niclist.exe
+ @RMCOMMAND@ bochs.out
+ @RMCOMMAND@ bochsout.txt
+ @RMCOMMAND@ bochs.exp
+ @RMCOMMAND@ bochs.def
+ @RMCOMMAND@ bochs.scpt
+ @RMCOMMAND@ -rf bochs.app
+ @RMCOMMAND@ -rf .libs
+ @RMCOMMAND@ .win32_dll_plugin_target
+
+local-dist-clean: clean
+ @RMCOMMAND@ config.h config.status config.log config.cache
+ @RMCOMMAND@ .dummy `find . -name '*.dsp' -o -name '*.dsw' -o -name '*.opt' -o -name '.DS_Store'`
+ @RMCOMMAND@ bxversion.h build/linux/bochs-dlx _rpm_top *.rpm
+ @RMCOMMAND@ build/win32/nsis/Makefile build/win32/nsis/bochs.nsi
+ @RMCOMMAND@ build/macosx/Info.plist build/macosx/script_compiled.rsrc
+ @RMCOMMAND@ libtool
+ @RMCOMMAND@ ltdlconf.h
+
+all-clean: clean
+ cd iodev @COMMAND_SEPARATOR@
+ $(MAKE) clean
+ @CD_UP_ONE@
+ cd bx_debug @COMMAND_SEPARATOR@
+ $(MAKE) clean
+ @CD_UP_ONE@
+ cd cpu @COMMAND_SEPARATOR@
+ $(MAKE) clean
+ @CD_UP_ONE@
+ cd memory @COMMAND_SEPARATOR@
+ $(MAKE) clean
+ @CD_UP_ONE@
+ cd gui @COMMAND_SEPARATOR@
+ $(MAKE) clean
+ @CD_UP_ONE@
+ cd disasm @COMMAND_SEPARATOR@
+ $(MAKE) clean
+ @CD_UP_ONE@
+ cd @INSTRUMENT_DIR@ @COMMAND_SEPARATOR@
+ $(MAKE) clean
+ @CD_UP_TWO@
+ cd misc @COMMAND_SEPARATOR@
+ $(MAKE) clean
+ @CD_UP_ONE@
+ cd fpu @COMMAND_SEPARATOR@
+ $(MAKE) clean
+ @CD_UP_ONE@
+ cd doc/docbook @COMMAND_SEPARATOR@
+ $(MAKE) clean
+ @CD_UP_TWO@
+ cd host/linux/pcidev @COMMAND_SEPARATOR@
+ $(MAKE) clean
+ @CD_UP_THREE@
+
+dist-clean: local-dist-clean
+ cd iodev @COMMAND_SEPARATOR@
+ $(MAKE) dist-clean
+ @CD_UP_ONE@
+ cd bx_debug @COMMAND_SEPARATOR@
+ $(MAKE) dist-clean
+ @CD_UP_ONE@
+ cd bios @COMMAND_SEPARATOR@
+ $(MAKE) dist-clean
+ @CD_UP_ONE@
+ cd cpu @COMMAND_SEPARATOR@
+ $(MAKE) dist-clean
+ @CD_UP_ONE@
+ cd memory @COMMAND_SEPARATOR@
+ $(MAKE) dist-clean
+ @CD_UP_ONE@
+ cd gui @COMMAND_SEPARATOR@
+ $(MAKE) dist-clean
+ @CD_UP_ONE@
+ cd disasm @COMMAND_SEPARATOR@
+ $(MAKE) dist-clean
+ @CD_UP_ONE@
+ cd @INSTRUMENT_DIR@ @COMMAND_SEPARATOR@
+ $(MAKE) dist-clean
+ @CD_UP_TWO@
+ cd misc @COMMAND_SEPARATOR@
+ $(MAKE) dist-clean
+ @CD_UP_ONE@
+ cd fpu @COMMAND_SEPARATOR@
+ $(MAKE) dist-clean
+ @CD_UP_ONE@
+ cd doc/docbook @COMMAND_SEPARATOR@
+ $(MAKE) dist-clean
+ @CD_UP_TWO@
+ cd host/linux/pcidev @COMMAND_SEPARATOR@
+ $(MAKE) dist-clean
+ @CD_UP_THREE@
+ @RMCOMMAND@ Makefile
+
+###########################################
+# Build app on MacOS X
+###########################################
+MACOSX_STUFF=build/macosx
+MACOSX_STUFF_SRCDIR=$(srcdir)/$(MACOSX_STUFF)
+APP=bochs.app
+APP_PLATFORM=MacOS
+SCRIPT_EXEC=bochs.scpt
+SCRIPT_DATA=$(MACOSX_STUFF_SRCDIR)/script.data
+SCRIPT_R=$(MACOSX_STUFF_SRCDIR)/script.r
+SCRIPT_APPLESCRIPT=$(MACOSX_STUFF_SRCDIR)/bochs.applescript
+SCRIPT_COMPILED_RSRC=$(MACOSX_STUFF)/script_compiled.rsrc
+REZ=/Developer/Tools/Rez
+CPMAC=/Developer/Tools/CpMac
+RINCLUDES=/System/Library/Frameworks/Carbon.framework/Libraries/RIncludes
+REZ_ARGS=-append -i $RINCLUDES -d SystemSevenOrLater=1 -useDF
+STANDALONE_LIBDIR=`pwd`/$(APP)/Contents/$(APP_PLATFORM)/lib
+OSACOMPILE=/usr/bin/osacompile
+SETFILE=/Developer/Tools/Setfile
+
+# On a MacOS X machine, you run rez, osacompile, and setfile to
+# produce the script executable, which has both a data fork and a
+# resource fork. Ideally, we would just recompile the whole
+# executable at build time, but unfortunately this cannot be done on
+# the SF compile farm through an ssh connection because osacompile
+# needs to be run locally for some reason. Solution: If the script
+# sources are changed, rebuild the executable on a MacOSX machine,
+# split it into its data and resource forks and check them into CVS
+# as separate files. Then at release time, all that's left to do is
+# put the data and resource forks back together to make a working script.
+# (This can be done through ssh.)
+#
+# Sources:
+# 1. script.r: resources for the script
+# 2. script.data: binary data for the script
+# 3. bochs.applescript: the source of the script
+#
+# NOTE: All of this will fail if you aren't building on an HFS+
+# filesystem! On the SF compile farm building in your user directory
+# will fail, while doing the build in /tmp will work ok.
+
+# check if this filesystem supports resource forks at all
+test_hfsplus:
+ $(RM) -rf test_hfsplus
+ echo data > test_hfsplus
+ # if you get "Not a directory", then this filesystem doesn't support resources
+ echo resource > test_hfsplus/rsrc
+ # test succeeded
+ $(RM) -rf test_hfsplus
+
+# Step 1 (must be done locally on MacOSX, only when sources change)
+# Compile and pull out just the resource fork. The resource fork is
+# checked into CVS as script_compiled.rsrc. Note that we don't need
+# to check in the data fork of tmpscript because it is identical to the
+# script.data input file.
+$(SCRIPT_COMPILED_RSRC): $(SCRIPT_R) $(SCRIPT_APPLESCRIPT)
+ $(RM) -f tmpscript
+ $(CP) -f $(SCRIPT_DATA) tmpscript
+ $(REZ) -append $(SCRIPT_R) -o tmpscript
+ $(OSACOMPILE) -o tmpscript $(SCRIPT_APPLESCRIPT)
+ $(CP) tmpscript/rsrc $(SCRIPT_COMPILED_RSRC)
+ $(RM) -f tmpscript
+
+# Step 2 (can be done locally or remotely on MacOSX)
+# Combine the data fork and resource fork, and set attributes.
+$(SCRIPT_EXEC): $(SCRIPT_DATA) $(SCRIPT_COMPILED_RSRC)
+ rm -f $(SCRIPT_EXEC)
+ $(CP) $(SCRIPT_DATA) $(SCRIPT_EXEC)
+ if test ! -f $(SCRIPT_COMPILED_RSRC); then $(CP) $(srcdir)/$(SCRIPT_COMPILED_RSRC) $(SCRIPT_COMPILED_RSRC); fi
+ $(CP) $(SCRIPT_COMPILED_RSRC) $(SCRIPT_EXEC)/rsrc
+ $(SETFILE) -t "APPL" -c "aplt" $(SCRIPT_EXEC)
+
+$(APP)/.build: bochs test_hfsplus $(SCRIPT_EXEC)
+ rm -f $(APP)/.build
+ $(MKDIR) -p $(APP)
+ $(MKDIR) -p $(APP)/Contents
+ $(CP) -f $(MACOSX_STUFF)/Info.plist $(APP)/Contents
+ $(CP) -f $(MACOSX_STUFF_SRCDIR)/pbdevelopment.plist $(APP)/Contents
+ echo -n "APPL????" > $(APP)/Contents/PkgInfo
+ $(MKDIR) -p $(APP)/Contents/$(APP_PLATFORM)
+ $(CP) bochs $(APP)/Contents/$(APP_PLATFORM)
+ $(MKDIR) -p $(APP)/Contents/Resources
+ $(REZ) $(REZ_ARGS) $(MACOSX_STUFF_SRCDIR)/bochs.r -o $(APP)/Contents/Resources/bochs.rsrc
+ $(CP) -f $(MACOSX_STUFF_SRCDIR)/bochs-icn.icns $(APP)/Contents/Resources
+ ls -ld $(APP) $(SCRIPT_EXEC) $(SCRIPT_EXEC)/rsrc
+ touch $(APP)/.build
+
+$(APP)/.build_plugins: $(APP)/.build bochs_plugins
+ rm -f $(APP)/.build_plugins
+ $(MKDIR) -p $(STANDALONE_LIBDIR);
+ list=`cd gui && echo *.la`; for i in $$list; do $(LIBTOOL) cp gui/$$i $(STANDALONE_LIBDIR); done;
+ list=`cd iodev && echo *.la`; for i in $$list; do $(LIBTOOL) cp iodev/$$i $(STANDALONE_LIBDIR); done;
+ $(LIBTOOL) --finish $(STANDALONE_LIBDIR);
+ touch $(APP)/.build_plugins
+
+install_macosx: all download_dlx install_man @INSTALL_DOCBOOK_VAR@
+ -mkdir -p $(DESTDIR)$(prefix)
+ for i in $(INSTALL_LIST_MACOSX); do if test -e $$i; then $(CPMAC) -r $$i $(DESTDIR)$(sharedir); else $(CPMAC) -r $(srcdir)/$$i $(DESTDIR)$(sharedir); fi; done
+ $(CPMAC) $(srcdir)/.bochsrc $(DESTDIR)$(sharedir)/bochsrc-sample.txt
+ -mkdir $(DESTDIR)$(sharedir)/keymaps
+ $(CPMAC) $(srcdir)/gui/keymaps/*.map $(DESTDIR)$(sharedir)/keymaps
+ cat $(DLXLINUX_TAR) | (cd $(DESTDIR)$(sharedir) && tar xzvf -)
+ dlxrc=$(DESTDIR)$(sharedir)/dlxlinux/bochsrc.txt; mv "$$dlxrc" "$$dlxrc.orig" && sed < "$$dlxrc.orig" 's/\/usr\/local\/bochs\/latest/../' > "$$dlxrc" && rm -f "$$dlxrc.orig"
+ mv $(srcdir)/README $(srcdir)/README.orig
+ cat $(srcdir)/build/macosx/README.macosx-binary $(srcdir)/README.orig > $(DESTDIR)$(sharedir)/README
+ rm -f $(DESTDIR)$(sharedir)/README.orig
+ $(CPMAC) $(SCRIPT_EXEC) $(DESTDIR)$(sharedir)/dlxlinux
+# for i in $(TEXT_FILE_LIST); do mv $(srcdir)/$$i $(DESTDIR)$(sharedir)/$$i.txt; done
+
+###########################################
+# BeOS make target.
+# Build the binary normally, then copy the resource attributes.
+###########################################
+.bochs_beos_target: bochs@EXE@
+ unzip $(srcdir)/build/beos/resource.zip
+ copyattr -t ICON BeBochs.rsrc bochs
+ copyattr -t MICN BeBochs.rsrc bochs
+
+###########################################
+# dependencies generated by
+# gcc -MM -I. -Iinstrument/stubs *.cc | sed -e 's/\.cc/.@CPP_SUFFIX@/g' -e 's,cpu/,cpu/,g'
+###########################################
+config.o: config.@CPP_SUFFIX@ bochs.h config.h osdep.h bx_debug/debug.h config.h \
+ osdep.h bxversion.h gui/siminterface.h memory/memory.h pc_system.h \
+ plugin.h extplugin.h ltdl.h gui/gui.h gui/textconfig.h gui/keymap.h \
+ instrument/stubs/instrument.h iodev/iodev.h bochs.h iodev/vga.h \
+ iodev/svga_cirrus.h iodev/ioapic.h cpu/apic.h iodev/keyboard.h
+crc.o: crc.@CPP_SUFFIX@ config.h
+gdbstub.o: gdbstub.@CPP_SUFFIX@ bochs.h config.h osdep.h bx_debug/debug.h config.h \
+ osdep.h bxversion.h gui/siminterface.h memory/memory.h pc_system.h \
+ plugin.h extplugin.h ltdl.h gui/gui.h gui/textconfig.h gui/keymap.h \
+ instrument/stubs/instrument.h cpu/cpu.h disasm/disasm.h cpu/crregs.h \
+ cpu/descriptor.h cpu/instr.h cpu/lazy_flags.h cpu/icache.h cpu/apic.h \
+ cpu/i387.h fpu/softfloat.h fpu/tag_w.h fpu/status_w.h fpu/control_w.h \
+ cpu/xmm.h cpu/stack.h iodev/iodev.h bochs.h iodev/vga.h \
+ iodev/svga_cirrus.h iodev/ioapic.h cpu/apic.h iodev/keyboard.h
+load32bitOShack.o: load32bitOShack.@CPP_SUFFIX@ bochs.h config.h osdep.h \
+ bx_debug/debug.h config.h osdep.h bxversion.h gui/siminterface.h \
+ memory/memory.h pc_system.h plugin.h extplugin.h ltdl.h gui/gui.h \
+ gui/textconfig.h gui/keymap.h instrument/stubs/instrument.h cpu/cpu.h \
+ disasm/disasm.h cpu/crregs.h cpu/descriptor.h cpu/instr.h \
+ cpu/lazy_flags.h cpu/icache.h cpu/apic.h cpu/i387.h fpu/softfloat.h \
+ fpu/tag_w.h fpu/status_w.h fpu/control_w.h cpu/xmm.h iodev/iodev.h \
+ bochs.h iodev/vga.h iodev/svga_cirrus.h iodev/ioapic.h cpu/apic.h \
+ iodev/keyboard.h
+logio.o: logio.@CPP_SUFFIX@ bochs.h config.h osdep.h bx_debug/debug.h config.h \
+ osdep.h bxversion.h gui/siminterface.h memory/memory.h pc_system.h \
+ plugin.h extplugin.h ltdl.h gui/gui.h gui/textconfig.h gui/keymap.h \
+ instrument/stubs/instrument.h cpu/cpu.h disasm/disasm.h cpu/crregs.h \
+ cpu/descriptor.h cpu/instr.h cpu/lazy_flags.h cpu/icache.h cpu/apic.h \
+ cpu/i387.h fpu/softfloat.h fpu/tag_w.h fpu/status_w.h fpu/control_w.h \
+ cpu/xmm.h iodev/iodev.h bochs.h iodev/vga.h iodev/svga_cirrus.h \
+ iodev/ioapic.h cpu/apic.h iodev/keyboard.h
+main.o: main.@CPP_SUFFIX@ bochs.h config.h osdep.h bx_debug/debug.h config.h \
+ osdep.h bxversion.h gui/siminterface.h memory/memory.h pc_system.h \
+ plugin.h extplugin.h ltdl.h gui/gui.h gui/textconfig.h gui/keymap.h \
+ instrument/stubs/instrument.h cpu/cpu.h disasm/disasm.h cpu/crregs.h \
+ cpu/descriptor.h cpu/instr.h cpu/lazy_flags.h cpu/icache.h cpu/apic.h \
+ cpu/i387.h fpu/softfloat.h fpu/tag_w.h fpu/status_w.h fpu/control_w.h \
+ cpu/xmm.h iodev/iodev.h bochs.h iodev/vga.h iodev/svga_cirrus.h \
+ iodev/ioapic.h cpu/apic.h iodev/keyboard.h
+osdep.o: osdep.@CPP_SUFFIX@ bochs.h config.h osdep.h bx_debug/debug.h config.h \
+ osdep.h bxversion.h gui/siminterface.h memory/memory.h pc_system.h \
+ plugin.h extplugin.h ltdl.h gui/gui.h gui/textconfig.h gui/keymap.h \
+ instrument/stubs/instrument.h
+pc_system.o: pc_system.@CPP_SUFFIX@ bochs.h config.h osdep.h bx_debug/debug.h \
+ config.h osdep.h bxversion.h gui/siminterface.h memory/memory.h \
+ pc_system.h plugin.h extplugin.h ltdl.h gui/gui.h gui/textconfig.h \
+ gui/keymap.h instrument/stubs/instrument.h cpu/cpu.h disasm/disasm.h \
+ cpu/crregs.h cpu/descriptor.h cpu/instr.h cpu/lazy_flags.h cpu/icache.h \
+ cpu/apic.h cpu/i387.h fpu/softfloat.h fpu/tag_w.h fpu/status_w.h \
+ fpu/control_w.h cpu/xmm.h iodev/iodev.h bochs.h iodev/vga.h \
+ iodev/svga_cirrus.h iodev/ioapic.h cpu/apic.h iodev/keyboard.h
+plex86-interface.o: plex86-interface.@CPP_SUFFIX@ bochs.h config.h osdep.h \
+ bx_debug/debug.h config.h osdep.h bxversion.h gui/siminterface.h \
+ memory/memory.h pc_system.h plugin.h extplugin.h ltdl.h gui/gui.h \
+ gui/textconfig.h gui/keymap.h instrument/stubs/instrument.h \
+ plex86-interface.h plex86/plex86.h plex86/descriptor.h
+plugin.o: plugin.@CPP_SUFFIX@ bochs.h config.h osdep.h bx_debug/debug.h config.h \
+ osdep.h bxversion.h gui/siminterface.h memory/memory.h pc_system.h \
+ plugin.h extplugin.h ltdl.h gui/gui.h gui/textconfig.h gui/keymap.h \
+ instrument/stubs/instrument.h iodev/iodev.h bochs.h iodev/vga.h \
+ iodev/svga_cirrus.h iodev/ioapic.h cpu/apic.h iodev/keyboard.h
diff --git a/bochs/bios/.cvsignore b/bochs/bios/.cvsignore
new file mode 100644
index 0000000..f3c7a7c
--- /dev/null
+++ b/bochs/bios/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/bochs/bios/Makefile.in b/bochs/bios/Makefile.in
new file mode 100644
index 0000000..28ada75
--- /dev/null
+++ b/bochs/bios/Makefile.in
@@ -0,0 +1,120 @@
+# Copyright (C) 2001 MandrakeSoft S.A.
+#
+# MandrakeSoft S.A.
+# 43, rue d'Aboukir
+# 75002 Paris - France
+# http://www.linux-mandrake.com/
+# http://www.mandrakesoft.com/
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Makefile for the BIOS component of bochs
+
+
+@SUFFIX_LINE@
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+SHELL = /bin/sh
+
+@SET_MAKE@
+
+CXX = @CXX@
+CXXFLAGS = @CXXFLAGS@
+
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+RANLIB = @RANLIB@
+
+BCC = bcc
+GCC = gcc
+GCC32 = gcc -m32 -fno-stack-protector
+AS86 = as86
+
+BX_INCDIRS = -I.. -I$(srcdir)/.. -I../iodev -I$(srcdir)/../iodev
+LOCAL_CXXFLAGS =
+
+BUILDDATE = `date '+%m/%d/%y'`
+BIOS_BUILD_DATE = "-DBIOS_BUILD_DATE=\"$(BUILDDATE)\""
+#
+# -------- end configurable options --------------------------
+#
+
+
+.@CPP_SUFFIX@.o:
+ $(CXX) -c $(BX_INCDIRS) $(CXXFLAGS) $(LOCAL_CXXFLAGS) @CXXFP@$< @OFP@$@
+
+
+bios: biossums BIOS-bochs-latest BIOS-bochs-legacy
+
+clean:
+ @RMCOMMAND@ *.o *.a *.s _rombios*_.c rombios*.txt rombios*.sym
+ @RMCOMMAND@ usage biossums rombios16.bin
+ @RMCOMMAND@ rombios32.bin rombios32.out
+
+dist-clean: clean
+ @RMCOMMAND@ Makefile
+
+bios-clean:
+ @RMCOMMAND@ BIOS-bochs-*
+
+BIOS-bochs-legacy: rombios.c apmbios.S biossums rombios.h
+ $(GCC32) $(BIOS_BUILD_DATE) -DLEGACY -E -P $< > _rombiosl_.c
+ $(BCC) -o rombiosl.s -C-c -D__i86__ -0 -S _rombiosl_.c
+ sed -e 's/^\.text//' -e 's/^\.data//' rombiosl.s > _rombiosl_.s
+ $(AS86) _rombiosl_.s -b tmpl.bin -u- -w- -g -0 -j -O -l rombiosl.txt
+ -perl ${srcdir}/makesym.perl < rombiosl.txt > rombiosl.sym
+ mv tmpl.bin $@
+ ./biossums $@
+ @RMCOMMAND@ _rombiosl_.s
+
+
+rombios16.bin: rombios.c apmbios.S biossums rombios.h
+ $(GCC32) $(BIOS_BUILD_DATE) -E -P $< > _rombios_.c
+ $(BCC) -o rombios.s -C-c -D__i86__ -0 -S _rombios_.c
+ sed -e 's/^\.text//' -e 's/^\.data//' rombios.s > _rombios_.s
+ $(AS86) _rombios_.s -b tmp.bin -u- -w- -g -0 -j -O -l rombios.txt
+ -perl ${srcdir}/makesym.perl < rombios.txt > rombios.sym
+ mv tmp.bin rombios16.bin
+ ./biossums rombios16.bin
+ @RMCOMMAND@ _rombios_.s
+
+
+rombios32.bin: rombios32.out rombios.h
+ objcopy -O binary $< $@
+ ./biossums -pad $@
+
+rombios32.out: rombios32start.o rombios32.o rombios32.ld
+ ld -o $@ -T $(srcdir)/rombios32.ld rombios32start.o rombios32.o
+
+rombios32.o: rombios32.c acpi-dsdt.hex
+ $(GCC32) -O2 -Wall -c -o $@ $<
+
+ifeq ("1", "0")
+acpi-dsdt.hex: acpi-dsdt.dsl
+ cpp -P $< $<.i
+ iasl -tc -p $@ $<.i
+ rm $<.i
+ sed -i -e's/^unsigned/const unsigned/' $@
+endif
+
+rombios32start.o: rombios32start.S
+ $(GCC32) -c -o $@ $<
+
+BIOS-bochs-latest: rombios16.bin rombios32.bin
+ cat rombios32.bin rombios16.bin > $@
+
+biossums: biossums.o
diff --git a/bochs/bios/acpi-dsdt.dsl b/bochs/bios/acpi-dsdt.dsl
new file mode 100644
index 0000000..7bff30a
--- /dev/null
+++ b/bochs/bios/acpi-dsdt.dsl
@@ -0,0 +1,752 @@
+/*
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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, 0xb044, 0x04)
+ Field (DBG, DWordAcc, NoLock, Preserve)
+ {
+ DBGL, 32,
+ }
+ }
+
+
+ /* 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),
+ prt_slot1(0x0001),
+ 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,
+ }
+
+#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)
+ })
+ }
+#ifdef BX_QEMU
+ 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 */
+ )
+ })
+ }
+#endif
+ }
+
+ Scope(\_SB.PCI0) {
+ Device (VGA) {
+ Name (_ADR, 0x00020000)
+ Method (_S1D, 0, NotSerialized)
+ {
+ Return (0x00)
+ }
+ Method (_S2D, 0, NotSerialized)
+ {
+ Return (0x00)
+ }
+ Method (_S3D, 0, NotSerialized)
+ {
+ Return (0x00)
+ }
+ }
+
+ /* PIIX3 ISA bridge */
+ Device (ISA) {
+ Name (_ADR, 0x00010000)
+
+ /* 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
+ }
+ }
+ }
+
+ /* 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(){
+ IRQ (Level, ActiveLow, Shared)
+ {3,4,5,6,7,9,10,11,12}
+ })
+ 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 ()
+ {
+ IRQ (Level, ActiveLow, Shared)
+ {1}
+ })
+ CreateWordField (PRR0, 0x01, TMP)
+ Store (PRQ0, Local0)
+ If (LLess (Local0, 0x80))
+ {
+ ShiftLeft (One, Local0, TMP)
+ }
+ Else
+ {
+ Store (Zero, TMP)
+ }
+ Return (PRR0)
+ }
+ Method (_SRS, 1, NotSerialized)
+ {
+ CreateWordField (Arg0, 0x01, TMP)
+ FindSetRightBit (TMP, Local0)
+ Decrement (Local0)
+ Store (Local0, PRQ0)
+ }
+ }
+ Device(LNKB){
+ Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
+ Name(_UID, 2)
+ Name(_PRS, ResourceTemplate(){
+ IRQ (Level, ActiveLow, Shared)
+ {3,4,5,6,7,9,10,11,12}
+ })
+ 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 ()
+ {
+ IRQ (Level, ActiveLow, Shared)
+ {1}
+ })
+ CreateWordField (PRR0, 0x01, TMP)
+ Store (PRQ1, Local0)
+ If (LLess (Local0, 0x80))
+ {
+ ShiftLeft (One, Local0, TMP)
+ }
+ Else
+ {
+ Store (Zero, TMP)
+ }
+ Return (PRR0)
+ }
+ Method (_SRS, 1, NotSerialized)
+ {
+ CreateWordField (Arg0, 0x01, TMP)
+ FindSetRightBit (TMP, Local0)
+ Decrement (Local0)
+ Store (Local0, PRQ1)
+ }
+ }
+ Device(LNKC){
+ Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
+ Name(_UID, 3)
+ Name(_PRS, ResourceTemplate(){
+ IRQ (Level, ActiveLow, Shared)
+ {3,4,5,6,7,9,10,11,12}
+ })
+ 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 ()
+ {
+ IRQ (Level, ActiveLow, Shared)
+ {1}
+ })
+ CreateWordField (PRR0, 0x01, TMP)
+ Store (PRQ2, Local0)
+ If (LLess (Local0, 0x80))
+ {
+ ShiftLeft (One, Local0, TMP)
+ }
+ Else
+ {
+ Store (Zero, TMP)
+ }
+ Return (PRR0)
+ }
+ Method (_SRS, 1, NotSerialized)
+ {
+ CreateWordField (Arg0, 0x01, TMP)
+ FindSetRightBit (TMP, Local0)
+ Decrement (Local0)
+ Store (Local0, PRQ2)
+ }
+ }
+ Device(LNKD){
+ Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
+ Name(_UID, 4)
+ Name(_PRS, ResourceTemplate(){
+ IRQ (Level, ActiveLow, Shared)
+ {3,4,5,6,7,9,10,11,12}
+ })
+ 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 ()
+ {
+ IRQ (Level, ActiveLow, Shared)
+ {1}
+ })
+ CreateWordField (PRR0, 0x01, TMP)
+ Store (PRQ3, Local0)
+ If (LLess (Local0, 0x80))
+ {
+ ShiftLeft (One, Local0, TMP)
+ }
+ Else
+ {
+ Store (Zero, TMP)
+ }
+ Return (PRR0)
+ }
+ Method (_SRS, 1, NotSerialized)
+ {
+ CreateWordField (Arg0, 0x01, TMP)
+ FindSetRightBit (TMP, Local0)
+ Decrement (Local0)
+ Store (Local0, PRQ3)
+ }
+ }
+ }
+
+ /*
+ * 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 */
+ })
+
+ 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) {
+ Return(0x01)
+ }
+ 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/bochs/bios/acpi-dsdt.hex b/bochs/bios/acpi-dsdt.hex
new file mode 100644
index 0000000..a4c64e6
--- /dev/null
+++ b/bochs/bios/acpi-dsdt.hex
@@ -0,0 +1,273 @@
+/*
+ *
+ * Intel ACPI Component Architecture
+ * ASL Optimizing Compiler version 20061109 [May 15 2007]
+ * Copyright (C) 2000 - 2006 Intel Corporation
+ * Supports ACPI Specification Revision 3.0a
+ *
+ * Compilation of "acpi-dsdt.dsl" - Mon Oct 27 10:39:43 2008
+ *
+ * C source code output
+ *
+ */
+const unsigned char AmlCode[] =
+{
+ 0x44,0x53,0x44,0x54,0x0D,0x08,0x00,0x00, /* 00000000 "DSDT...." */
+ 0x01,0xA1,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" */
+ 0x09,0x11,0x06,0x20,0x10,0x1C,0x5C,0x00, /* 00000020 "... ..\." */
+ 0x5B,0x80,0x44,0x42,0x47,0x5F,0x01,0x0B, /* 00000028 "[.DBG_.." */
+ 0x44,0xB0,0x0A,0x04,0x5B,0x81,0x0B,0x44, /* 00000030 "D...[..D" */
+ 0x42,0x47,0x5F,0x03,0x44,0x42,0x47,0x4C, /* 00000038 "BG_.DBGL" */
+ 0x20,0x10,0x49,0x1F,0x5F,0x53,0x42,0x5F, /* 00000040 " .I._SB_" */
+ 0x5B,0x82,0x41,0x1F,0x50,0x43,0x49,0x30, /* 00000048 "[.A.PCI0" */
+ 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00000050 "._HID.A." */
+ 0x0A,0x03,0x08,0x5F,0x41,0x44,0x52,0x00, /* 00000058 "..._ADR." */
+ 0x08,0x5F,0x55,0x49,0x44,0x01,0x08,0x5F, /* 00000060 "._UID.._" */
+ 0x50,0x52,0x54,0x12,0x47,0x15,0x18,0x12, /* 00000068 "PRT.G..." */
+ 0x0B,0x04,0x0B,0xFF,0xFF,0x00,0x4C,0x4E, /* 00000070 "......LN" */
+ 0x4B,0x44,0x00,0x12,0x0B,0x04,0x0B,0xFF, /* 00000078 "KD......" */
+ 0xFF,0x01,0x4C,0x4E,0x4B,0x41,0x00,0x12, /* 00000080 "..LNKA.." */
+ 0x0C,0x04,0x0B,0xFF,0xFF,0x0A,0x02,0x4C, /* 00000088 ".......L" */
+ 0x4E,0x4B,0x42,0x00,0x12,0x0C,0x04,0x0B, /* 00000090 "NKB....." */
+ 0xFF,0xFF,0x0A,0x03,0x4C,0x4E,0x4B,0x43, /* 00000098 "....LNKC" */
+ 0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x01, /* 000000A0 "........" */
+ 0x00,0x00,0x4C,0x4E,0x4B,0x41,0x00,0x12, /* 000000A8 "..LNKA.." */
+ 0x0D,0x04,0x0C,0xFF,0xFF,0x01,0x00,0x01, /* 000000B0 "........" */
+ 0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0E,0x04, /* 000000B8 "LNKB...." */
+ 0x0C,0xFF,0xFF,0x01,0x00,0x0A,0x02,0x4C, /* 000000C0 ".......L" */
+ 0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C, /* 000000C8 "NKC....." */
+ 0xFF,0xFF,0x01,0x00,0x0A,0x03,0x4C,0x4E, /* 000000D0 "......LN" */
+ 0x4B,0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF, /* 000000D8 "KD......" */
+ 0xFF,0x02,0x00,0x00,0x4C,0x4E,0x4B,0x42, /* 000000E0 "....LNKB" */
+ 0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x02, /* 000000E8 "........" */
+ 0x00,0x01,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000000F0 "..LNKC.." */
+ 0x0E,0x04,0x0C,0xFF,0xFF,0x02,0x00,0x0A, /* 000000F8 "........" */
+ 0x02,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E, /* 00000100 ".LNKD..." */
+ 0x04,0x0C,0xFF,0xFF,0x02,0x00,0x0A,0x03, /* 00000108 "........" */
+ 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04, /* 00000110 "LNKA...." */
+ 0x0C,0xFF,0xFF,0x03,0x00,0x00,0x4C,0x4E, /* 00000118 "......LN" */
+ 0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C,0xFF, /* 00000120 "KC......" */
+ 0xFF,0x03,0x00,0x01,0x4C,0x4E,0x4B,0x44, /* 00000128 "....LNKD" */
+ 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x03, /* 00000130 "........" */
+ 0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x41,0x00, /* 00000138 "...LNKA." */
+ 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x03,0x00, /* 00000140 "........" */
+ 0x0A,0x03,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 00000148 "..LNKB.." */
+ 0x0D,0x04,0x0C,0xFF,0xFF,0x04,0x00,0x00, /* 00000150 "........" */
+ 0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0D,0x04, /* 00000158 "LNKD...." */
+ 0x0C,0xFF,0xFF,0x04,0x00,0x01,0x4C,0x4E, /* 00000160 "......LN" */
+ 0x4B,0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000168 "KA......" */
+ 0xFF,0x04,0x00,0x0A,0x02,0x4C,0x4E,0x4B, /* 00000170 ".....LNK" */
+ 0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000178 "B......." */
+ 0x04,0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x43, /* 00000180 "....LNKC" */
+ 0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x05, /* 00000188 "........" */
+ 0x00,0x00,0x4C,0x4E,0x4B,0x41,0x00,0x12, /* 00000190 "..LNKA.." */
+ 0x0D,0x04,0x0C,0xFF,0xFF,0x05,0x00,0x01, /* 00000198 "........" */
+ 0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0E,0x04, /* 000001A0 "LNKB...." */
+ 0x0C,0xFF,0xFF,0x05,0x00,0x0A,0x02,0x4C, /* 000001A8 ".......L" */
+ 0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C, /* 000001B0 "NKC....." */
+ 0xFF,0xFF,0x05,0x00,0x0A,0x03,0x4C,0x4E, /* 000001B8 "......LN" */
+ 0x4B,0x44,0x00,0x08,0x5F,0x43,0x52,0x53, /* 000001C0 "KD.._CRS" */
+ 0x11,0x42,0x07,0x0A,0x6E,0x88,0x0D,0x00, /* 000001C8 ".B..n..." */
+ 0x02,0x0C,0x00,0x00,0x00,0x00,0x00,0xFF, /* 000001D0 "........" */
+ 0x00,0x00,0x00,0x00,0x01,0x47,0x01,0xF8, /* 000001D8 ".....G.." */
+ 0x0C,0xF8,0x0C,0x01,0x08,0x88,0x0D,0x00, /* 000001E0 "........" */
+ 0x01,0x0C,0x03,0x00,0x00,0x00,0x00,0xF7, /* 000001E8 "........" */
+ 0x0C,0x00,0x00,0xF8,0x0C,0x88,0x0D,0x00, /* 000001F0 "........" */
+ 0x01,0x0C,0x03,0x00,0x00,0x00,0x0D,0xFF, /* 000001F8 "........" */
+ 0xFF,0x00,0x00,0x00,0xF3,0x87,0x17,0x00, /* 00000200 "........" */
+ 0x00,0x0C,0x03,0x00,0x00,0x00,0x00,0x00, /* 00000208 "........" */
+ 0x00,0x0A,0x00,0xFF,0xFF,0x0B,0x00,0x00, /* 00000210 "........" */
+ 0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x87, /* 00000218 "........" */
+ 0x17,0x00,0x00,0x0C,0x01,0x00,0x00,0x00, /* 00000220 "........" */
+ 0x00,0x00,0x00,0x00,0xE0,0xFF,0xFF,0xBF, /* 00000228 "........" */
+ 0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0xC0, /* 00000230 "........" */
+ 0x1E,0x79,0x00,0x10,0x4D,0x2B,0x2E,0x5F, /* 00000238 ".y..M+._" */
+ 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x5B, /* 00000240 "SB_PCI0[" */
+ 0x82,0x2A,0x56,0x47,0x41,0x5F,0x08,0x5F, /* 00000248 ".*VGA_._" */
+ 0x41,0x44,0x52,0x0C,0x00,0x00,0x02,0x00, /* 00000250 "ADR....." */
+ 0x14,0x08,0x5F,0x53,0x31,0x44,0x00,0xA4, /* 00000258 ".._S1D.." */
+ 0x00,0x14,0x08,0x5F,0x53,0x32,0x44,0x00, /* 00000260 "..._S2D." */
+ 0xA4,0x00,0x14,0x08,0x5F,0x53,0x33,0x44, /* 00000268 "...._S3D" */
+ 0x00,0xA4,0x00,0x5B,0x82,0x42,0x23,0x49, /* 00000270 "...[.B#I" */
+ 0x53,0x41,0x5F,0x08,0x5F,0x41,0x44,0x52, /* 00000278 "SA_._ADR" */
+ 0x0C,0x00,0x00,0x01,0x00,0x5B,0x80,0x50, /* 00000280 ".....[.P" */
+ 0x34,0x30,0x43,0x02,0x0A,0x60,0x0A,0x04, /* 00000288 "40C..`.." */
+ 0x5B,0x82,0x2D,0x52,0x54,0x43,0x5F,0x08, /* 00000290 "[.-RTC_." */
+ 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x0B, /* 00000298 "_HID.A.." */
+ 0x00,0x08,0x5F,0x43,0x52,0x53,0x11,0x18, /* 000002A0 ".._CRS.." */
+ 0x0A,0x15,0x47,0x01,0x70,0x00,0x70,0x00, /* 000002A8 "..G.p.p." */
+ 0x10,0x02,0x22,0x00,0x01,0x47,0x01,0x72, /* 000002B0 ".."..G.r" */
+ 0x00,0x72,0x00,0x02,0x06,0x79,0x00,0x5B, /* 000002B8 ".r...y.[" */
+ 0x82,0x44,0x04,0x4B,0x42,0x44,0x5F,0x08, /* 000002C0 ".D.KBD_." */
+ 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x03, /* 000002C8 "_HID.A.." */
+ 0x03,0x14,0x09,0x5F,0x53,0x54,0x41,0x00, /* 000002D0 "..._STA." */
+ 0xA4,0x0A,0x0F,0x14,0x29,0x5F,0x43,0x52, /* 000002D8 "....)_CR" */
+ 0x53,0x00,0x08,0x54,0x4D,0x50,0x5F,0x11, /* 000002E0 "S..TMP_." */
+ 0x18,0x0A,0x15,0x47,0x01,0x60,0x00,0x60, /* 000002E8 "...G.`.`" */
+ 0x00,0x01,0x01,0x47,0x01,0x64,0x00,0x64, /* 000002F0 "...G.d.d" */
+ 0x00,0x01,0x01,0x22,0x02,0x00,0x79,0x00, /* 000002F8 "..."..y." */
+ 0xA4,0x54,0x4D,0x50,0x5F,0x5B,0x82,0x33, /* 00000300 ".TMP_[.3" */
+ 0x4D,0x4F,0x55,0x5F,0x08,0x5F,0x48,0x49, /* 00000308 "MOU_._HI" */
+ 0x44,0x0C,0x41,0xD0,0x0F,0x13,0x14,0x09, /* 00000310 "D.A....." */
+ 0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F, /* 00000318 "_STA...." */
+ 0x14,0x19,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000320 ".._CRS.." */
+ 0x54,0x4D,0x50,0x5F,0x11,0x08,0x0A,0x05, /* 00000328 "TMP_...." */
+ 0x22,0x00,0x10,0x79,0x00,0xA4,0x54,0x4D, /* 00000330 ""..y..TM" */
+ 0x50,0x5F,0x5B,0x82,0x47,0x04,0x46,0x44, /* 00000338 "P_[.G.FD" */
+ 0x43,0x30,0x08,0x5F,0x48,0x49,0x44,0x0C, /* 00000340 "C0._HID." */
+ 0x41,0xD0,0x07,0x00,0x14,0x09,0x5F,0x53, /* 00000348 "A....._S" */
+ 0x54,0x41,0x00,0xA4,0x0A,0x0F,0x14,0x2C, /* 00000350 "TA.....," */
+ 0x5F,0x43,0x52,0x53,0x00,0x08,0x42,0x55, /* 00000358 "_CRS..BU" */
+ 0x46,0x30,0x11,0x1B,0x0A,0x18,0x47,0x01, /* 00000360 "F0....G." */
+ 0xF2,0x03,0xF2,0x03,0x00,0x04,0x47,0x01, /* 00000368 "......G." */
+ 0xF7,0x03,0xF7,0x03,0x00,0x01,0x22,0x40, /* 00000370 "......"@" */
+ 0x00,0x2A,0x04,0x00,0x79,0x00,0xA4,0x42, /* 00000378 ".*..y..B" */
+ 0x55,0x46,0x30,0x5B,0x82,0x4B,0x05,0x4C, /* 00000380 "UF0[.K.L" */
+ 0x50,0x54,0x5F,0x08,0x5F,0x48,0x49,0x44, /* 00000388 "PT_._HID" */
+ 0x0C,0x41,0xD0,0x04,0x00,0x14,0x28,0x5F, /* 00000390 ".A....(_" */
+ 0x53,0x54,0x41,0x00,0x70,0x5E,0x5E,0x5E, /* 00000398 "STA.p^^^" */
+ 0x2E,0x50,0x58,0x31,0x33,0x44,0x52,0x53, /* 000003A0 ".PX13DRS" */
+ 0x41,0x60,0x7B,0x60,0x0C,0x00,0x00,0x00, /* 000003A8 "A`{`...." */
+ 0x80,0x60,0xA0,0x06,0x93,0x60,0x00,0xA4, /* 000003B0 ".`...`.." */
+ 0x00,0xA1,0x04,0xA4,0x0A,0x0F,0x14,0x21, /* 000003B8 ".......!" */
+ 0x5F,0x43,0x52,0x53,0x00,0x08,0x42,0x55, /* 000003C0 "_CRS..BU" */
+ 0x46,0x30,0x11,0x10,0x0A,0x0D,0x47,0x01, /* 000003C8 "F0....G." */
+ 0x78,0x03,0x78,0x03,0x08,0x08,0x22,0x80, /* 000003D0 "x.x..."." */
+ 0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 000003D8 ".y..BUF0" */
+ 0x5B,0x82,0x41,0x06,0x43,0x4F,0x4D,0x31, /* 000003E0 "[.A.COM1" */
+ 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000003E8 "._HID.A." */
+ 0x05,0x01,0x08,0x5F,0x55,0x49,0x44,0x01, /* 000003F0 "..._UID." */
+ 0x14,0x28,0x5F,0x53,0x54,0x41,0x00,0x70, /* 000003F8 ".(_STA.p" */
+ 0x5E,0x5E,0x5E,0x2E,0x50,0x58,0x31,0x33, /* 00000400 "^^^.PX13" */
+ 0x44,0x52,0x53,0x43,0x60,0x7B,0x60,0x0C, /* 00000408 "DRSC`{`." */
+ 0x00,0x00,0x00,0x08,0x60,0xA0,0x06,0x93, /* 00000410 "....`..." */
+ 0x60,0x00,0xA4,0x00,0xA1,0x04,0xA4,0x0A, /* 00000418 "`......." */
+ 0x0F,0x14,0x21,0x5F,0x43,0x52,0x53,0x00, /* 00000420 "..!_CRS." */
+ 0x08,0x42,0x55,0x46,0x30,0x11,0x10,0x0A, /* 00000428 ".BUF0..." */
+ 0x0D,0x47,0x01,0xF8,0x03,0xF8,0x03,0x00, /* 00000430 ".G......" */
+ 0x08,0x22,0x10,0x00,0x79,0x00,0xA4,0x42, /* 00000438 "."..y..B" */
+ 0x55,0x46,0x30,0x5B,0x82,0x42,0x06,0x43, /* 00000440 "UF0[.B.C" */
+ 0x4F,0x4D,0x32,0x08,0x5F,0x48,0x49,0x44, /* 00000448 "OM2._HID" */
+ 0x0C,0x41,0xD0,0x05,0x01,0x08,0x5F,0x55, /* 00000450 ".A...._U" */
+ 0x49,0x44,0x0A,0x02,0x14,0x28,0x5F,0x53, /* 00000458 "ID...(_S" */
+ 0x54,0x41,0x00,0x70,0x5E,0x5E,0x5E,0x2E, /* 00000460 "TA.p^^^." */
+ 0x50,0x58,0x31,0x33,0x44,0x52,0x53,0x43, /* 00000468 "PX13DRSC" */
+ 0x60,0x7B,0x60,0x0C,0x00,0x00,0x00,0x80, /* 00000470 "`{`....." */
+ 0x60,0xA0,0x06,0x93,0x60,0x00,0xA4,0x00, /* 00000478 "`...`..." */
+ 0xA1,0x04,0xA4,0x0A,0x0F,0x14,0x21,0x5F, /* 00000480 "......!_" */
+ 0x43,0x52,0x53,0x00,0x08,0x42,0x55,0x46, /* 00000488 "CRS..BUF" */
+ 0x30,0x11,0x10,0x0A,0x0D,0x47,0x01,0xF8, /* 00000490 "0....G.." */
+ 0x02,0xF8,0x02,0x00,0x08,0x22,0x08,0x00, /* 00000498 ".....".." */
+ 0x79,0x00,0xA4,0x42,0x55,0x46,0x30,0x5B, /* 000004A0 "y..BUF0[" */
+ 0x82,0x40,0x05,0x50,0x58,0x31,0x33,0x08, /* 000004A8 ".@.PX13." */
+ 0x5F,0x41,0x44,0x52,0x0C,0x03,0x00,0x01, /* 000004B0 "_ADR...." */
+ 0x00,0x5B,0x80,0x50,0x31,0x33,0x43,0x02, /* 000004B8 ".[.P13C." */
+ 0x0A,0x5C,0x0A,0x24,0x5B,0x81,0x33,0x50, /* 000004C0 ".\.$[.3P" */
+ 0x31,0x33,0x43,0x03,0x44,0x52,0x53,0x41, /* 000004C8 "13C.DRSA" */
+ 0x20,0x44,0x52,0x53,0x42,0x20,0x44,0x52, /* 000004D0 " DRSB DR" */
+ 0x53,0x43,0x20,0x44,0x52,0x53,0x45,0x20, /* 000004D8 "SC DRSE " */
+ 0x44,0x52,0x53,0x46,0x20,0x44,0x52,0x53, /* 000004E0 "DRSF DRS" */
+ 0x47,0x20,0x44,0x52,0x53,0x48,0x20,0x44, /* 000004E8 "G DRSH D" */
+ 0x52,0x53,0x49,0x20,0x44,0x52,0x53,0x4A, /* 000004F0 "RSI DRSJ" */
+ 0x20,0x10,0x4F,0x2E,0x5F,0x53,0x42,0x5F, /* 000004F8 " .O._SB_" */
+ 0x5B,0x81,0x24,0x2F,0x03,0x50,0x43,0x49, /* 00000500 "[.$/.PCI" */
+ 0x30,0x49,0x53,0x41,0x5F,0x50,0x34,0x30, /* 00000508 "0ISA_P40" */
+ 0x43,0x01,0x50,0x52,0x51,0x30,0x08,0x50, /* 00000510 "C.PRQ0.P" */
+ 0x52,0x51,0x31,0x08,0x50,0x52,0x51,0x32, /* 00000518 "RQ1.PRQ2" */
+ 0x08,0x50,0x52,0x51,0x33,0x08,0x5B,0x82, /* 00000520 ".PRQ3.[." */
+ 0x4E,0x0A,0x4C,0x4E,0x4B,0x41,0x08,0x5F, /* 00000528 "N.LNKA._" */
+ 0x48,0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F, /* 00000530 "HID.A..." */
+ 0x08,0x5F,0x55,0x49,0x44,0x01,0x08,0x5F, /* 00000538 "._UID.._" */
+ 0x50,0x52,0x53,0x11,0x09,0x0A,0x06,0x23, /* 00000540 "PRS....#" */
+ 0xF8,0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F, /* 00000548 "...y..._" */
+ 0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 00000550 "STA.p..`" */
+ 0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 00000558 "..{..PRQ" */
+ 0x30,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 00000560 "0ap..`.`" */
+ 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 00000568 ".._DIS.}" */
+ 0x50,0x52,0x51,0x30,0x0A,0x80,0x50,0x52, /* 00000570 "PRQ0..PR" */
+ 0x51,0x30,0x14,0x3F,0x5F,0x43,0x52,0x53, /* 00000578 "Q0.?_CRS" */
+ 0x00,0x08,0x50,0x52,0x52,0x30,0x11,0x09, /* 00000580 "..PRR0.." */
+ 0x0A,0x06,0x23,0x02,0x00,0x18,0x79,0x00, /* 00000588 "..#...y." */
+ 0x8B,0x50,0x52,0x52,0x30,0x01,0x54,0x4D, /* 00000590 ".PRR0.TM" */
+ 0x50,0x5F,0x70,0x50,0x52,0x51,0x30,0x60, /* 00000598 "P_pPRQ0`" */
+ 0xA0,0x0C,0x95,0x60,0x0A,0x80,0x79,0x01, /* 000005A0 "...`..y." */
+ 0x60,0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70, /* 000005A8 "`TMP_..p" */
+ 0x00,0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52, /* 000005B0 ".TMP_.PR" */
+ 0x52,0x30,0x14,0x1B,0x5F,0x53,0x52,0x53, /* 000005B8 "R0.._SRS" */
+ 0x01,0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F, /* 000005C0 "..h.TMP_" */
+ 0x82,0x54,0x4D,0x50,0x5F,0x60,0x76,0x60, /* 000005C8 ".TMP_`v`" */
+ 0x70,0x60,0x50,0x52,0x51,0x30,0x5B,0x82, /* 000005D0 "p`PRQ0[." */
+ 0x4F,0x0A,0x4C,0x4E,0x4B,0x42,0x08,0x5F, /* 000005D8 "O.LNKB._" */
+ 0x48,0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F, /* 000005E0 "HID.A..." */
+ 0x08,0x5F,0x55,0x49,0x44,0x0A,0x02,0x08, /* 000005E8 "._UID..." */
+ 0x5F,0x50,0x52,0x53,0x11,0x09,0x0A,0x06, /* 000005F0 "_PRS...." */
+ 0x23,0xF8,0x1E,0x18,0x79,0x00,0x14,0x1A, /* 000005F8 "#...y..." */
+ 0x5F,0x53,0x54,0x41,0x00,0x70,0x0A,0x0B, /* 00000600 "_STA.p.." */
+ 0x60,0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52, /* 00000608 "`..{..PR" */
+ 0x51,0x31,0x61,0x70,0x0A,0x09,0x60,0xA4, /* 00000610 "Q1ap..`." */
+ 0x60,0x14,0x11,0x5F,0x44,0x49,0x53,0x00, /* 00000618 "`.._DIS." */
+ 0x7D,0x50,0x52,0x51,0x31,0x0A,0x80,0x50, /* 00000620 "}PRQ1..P" */
+ 0x52,0x51,0x31,0x14,0x3F,0x5F,0x43,0x52, /* 00000628 "RQ1.?_CR" */
+ 0x53,0x00,0x08,0x50,0x52,0x52,0x30,0x11, /* 00000630 "S..PRR0." */
+ 0x09,0x0A,0x06,0x23,0x02,0x00,0x18,0x79, /* 00000638 "...#...y" */
+ 0x00,0x8B,0x50,0x52,0x52,0x30,0x01,0x54, /* 00000640 "..PRR0.T" */
+ 0x4D,0x50,0x5F,0x70,0x50,0x52,0x51,0x31, /* 00000648 "MP_pPRQ1" */
+ 0x60,0xA0,0x0C,0x95,0x60,0x0A,0x80,0x79, /* 00000650 "`...`..y" */
+ 0x01,0x60,0x54,0x4D,0x50,0x5F,0xA1,0x07, /* 00000658 ".`TMP_.." */
+ 0x70,0x00,0x54,0x4D,0x50,0x5F,0xA4,0x50, /* 00000660 "p.TMP_.P" */
+ 0x52,0x52,0x30,0x14,0x1B,0x5F,0x53,0x52, /* 00000668 "RR0.._SR" */
+ 0x53,0x01,0x8B,0x68,0x01,0x54,0x4D,0x50, /* 00000670 "S..h.TMP" */
+ 0x5F,0x82,0x54,0x4D,0x50,0x5F,0x60,0x76, /* 00000678 "_.TMP_`v" */
+ 0x60,0x70,0x60,0x50,0x52,0x51,0x31,0x5B, /* 00000680 "`p`PRQ1[" */
+ 0x82,0x4F,0x0A,0x4C,0x4E,0x4B,0x43,0x08, /* 00000688 ".O.LNKC." */
+ 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x0C, /* 00000690 "_HID.A.." */
+ 0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A,0x03, /* 00000698 ".._UID.." */
+ 0x08,0x5F,0x50,0x52,0x53,0x11,0x09,0x0A, /* 000006A0 "._PRS..." */
+ 0x06,0x23,0xF8,0x1E,0x18,0x79,0x00,0x14, /* 000006A8 ".#...y.." */
+ 0x1A,0x5F,0x53,0x54,0x41,0x00,0x70,0x0A, /* 000006B0 "._STA.p." */
+ 0x0B,0x60,0xA0,0x0D,0x7B,0x0A,0x80,0x50, /* 000006B8 ".`..{..P" */
+ 0x52,0x51,0x32,0x61,0x70,0x0A,0x09,0x60, /* 000006C0 "RQ2ap..`" */
+ 0xA4,0x60,0x14,0x11,0x5F,0x44,0x49,0x53, /* 000006C8 ".`.._DIS" */
+ 0x00,0x7D,0x50,0x52,0x51,0x32,0x0A,0x80, /* 000006D0 ".}PRQ2.." */
+ 0x50,0x52,0x51,0x32,0x14,0x3F,0x5F,0x43, /* 000006D8 "PRQ2.?_C" */
+ 0x52,0x53,0x00,0x08,0x50,0x52,0x52,0x30, /* 000006E0 "RS..PRR0" */
+ 0x11,0x09,0x0A,0x06,0x23,0x02,0x00,0x18, /* 000006E8 "....#..." */
+ 0x79,0x00,0x8B,0x50,0x52,0x52,0x30,0x01, /* 000006F0 "y..PRR0." */
+ 0x54,0x4D,0x50,0x5F,0x70,0x50,0x52,0x51, /* 000006F8 "TMP_pPRQ" */
+ 0x32,0x60,0xA0,0x0C,0x95,0x60,0x0A,0x80, /* 00000700 "2`...`.." */
+ 0x79,0x01,0x60,0x54,0x4D,0x50,0x5F,0xA1, /* 00000708 "y.`TMP_." */
+ 0x07,0x70,0x00,0x54,0x4D,0x50,0x5F,0xA4, /* 00000710 ".p.TMP_." */
+ 0x50,0x52,0x52,0x30,0x14,0x1B,0x5F,0x53, /* 00000718 "PRR0.._S" */
+ 0x52,0x53,0x01,0x8B,0x68,0x01,0x54,0x4D, /* 00000720 "RS..h.TM" */
+ 0x50,0x5F,0x82,0x54,0x4D,0x50,0x5F,0x60, /* 00000728 "P_.TMP_`" */
+ 0x76,0x60,0x70,0x60,0x50,0x52,0x51,0x32, /* 00000730 "v`p`PRQ2" */
+ 0x5B,0x82,0x4F,0x0A,0x4C,0x4E,0x4B,0x44, /* 00000738 "[.O.LNKD" */
+ 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00000740 "._HID.A." */
+ 0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 00000748 "..._UID." */
+ 0x04,0x08,0x5F,0x50,0x52,0x53,0x11,0x09, /* 00000750 ".._PRS.." */
+ 0x0A,0x06,0x23,0xF8,0x1E,0x18,0x79,0x00, /* 00000758 "..#...y." */
+ 0x14,0x1A,0x5F,0x53,0x54,0x41,0x00,0x70, /* 00000760 ".._STA.p" */
+ 0x0A,0x0B,0x60,0xA0,0x0D,0x7B,0x0A,0x80, /* 00000768 "..`..{.." */
+ 0x50,0x52,0x51,0x33,0x61,0x70,0x0A,0x09, /* 00000770 "PRQ3ap.." */
+ 0x60,0xA4,0x60,0x14,0x11,0x5F,0x44,0x49, /* 00000778 "`.`.._DI" */
+ 0x53,0x00,0x7D,0x50,0x52,0x51,0x33,0x0A, /* 00000780 "S.}PRQ3." */
+ 0x80,0x50,0x52,0x51,0x33,0x14,0x3F,0x5F, /* 00000788 ".PRQ3.?_" */
+ 0x43,0x52,0x53,0x00,0x08,0x50,0x52,0x52, /* 00000790 "CRS..PRR" */
+ 0x30,0x11,0x09,0x0A,0x06,0x23,0x02,0x00, /* 00000798 "0....#.." */
+ 0x18,0x79,0x00,0x8B,0x50,0x52,0x52,0x30, /* 000007A0 ".y..PRR0" */
+ 0x01,0x54,0x4D,0x50,0x5F,0x70,0x50,0x52, /* 000007A8 ".TMP_pPR" */
+ 0x51,0x33,0x60,0xA0,0x0C,0x95,0x60,0x0A, /* 000007B0 "Q3`...`." */
+ 0x80,0x79,0x01,0x60,0x54,0x4D,0x50,0x5F, /* 000007B8 ".y.`TMP_" */
+ 0xA1,0x07,0x70,0x00,0x54,0x4D,0x50,0x5F, /* 000007C0 "..p.TMP_" */
+ 0xA4,0x50,0x52,0x52,0x30,0x14,0x1B,0x5F, /* 000007C8 ".PRR0.._" */
+ 0x53,0x52,0x53,0x01,0x8B,0x68,0x01,0x54, /* 000007D0 "SRS..h.T" */
+ 0x4D,0x50,0x5F,0x82,0x54,0x4D,0x50,0x5F, /* 000007D8 "MP_.TMP_" */
+ 0x60,0x76,0x60,0x70,0x60,0x50,0x52,0x51, /* 000007E0 "`v`p`PRQ" */
+ 0x33,0x08,0x5F,0x53,0x33,0x5F,0x12,0x06, /* 000007E8 "3._S3_.." */
+ 0x04,0x01,0x01,0x00,0x00,0x08,0x5F,0x53, /* 000007F0 "......_S" */
+ 0x34,0x5F,0x12,0x06,0x04,0x00,0x00,0x00, /* 000007F8 "4_......" */
+ 0x00,0x08,0x5F,0x53,0x35,0x5F,0x12,0x06, /* 00000800 ".._S5_.." */
+ 0x04,0x00,0x00,0x00,0x00,
+};
diff --git a/bochs/bios/apmbios.S b/bochs/bios/apmbios.S
new file mode 100644
index 0000000..41c9e7e
--- /dev/null
+++ b/bochs/bios/apmbios.S
@@ -0,0 +1,365 @@
+// APM BIOS support for the Bochs BIOS
+// Copyright (C) 2004 Fabrice Bellard
+//
+// Debugging extensions, 16-bit interface and extended power options
+// Copyright (C) 2005 Struan Bartlett
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+#if defined(APM_REAL)
+#define APMSYM(s) apmreal_ ## s
+#elif defined(APM_PROT16)
+#define APMSYM(s) apm16_ ## s
+#elif defined(APM_PROT32)
+#define APMSYM(s) apm32_ ## s
+#else
+#error unsupported APM mode
+#endif
+
+APMSYM(out_str):
+ push eax
+ push ebx
+ mov ebx, eax
+APMSYM(out_str1):
+ SEG CS
+ mov al, byte ptr [bx]
+ cmp al, #0
+ je APMSYM(out_str2)
+ outb dx, al
+ inc ebx
+ jmp APMSYM(out_str1)
+APMSYM(out_str2):
+ pop ebx
+ pop eax
+ ret
+
+APMSYM(07_poweroff_str):
+ .ascii "Shutdown"
+ db 0
+APMSYM(07_suspend_str):
+ .ascii "Suspend"
+ db 0
+APMSYM(07_standby_str):
+ .ascii "Standby"
+ db 0
+
+#if DEBUG_APM
+APMSYM(put_str):
+ push edx
+ mov dx, #INFO_PORT
+ call APMSYM(out_str)
+ pop edx
+ ret
+
+; print the hex number in eax
+APMSYM(put_num):
+ push eax
+ push ebx
+ push ecx
+ push edx
+ mov ecx, eax
+ mov bx, #8
+ mov dx, #INFO_PORT
+APMSYM(put_num1):
+ mov eax, ecx
+ shr eax, #28
+ add al, #0x30
+ cmp al, #0x39
+ jbe APMSYM(put_num2)
+ add al, #0x27
+APMSYM(put_num2):
+ outb dx, al
+ shl ecx, #4
+ dec bx
+ jne APMSYM(put_num1)
+ pop edx
+ pop ecx
+ pop ebx
+ pop eax
+ ret
+
+APMSYM(put_reg):
+ outb dx, al
+ shr eax, #8
+ outb dx, al
+ shr eax, #8
+ outb dx, al
+ shr eax, #8
+ outb dx, al
+
+ mov eax,ebx
+ call APMSYM(put_num)
+
+ mov al, #0x3b
+ outb dx,al
+ mov al, #0x20
+ outb dx,al
+ ret
+
+APMSYM(put_regs):
+ push eax
+ push edx
+ push ebx
+ mov dx, #INFO_PORT
+
+ mov ebx, eax
+ mov eax, #0x3d584145 // 'EAX='
+ call APMSYM(put_reg)
+ pop ebx
+ push ebx
+ mov eax, #0x3d584245 // 'EBX='
+ call APMSYM(put_reg)
+ mov ebx, ecx
+ mov eax, #0x3d584345 // 'ECX='
+ call APMSYM(put_reg)
+ mov ebx, edx
+ mov eax, #0x3d584445 // 'EDX='
+ call APMSYM(put_reg)
+ mov ebx, esi
+ mov eax, #0x3d495345 // 'ESI='
+ call APMSYM(put_reg)
+ mov ebx, edi
+ mov eax, #0x3d494445 // 'EDI='
+ call APMSYM(put_reg)
+
+ mov al, #0x0a
+ outb dx, al
+ pop ebx
+ pop edx
+ pop eax
+ ret
+#endif
+
+#if defined(APM_PROT32)
+_apm32_entry:
+#endif
+#if defined(APM_PROT16)
+_apm16_entry:
+#endif
+ pushf
+
+#if defined(APM_REAL)
+_apmreal_entry:
+#endif
+
+#if DEBUG_APM
+ call APMSYM(put_regs)
+#endif
+
+#if defined(APM_REAL)
+;-----------------
+; APM installation check
+APMSYM(00):
+ cmp al, #0x00
+ jne APMSYM(01)
+
+ mov ah, #1 // APM major version
+ mov al, #2 // APM minor version
+
+ mov bh, #0x50 // 'P'
+ mov bl, #0x4d // 'M'
+
+ // bit 0 : 16 bit interface supported
+ // bit 1 : 32 bit interface supported
+ mov cx, #0x3
+ jmp APMSYM(ok)
+
+;-----------------
+; APM real mode interface connect
+APMSYM(01):
+ cmp al, #0x01
+ jne APMSYM(02)
+ jmp APMSYM(ok)
+
+;-----------------
+; APM 16 bit protected mode interface connect
+APMSYM(02):
+ cmp al, #0x02
+ jne APMSYM(03)
+
+ mov bx, #_apm16_entry
+
+ mov ax, #0xf000 // 16 bit code segment base
+ mov si, #0xfff0 // 16 bit code segment size
+ mov cx, #0xf000 // data segment address
+ mov di, #0xfff0 // data segment length
+ jmp APMSYM(ok)
+
+;-----------------
+; APM 32 bit protected mode interface connect
+APMSYM(03):
+ cmp al, #0x03
+ jne APMSYM(04)
+ mov ax, #0xf000 // 32 bit code segment base
+ mov ebx, #_apm32_entry
+ mov cx, #0xf000 // 16 bit code segment base
+ // 32 bit code segment size (low 16 bits)
+ // 16 bit code segment size (high 16 bits)
+ mov esi, #0xfff0fff0
+ mov dx, #0xf000 // data segment address
+ mov di, #0xfff0 // data segment length
+ jmp APMSYM(ok)
+#endif
+
+;-----------------
+; APM interface disconnect
+APMSYM(04):
+ cmp al, #0x04
+ jne APMSYM(05)
+ jmp APMSYM(ok)
+
+;-----------------
+; APM cpu idle
+APMSYM(05):
+ cmp al, #0x05
+ jne APMSYM(07)
+ sti
+ hlt
+ jmp APMSYM(ok)
+
+;-----------------
+; APM Set Power State
+APMSYM(07):
+ cmp al, #0x07
+ jne APMSYM(08)
+
+ cmp bx, #1
+ jne APMSYM(ok)
+
+ cmp cx, #3
+ je APMSYM(07_poweroff)
+
+ cmp cx, #2
+ je APMSYM(07_suspend)
+
+ cmp cx, #1
+ je APMSYM(07_standby)
+
+ jne APMSYM(ok)
+
+APMSYM(07_poweroff):
+ // send power off event to emulator
+ cli
+ mov dx, #0x8900
+ mov ax, #APMSYM(07_poweroff_str)
+ call APMSYM(out_str)
+
+APMSYM(07_1):
+ hlt
+ jmp APMSYM(07_1)
+
+APMSYM(07_suspend):
+ push edx
+ mov dx, #0x8900
+ mov ax, #APMSYM(07_suspend_str)
+ call APMSYM(out_str)
+ pop edx
+ jmp APMSYM(ok)
+
+APMSYM(07_standby):
+ push edx
+ mov dx, #0x8900
+ mov ax, #APMSYM(07_standby_str)
+ call APMSYM(out_str)
+ pop edx
+ jmp APMSYM(ok)
+
+;-----------------
+; APM Enable / Disable
+APMSYM(08):
+ cmp al, #0x08
+ jne APMSYM(0a)
+
+ jmp APMSYM(ok)
+
+;-----------------
+; Get Power Status
+APMSYM(0a):
+ cmp al, #0x0a
+ jne APMSYM(0b)
+ mov bh, #0x01 // on line
+ // mov bh, #0x02 // battery
+ mov bl, #0xff // unknown battery status
+ // mov bl, #0x03 // charging
+ mov ch, #0x80 // no system battery
+ // mov ch, #0x8 // charging
+ mov cl, #0xff // unknown remaining time
+ // mov cl, #50
+ mov dx, #0xffff // unknown remaining time
+ mov si, #0 // zero battery
+ // mov si, #1 // one battery
+ jmp APMSYM(ok)
+
+;-----------------
+; Get PM Event
+APMSYM(0b):
+ cmp al, #0x0b
+ jne APMSYM(0e)
+ mov ah, #0x80 // no event pending
+ jmp APMSYM(error)
+
+;-----------------
+; APM Driver Version
+APMSYM(0e):
+ cmp al, #0x0e
+ jne APMSYM(0f)
+
+ mov ah, #1
+ mov al, #2
+
+ jmp APMSYM(ok)
+
+;-----------------
+; APM Engage / Disengage
+APMSYM(0f):
+ cmp al, #0x0f
+ jne APMSYM(10)
+
+ jmp APMSYM(ok)
+
+;-----------------
+; APM Get Capabilities
+APMSYM(10):
+ cmp al, #0x10
+ jne APMSYM(unimplemented)
+
+ mov bl, #0
+ mov cx, #0
+
+ jmp APMSYM(ok)
+
+;-----------------
+APMSYM(ok):
+ popf
+ clc
+#if defined(APM_REAL)
+ jmp iret_modify_cf
+#else
+ retf
+#endif
+APMSYM(unimplemented):
+APMSYM(error):
+ popf
+ stc
+#if defined(APM_REAL)
+ jmp iret_modify_cf
+#else
+ retf
+#endif
+
+#undef APM_PROT32
+#undef APM_PROT16
+#undef APM_REAL
+#undef APMSYM
diff --git a/bochs/bios/bios_usage b/bochs/bios/bios_usage
new file mode 100644
index 0000000..8019ef6
--- /dev/null
+++ b/bochs/bios/bios_usage
@@ -0,0 +1,4 @@
+#!/bin/csh -f
+gcc -E rombios.c | grep "^\.org" | sed -e 's/\.org //' | sed -e 's/ .*//' | sort >! temp.usage
+usage rombios.bin temp.usage
+/bin/rm temp.usage
diff --git a/bochs/bios/biossums.c b/bochs/bios/biossums.c
new file mode 100644
index 0000000..c7680b4
--- /dev/null
+++ b/bochs/bios/biossums.c
@@ -0,0 +1,504 @@
+/*
+ * $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* biossums.c --- written by Eike W. for the Bochs BIOS */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+typedef unsigned char byte;
+
+void check( int value, char* message );
+
+#define LEN_BIOS_DATA 0x10000
+#define MAX_OFFSET (LEN_BIOS_DATA - 1)
+
+
+#define BIOS_OFFSET 0xFFFF
+
+long chksum_bios_get_offset( byte* data, long offset );
+byte chksum_bios_calc_value( byte* data, long offset );
+byte chksum_bios_get_value( byte* data, long offset );
+void chksum_bios_set_value( byte* data, long offset, byte value );
+
+
+#define _32__LEN 9
+#define _32__CHKSUM 10
+
+#define _32__MINHDR 16
+
+long chksum__32__get_offset( byte* data, long offset );
+byte chksum__32__calc_value( byte* data, long offset );
+byte chksum__32__get_value( byte* data, long offset );
+void chksum__32__set_value( byte* data, long offset, byte value );
+
+
+#define _MP__LEN 8
+#define _MP__CHKSUM 10
+
+#define _MP__MINHDR 16
+
+long chksum__mp__get_offset( byte* data, long offset );
+byte chksum__mp__calc_value( byte* data, long offset );
+byte chksum__mp__get_value( byte* data, long offset );
+void chksum__mp__set_value( byte* data, long offset, byte value );
+
+
+#define PCMP_BASELEN 4
+#define PCMP_CHKSUM 7
+#define PCMP_EXT_LEN 40
+#define PCMP_EXT_CHKSUM 42
+
+#define PCMP_MINHDR 42
+
+long chksum_pcmp_get_offset( byte* data, long offset );
+byte chksum_pcmp_calc_value( byte* data, long offset );
+byte chksum_pcmp_get_value( byte* data, long offset );
+void chksum_pcmp_set_value( byte* data, long offset, byte value );
+
+
+#define _PIR_LEN 6
+#define _PIR_CHKSUM 31
+
+#define _PIR_MINHDR 32
+
+long chksum__pir_get_offset( byte *data, long offset );
+byte chksum__pir_calc_value( byte* data, long offset );
+byte chksum__pir_get_value( byte* data, long offset );
+void chksum__pir_set_value( byte* data, long offset, byte value );
+
+
+byte bios_data[LEN_BIOS_DATA];
+long bios_len;
+
+
+int main(int argc, char* argv[]) {
+
+ FILE* stream;
+ long offset, tmp_offset;
+ byte cur_val = 0, new_val = 0;
+ int arg = 1, hits, pad = 0;
+
+
+ if ((argc == 3) && (!strcmp(argv[1], "-pad"))) {
+ pad = 1;
+ arg = 2;
+ } else if (argc != 2) {
+ printf("Error. Need a file-name as an argument.\n");
+ exit(EXIT_FAILURE);
+ }
+ memset(bios_data, 0xff, LEN_BIOS_DATA);
+
+ if ((stream = fopen(argv[arg], "rb")) == NULL) {
+ printf("Error opening %s for reading.\n", argv[arg]);
+ exit(EXIT_FAILURE);
+ }
+ bios_len = fread(bios_data, 1, LEN_BIOS_DATA, stream);
+ if ((bios_len < LEN_BIOS_DATA) && (pad == 0)) {
+ printf("Error reading 64KBytes from %s.\n", argv[arg]);
+ fclose(stream);
+ exit(EXIT_FAILURE);
+ }
+ fclose(stream);
+ if (pad == 1) goto write_bios;
+
+ hits = 0;
+ offset = 0L;
+ while( (tmp_offset = chksum__32__get_offset( bios_data, offset )) != -1L ) {
+ offset = tmp_offset;
+ cur_val = chksum__32__get_value( bios_data, offset );
+ new_val = chksum__32__calc_value( bios_data, offset );
+ printf( "\n\nPCI-Bios header at: 0x%4lX\n", offset );
+ printf( "Current checksum: 0x%02X\n", cur_val );
+ printf( "Calculated checksum: 0x%02X ", new_val );
+ hits++;
+ }
+ if( hits == 1 && cur_val != new_val ) {
+ printf( "Setting checksum." );
+ chksum__32__set_value( bios_data, offset, new_val );
+ }
+ if( hits >= 2 ) {
+ printf( "Multiple PCI headers! No checksum set." );
+ }
+ if( hits ) {
+ printf( "\n" );
+ }
+
+
+ hits = 0;
+ offset = 0L;
+ while( (tmp_offset = chksum__mp__get_offset( bios_data, offset )) != -1L ) {
+ offset = tmp_offset;
+ cur_val = chksum__mp__get_value( bios_data, offset );
+ new_val = chksum__mp__calc_value( bios_data, offset );
+ printf( "\n\nMP header at: 0x%4lX\n", offset );
+ printf( "Current checksum: 0x%02X\n", cur_val );
+ printf( "Calculated checksum: 0x%02X ", new_val );
+ hits++;
+ }
+ if( hits == 1 && cur_val != new_val ) {
+ printf( "Setting checksum." );
+ chksum__mp__set_value( bios_data, offset, new_val );
+ }
+ if( hits >= 2 ) {
+ printf( "Warning! Multiple MP headers. No checksum set." );
+ }
+ if( hits ) {
+ printf( "\n" );
+ }
+
+
+ hits = 0;
+ offset = 0L;
+ while( (tmp_offset = chksum_pcmp_get_offset( bios_data, offset )) != -1L ) {
+ offset = tmp_offset;
+ cur_val = chksum_pcmp_get_value( bios_data, offset );
+ new_val = chksum_pcmp_calc_value( bios_data, offset );
+ printf( "\n\nPCMP header at: 0x%4lX\n", offset );
+ printf( "Current checksum: 0x%02X\n", cur_val );
+ printf( "Calculated checksum: 0x%02X ", new_val );
+ hits++;
+ }
+ if( hits == 1 && cur_val != new_val ) {
+ printf( "Setting checksum." );
+ chksum_pcmp_set_value( bios_data, offset, new_val );
+ }
+ if( hits >= 2 ) {
+ printf( "Warning! Multiple PCMP headers. No checksum set." );
+ }
+ if( hits ) {
+ printf( "\n" );
+ }
+
+
+ hits = 0;
+ offset = 0L;
+ while( (tmp_offset = chksum__pir_get_offset( bios_data, offset )) != -1L ) {
+ offset = tmp_offset;
+ cur_val = chksum__pir_get_value( bios_data, offset );
+ new_val = chksum__pir_calc_value( bios_data, offset );
+ printf( "\n\n$PIR header at: 0x%4lX\n", offset );
+ printf( "Current checksum: 0x%02X\n", cur_val );
+ printf( "Calculated checksum: 0x%02X\n ", new_val );
+ hits++;
+ }
+ if( hits == 1 && cur_val != new_val ) {
+ printf( "Setting checksum." );
+ chksum__pir_set_value( bios_data, offset, new_val );
+ }
+ if( hits >= 2 ) {
+ printf( "Warning! Multiple $PIR headers. No checksum set." );
+ }
+ if( hits ) {
+ printf( "\n" );
+ }
+
+
+ offset = 0L;
+ offset = chksum_bios_get_offset( bios_data, offset );
+ cur_val = chksum_bios_get_value( bios_data, offset );
+ new_val = chksum_bios_calc_value( bios_data, offset );
+ printf( "\n\nBios checksum at: 0x%4lX\n", offset );
+ printf( "Current checksum: 0x%02X\n", cur_val );
+ printf( "Calculated checksum: 0x%02X ", new_val );
+ if( cur_val != new_val ) {
+ printf( "Setting checksum." );
+ chksum_bios_set_value( bios_data, offset, new_val );
+ }
+ printf( "\n" );
+
+write_bios:
+ if ((stream = fopen(argv[arg], "wb")) == NULL) {
+ printf("Error opening %s for writing.\n", argv[arg]);
+ exit(EXIT_FAILURE);
+ }
+ if (fwrite(bios_data, 1, LEN_BIOS_DATA, stream) < LEN_BIOS_DATA) {
+ printf("Error writing 64KBytes to %s.\n", argv[arg]);
+ fclose(stream);
+ exit(EXIT_FAILURE);
+ }
+ fclose(stream);
+
+ return(EXIT_SUCCESS);
+}
+
+
+void check(int okay, char* message) {
+
+ if (!okay) {
+ printf("\n\nError. %s.\n", message);
+ exit(EXIT_FAILURE);
+ }
+}
+
+
+long chksum_bios_get_offset( byte* data, long offset ) {
+
+ return( BIOS_OFFSET );
+}
+
+
+byte chksum_bios_calc_value( byte* data, long offset ) {
+
+ int i;
+ byte sum;
+
+ sum = 0;
+ for( i = 0; i < MAX_OFFSET; i++ ) {
+ sum = sum + *( data + i );
+ }
+ sum = -sum; /* iso ensures -s + s == 0 on unsigned types */
+ return( sum );
+}
+
+
+byte chksum_bios_get_value( byte* data, long offset ) {
+
+ return( *( data + BIOS_OFFSET ) );
+}
+
+
+void chksum_bios_set_value( byte* data, long offset, byte value ) {
+
+ *( data + BIOS_OFFSET ) = value;
+}
+
+
+byte chksum__32__calc_value( byte* data, long offset ) {
+
+ int i;
+ int len;
+ byte sum;
+
+ check( offset + _32__MINHDR <= MAX_OFFSET, "_32_ header out of bounds" );
+ len = *( data + offset + _32__LEN ) << 4;
+ check( offset + len <= MAX_OFFSET, "_32_ header-length out of bounds" );
+ sum = 0;
+ for( i = 0; i < len; i++ ) {
+ if( i != _32__CHKSUM ) {
+ sum = sum + *( data + offset + i );
+ }
+ }
+ sum = -sum;
+ return( sum );
+}
+
+
+long chksum__32__get_offset( byte* data, long offset ) {
+
+ long result = -1L;
+
+ offset = offset + 0x0F;
+ offset = offset & ~( 0x0F );
+ while( offset + 16 < MAX_OFFSET ) {
+ offset = offset + 16;
+ if( *( data + offset + 0 ) == '_' && \
+ *( data + offset + 1 ) == '3' && \
+ *( data + offset + 2 ) == '2' && \
+ *( data + offset + 3 ) == '_' ) {
+ result = offset;
+ break;
+ }
+ }
+ return( result );
+}
+
+
+byte chksum__32__get_value( byte* data, long offset ) {
+
+ check( offset + _32__CHKSUM <= MAX_OFFSET, "PCI-Bios checksum out of bounds" );
+ return( *( data + offset + _32__CHKSUM ) );
+}
+
+
+void chksum__32__set_value( byte* data, long offset, byte value ) {
+
+ check( offset + _32__CHKSUM <= MAX_OFFSET, "PCI-Bios checksum out of bounds" );
+ *( data + offset + _32__CHKSUM ) = value;
+}
+
+
+byte chksum__mp__calc_value( byte* data, long offset ) {
+
+ int i;
+ int len;
+ byte sum;
+
+ check( offset + _MP__MINHDR <= MAX_OFFSET, "_MP_ header out of bounds" );
+ len = *( data + offset + _MP__LEN ) << 4;
+ check( offset + len <= MAX_OFFSET, "_MP_ header-length out of bounds" );
+ sum = 0;
+ for( i = 0; i < len; i++ ) {
+ if( i != _MP__CHKSUM ) {
+ sum = sum + *( data + offset + i );
+ }
+ }
+ sum = -sum;
+ return( sum );
+}
+
+
+long chksum__mp__get_offset( byte* data, long offset ) {
+
+ long result = -1L;
+
+ offset = offset + 0x0F;
+ offset = offset & ~( 0x0F );
+ while( offset + 16 < MAX_OFFSET ) {
+ offset = offset + 16;
+ if( *( data + offset + 0 ) == '_' && \
+ *( data + offset + 1 ) == 'M' && \
+ *( data + offset + 2 ) == 'P' && \
+ *( data + offset + 3 ) == '_' ) {
+ result = offset;
+ break;
+ }
+ }
+ return( result );
+}
+
+
+byte chksum__mp__get_value( byte* data, long offset ) {
+
+ check( offset + _MP__CHKSUM <= MAX_OFFSET, "MP checksum out of bounds" );
+ return( *( data + offset + _MP__CHKSUM ) );
+}
+
+
+void chksum__mp__set_value( byte* data, long offset, byte value ) {
+
+ check( offset + _MP__CHKSUM <= MAX_OFFSET, "MP checksum out of bounds" );
+ *( data + offset + _MP__CHKSUM ) = value;
+}
+
+
+byte chksum_pcmp_calc_value( byte* data, long offset ) {
+
+ int i;
+ int len;
+ byte sum;
+
+ check( offset + PCMP_MINHDR <= MAX_OFFSET, "PCMP header out of bounds" );
+ len = *( data + offset + PCMP_BASELEN ) + \
+ ( *( data + offset + PCMP_BASELEN + 1 ) << 8 );
+ check( offset + len <= MAX_OFFSET, "PCMP header-length out of bounds" );
+ if( *( data + offset + PCMP_EXT_LEN ) | \
+ *( data + offset + PCMP_EXT_LEN + 1 ) | \
+ *( data + offset + PCMP_EXT_CHKSUM ) ) {
+ check( 0, "PCMP header indicates extended tables (unsupported)" );
+ }
+ sum = 0;
+ for( i = 0; i < len; i++ ) {
+ if( i != PCMP_CHKSUM ) {
+ sum = sum + *( data + offset + i );
+ }
+ }
+ sum = -sum;
+ return( sum );
+}
+
+
+long chksum_pcmp_get_offset( byte* data, long offset ) {
+
+ long result = -1L;
+
+ offset = offset + 0x0F;
+ offset = offset & ~( 0x0F );
+ while( offset + 16 < MAX_OFFSET ) {
+ offset = offset + 16;
+ if( *( data + offset + 0 ) == 'P' && \
+ *( data + offset + 1 ) == 'C' && \
+ *( data + offset + 2 ) == 'M' && \
+ *( data + offset + 3 ) == 'P' ) {
+ result = offset;
+ break;
+ }
+ }
+ return( result );
+}
+
+
+byte chksum_pcmp_get_value( byte* data, long offset ) {
+
+ check( offset + PCMP_CHKSUM <= MAX_OFFSET, "PCMP checksum out of bounds" );
+ return( *( data + offset + PCMP_CHKSUM ) );
+}
+
+
+void chksum_pcmp_set_value( byte* data, long offset, byte value ) {
+
+ check( offset + PCMP_CHKSUM <= MAX_OFFSET, "PCMP checksum out of bounds" );
+ *( data + offset + PCMP_CHKSUM ) = value;
+}
+
+
+byte chksum__pir_calc_value( byte* data, long offset ) {
+
+ int i;
+ int len;
+ byte sum;
+
+ check( offset + _PIR_MINHDR <= MAX_OFFSET, "$PIR header out of bounds" );
+ len = *( data + offset + _PIR_LEN ) + \
+ ( *( data + offset + _PIR_LEN + 1 ) << 8 );
+ check( offset + len <= MAX_OFFSET, "$PIR header-length out of bounds" );
+ sum = 0;
+ for( i = 0; i < len; i++ ) {
+ if( i != _PIR_CHKSUM ) {
+ sum = sum + *( data + offset + i );
+ }
+ }
+ sum = -sum;
+ return( sum );
+}
+
+
+long chksum__pir_get_offset( byte* data, long offset ) {
+
+ long result = -1L;
+
+ offset = offset + 0x0F;
+ offset = offset & ~( 0x0F );
+ while( offset + 16 < MAX_OFFSET ) {
+ offset = offset + 16;
+ if( *( data + offset + 0 ) == '$' && \
+ *( data + offset + 1 ) == 'P' && \
+ *( data + offset + 2 ) == 'I' && \
+ *( data + offset + 3 ) == 'R' ) {
+ result = offset;
+ break;
+ }
+ }
+ return( result );
+}
+
+
+byte chksum__pir_get_value( byte* data, long offset ) {
+
+ check( offset + _PIR_CHKSUM <= MAX_OFFSET, "$PIR checksum out of bounds" );
+ return( *( data + offset + _PIR_CHKSUM ) );
+}
+
+
+void chksum__pir_set_value( byte* data, long offset, byte value ) {
+
+ check( offset + _PIR_CHKSUM <= MAX_OFFSET, "$PIR checksum out of bounds" );
+ *( data + offset + _PIR_CHKSUM ) = value;
+}
+
diff --git a/bochs/bios/makesym.perl b/bochs/bios/makesym.perl
new file mode 100755
index 0000000..0b6c94a
--- /dev/null
+++ b/bochs/bios/makesym.perl
@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+#
+# $Id$
+#
+# Read output file from as86 (e.g. rombios.txt) and write out a symbol
+# table suitable for the Bochs debugger.
+#
+
+$WHERE_BEFORE_SYM_TABLE = 0;
+$WHERE_IN_SYM_TABLE = 1;
+$WHERE_AFTER_SYM_TABLE = 2;
+
+$where = $WHERE_BEFORE_SYM_TABLE;
+while (<STDIN>) {
+ chop;
+ if ($where == WHERE_BEFORE_SYM_TABLE && /^Symbols:/) {
+ $where = $WHERE_IN_SYM_TABLE;
+ } elsif ($where == $WHERE_IN_SYM_TABLE && /^$/) {
+ $where = $WHERE_AFTER_SYM_TABLE;
+ }
+ if ($where == $WHERE_IN_SYM_TABLE) {
+ @F = split (/\s+/);
+ ($name[0], $junk, $addr[0], $junk, $name[1], $junk, $addr[1]) = @F;
+ foreach $col (0,1) {
+ next if length $addr[$col] < 1;
+ $addr[$col] =~ tr/A-Z/a-z/;
+ $addr[$col] = "000f" . $addr[$col];
+ print "$addr[$col] $name[$col]\n";
+ }
+ }
+}
diff --git a/bochs/bios/notes b/bochs/bios/notes
new file mode 100644
index 0000000..ae1073e
--- /dev/null
+++ b/bochs/bios/notes
@@ -0,0 +1,44 @@
+####################
+# Read Disk Sector #
+####################
+
+System programming:
+-------------------
+
+(Int 13h, ah=2)
+in 1f7 until BSY cleared
+out 1f2, AL # number of sectors
+out 1f3, cl (bits 0-5) # starting sector number
+out 1f4, ch # cylinder number bits 0..7, 0 based
+out 1f5, cl (bits 6,7) & dh (bits 6,7) # cyl, bits 8..9, 10..11
+out 1f6, dh (bits 0..3) --> bits 0..3 # head number
+ dh (bits 4..5) --> ??? # head number
+ dl (bit 0) --> bit 4 # drive number
+out 1f7, 0x20 # read sectors command normal
+
+
+
+Drive response:
+---------------
+
+* drive sets the busy bit in Status Reg to 1
+* if command parameters are wrong:
+ > drive sets the aborted-command bit in the Error register and
+ error bit in the Status register to 1.
+ > Drive also sets the busy bit in the Status register to 0.
+ > Drive then generates an interrupt to the system.
+* else:
+ > drive executes an implied seek to desired track and
+ reads sectors into sector buffer
+ > when sector buffer is filled and the data is ready to be
+ transferred, the drive sets the data-request bit to 1, sets
+ the busy bit to 0, and generates an interrupt.
+ > on a single-sector transfer, after the system has transferred
+ the data, the drive sets the data-request bit and the busy bit to 0.
+ > on a multiple-sector transfer, after the system has transferred
+ the first sector of data, the drive sets the data-request bit to 0,
+ and the busy bit to 1. When each subsequent sector is ready to be
+ transferred, the drive sets the data-request bit to 1, the busy bit to 0,
+ and generates an interrupt. When the system has tranferred the last sector,
+ the drive sets the data-request bit and busy bit to 0.
+
diff --git a/bochs/bios/rombios.c b/bochs/bios/rombios.c
new file mode 100644
index 0000000..0f13b53
--- /dev/null
+++ b/bochs/bios/rombios.c
@@ -0,0 +1,11407 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id$
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
+
+
+// ROM BIOS compatability entry points:
+// ===================================
+// $e05b ; POST Entry Point
+// $e2c3 ; NMI Handler Entry Point
+// $e3fe ; INT 13h Fixed Disk Services Entry Point
+// $e401 ; Fixed Disk Parameter Table
+// $e6f2 ; INT 19h Boot Load Service Entry Point
+// $e6f5 ; Configuration Data Table
+// $e729 ; Baud Rate Generator Table
+// $e739 ; INT 14h Serial Communications Service Entry Point
+// $e82e ; INT 16h Keyboard Service Entry Point
+// $e987 ; INT 09h Keyboard Service Entry Point
+// $ec59 ; INT 13h Diskette Service Entry Point
+// $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
+// $efc7 ; Diskette Controller Parameter Table
+// $efd2 ; INT 17h Printer Service Entry Point
+// $f045 ; INT 10 Functions 0-Fh Entry Point
+// $f065 ; INT 10h Video Support Service Entry Point
+// $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
+// $f841 ; INT 12h Memory Size Service Entry Point
+// $f84d ; INT 11h Equipment List Service Entry Point
+// $f859 ; INT 15h System Services Entry Point
+// $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
+// $fe6e ; INT 1Ah Time-of-day Service Entry Point
+// $fea5 ; INT 08h System Timer ISR Entry Point
+// $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
+// $ff53 ; IRET Instruction for Dummy Interrupt Handler
+// $ff54 ; INT 05h Print Screen Service Entry Point
+// $fff0 ; Power-up Entry Point
+// $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
+// $fffe ; System Model ID
+
+// NOTES for ATA/ATAPI driver (cbbochs@free.fr)
+// Features
+// - supports up to 4 ATA interfaces
+// - device/geometry detection
+// - 16bits/32bits device access
+// - pchs/lba access
+// - datain/dataout/packet command support
+//
+// NOTES for El-Torito Boot (cbbochs@free.fr)
+// - CD-ROM booting is only available if ATA/ATAPI Driver is available
+// - Current code is only able to boot mono-session cds
+// - Current code can not boot and emulate a hard-disk
+// the bios will panic otherwise
+// - Current code also use memory in EBDA segement.
+// - I used cmos byte 0x3D to store extended information on boot-device
+// - Code has to be modified modified to handle multiple cdrom drives
+// - Here are the cdrom boot failure codes:
+// 1 : no atapi device found
+// 2 : no atapi cdrom found
+// 3 : can not read cd - BRVD
+// 4 : cd is not eltorito (BRVD)
+// 5 : cd is not eltorito (ISO TAG)
+// 6 : cd is not eltorito (ELTORITO TAG)
+// 7 : can not read cd - boot catalog
+// 8 : boot catalog : bad header
+// 9 : boot catalog : bad platform
+// 10 : boot catalog : bad signature
+// 11 : boot catalog : bootable flag not set
+// 12 : can not read cd - boot image
+//
+// ATA driver
+// - EBDA segment.
+// I used memory starting at 0x121 in the segment
+// - the translation policy is defined in cmos regs 0x39 & 0x3a
+//
+// TODO :
+//
+// int74
+// - needs to be reworked. Uses direct [bp] offsets. (?)
+//
+// int13:
+// - f04 (verify sectors) isn't complete (?)
+// - f02/03/04 should set current cyl,etc in BDA (?)
+// - rewrite int13_relocated & clean up int13 entry code
+//
+// NOTES:
+// - NMI access (bit7 of addr written to 70h)
+//
+// ATA driver
+// - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
+// - could send the multiple-sector read/write commands
+//
+// El-Torito
+// - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
+// - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
+// - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
+// - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
+// This is ok. But DL should be reincremented afterwards.
+// - Fix all "FIXME ElTorito Various"
+// - should be able to boot any cdrom instead of the first one
+//
+// BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
+
+#include "rombios.h"
+
+#define DEBUG_ATA 0
+#define DEBUG_INT13_HD 0
+#define DEBUG_INT13_CD 0
+#define DEBUG_INT13_ET 0
+#define DEBUG_INT13_FL 0
+#define DEBUG_INT15 0
+#define DEBUG_INT16 0
+#define DEBUG_INT1A 0
+#define DEBUG_INT74 0
+#define DEBUG_APM 0
+
+#define BX_CPU 3
+#define BX_USE_PS2_MOUSE 1
+#define BX_CALL_INT15_4F 1
+#define BX_USE_EBDA 1
+#define BX_SUPPORT_FLOPPY 1
+#define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
+#define BX_PCIBIOS 1
+#define BX_APM 1
+
+#define BX_USE_ATADRV 1
+#define BX_ELTORITO_BOOT 1
+
+#define BX_MAX_ATA_INTERFACES 4
+#define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
+
+#define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
+#define BX_DEBUG_SERIAL 0 /* output to COM1 */
+
+ /* model byte 0xFC = AT */
+#define SYS_MODEL_ID 0xFC
+#define SYS_SUBMODEL_ID 0x00
+#define BIOS_REVISION 1
+#define BIOS_CONFIG_TABLE 0xe6f5
+
+#ifndef BIOS_BUILD_DATE
+# define BIOS_BUILD_DATE "06/23/99"
+#endif
+
+ // 1K of base memory used for Extended Bios Data Area (EBDA)
+ // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
+#define EBDA_SEG 0x9FC0
+#define EBDA_SIZE 1 // In KiB
+#define BASE_MEM_IN_K (640 - EBDA_SIZE)
+
+/* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */
+#define IPL_SEG 0x9ff0
+#define IPL_TABLE_OFFSET 0x0000
+#define IPL_TABLE_ENTRIES 8
+#define IPL_COUNT_OFFSET 0x0080 /* u16: number of valid table entries */
+#define IPL_SEQUENCE_OFFSET 0x0082 /* u16: next boot device */
+#define IPL_BOOTFIRST_OFFSET 0x0084 /* u16: user selected device */
+#define IPL_SIZE 0xff
+#define IPL_TYPE_FLOPPY 0x01
+#define IPL_TYPE_HARDDISK 0x02
+#define IPL_TYPE_CDROM 0x03
+#define IPL_TYPE_BEV 0x80
+
+ // Sanity Checks
+#if BX_USE_ATADRV && BX_CPU<3
+# error The ATA/ATAPI Driver can only to be used with a 386+ cpu
+#endif
+#if BX_USE_ATADRV && !BX_USE_EBDA
+# error ATA/ATAPI Driver can only be used if EBDA is available
+#endif
+#if BX_ELTORITO_BOOT && !BX_USE_ATADRV
+# error El-Torito Boot can only be use if ATA/ATAPI Driver is available
+#endif
+#if BX_PCIBIOS && BX_CPU<3
+# error PCI BIOS can only be used with 386+ cpu
+#endif
+#if BX_APM && BX_CPU<3
+# error APM BIOS can only be used with 386+ cpu
+#endif
+
+// define this if you want to make PCIBIOS working on a specific bridge only
+// undef enables PCIBIOS when at least one PCI device is found
+// i440FX is emulated by Bochs and QEMU
+#define PCI_FIXED_HOST_BRIDGE 0x12378086 ;; i440FX PCI bridge
+
+// #20 is dec 20
+// #$20 is hex 20 = 32
+// #0x20 is hex 20 = 32
+// LDA #$20
+// JSR $E820
+// LDD .i,S
+// JSR $C682
+// mov al, #$20
+
+// all hex literals should be prefixed with '0x'
+// grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
+// no mov SEG-REG, #value, must mov register into seg-reg
+// grep -i "mov[ ]*.s" rombios.c
+
+// This is for compiling with gcc2 and gcc3
+#define ASM_START #asm
+#define ASM_END #endasm
+
+ASM_START
+.rom
+
+.org 0x0000
+
+#if BX_CPU >= 3
+use16 386
+#else
+use16 286
+#endif
+
+MACRO HALT
+ ;; the HALT macro is called with the line number of the HALT call.
+ ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
+ ;; to print a BX_PANIC message. This will normally halt the simulation
+ ;; with a message such as "BIOS panic at rombios.c, line 4091".
+ ;; However, users can choose to make panics non-fatal and continue.
+#if BX_VIRTUAL_PORTS
+ mov dx,#PANIC_PORT
+ mov ax,#?1
+ out dx,ax
+#else
+ mov dx,#0x80
+ mov ax,#?1
+ out dx,al
+#endif
+MEND
+
+MACRO JMP_AP
+ db 0xea
+ dw ?2
+ dw ?1
+MEND
+
+MACRO SET_INT_VECTOR
+ mov ax, ?3
+ mov ?1*4, ax
+ mov ax, ?2
+ mov ?1*4+2, ax
+MEND
+
+ASM_END
+
+typedef unsigned char Bit8u;
+typedef unsigned short Bit16u;
+typedef unsigned short bx_bool;
+typedef unsigned long Bit32u;
+
+
+ void memsetb(seg,offset,value,count);
+ void memcpyb(dseg,doffset,sseg,soffset,count);
+ void memcpyd(dseg,doffset,sseg,soffset,count);
+
+ // memset of count bytes
+ void
+ memsetb(seg,offset,value,count)
+ Bit16u seg;
+ Bit16u offset;
+ Bit16u value;
+ Bit16u count;
+ {
+ ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push cx
+ push es
+ push di
+
+ mov cx, 10[bp] ; count
+ test cx, cx
+ je memsetb_end
+ mov ax, 4[bp] ; segment
+ mov es, ax
+ mov ax, 6[bp] ; offset
+ mov di, ax
+ mov al, 8[bp] ; value
+ cld
+ rep
+ stosb
+
+ memsetb_end:
+ pop di
+ pop es
+ pop cx
+ pop ax
+
+ pop bp
+ ASM_END
+ }
+
+ // memcpy of count bytes
+ void
+ memcpyb(dseg,doffset,sseg,soffset,count)
+ Bit16u dseg;
+ Bit16u doffset;
+ Bit16u sseg;
+ Bit16u soffset;
+ Bit16u count;
+ {
+ ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push cx
+ push es
+ push di
+ push ds
+ push si
+
+ mov cx, 12[bp] ; count
+ test cx, cx
+ je memcpyb_end
+ mov ax, 4[bp] ; dsegment
+ mov es, ax
+ mov ax, 6[bp] ; doffset
+ mov di, ax
+ mov ax, 8[bp] ; ssegment
+ mov ds, ax
+ mov ax, 10[bp] ; soffset
+ mov si, ax
+ cld
+ rep
+ movsb
+
+ memcpyb_end:
+ pop si
+ pop ds
+ pop di
+ pop es
+ pop cx
+ pop ax
+
+ pop bp
+ ASM_END
+ }
+
+ // memcpy of count dword
+ void
+ memcpyd(dseg,doffset,sseg,soffset,count)
+ Bit16u dseg;
+ Bit16u doffset;
+ Bit16u sseg;
+ Bit16u soffset;
+ Bit16u count;
+ {
+ ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push cx
+ push es
+ push di
+ push ds
+ push si
+
+ mov cx, 12[bp] ; count
+ test cx, cx
+ je memcpyd_end
+ mov ax, 4[bp] ; dsegment
+ mov es, ax
+ mov ax, 6[bp] ; doffset
+ mov di, ax
+ mov ax, 8[bp] ; ssegment
+ mov ds, ax
+ mov ax, 10[bp] ; soffset
+ mov si, ax
+ cld
+ rep
+ movsd
+
+ memcpyd_end:
+ pop si
+ pop ds
+ pop di
+ pop es
+ pop cx
+ pop ax
+
+ pop bp
+ ASM_END
+ }
+
+ // read_dword and write_dword functions
+ static Bit32u read_dword();
+ static void write_dword();
+
+ Bit32u
+ read_dword(seg, offset)
+ Bit16u seg;
+ Bit16u offset;
+ {
+ ASM_START
+ push bp
+ mov bp, sp
+
+ push bx
+ push ds
+ mov ax, 4[bp] ; segment
+ mov ds, ax
+ mov bx, 6[bp] ; offset
+ mov ax, [bx]
+ add bx, #2
+ mov dx, [bx]
+ ;; ax = return value (word)
+ ;; dx = return value (word)
+ pop ds
+ pop bx
+
+ pop bp
+ ASM_END
+ }
+
+ void
+ write_dword(seg, offset, data)
+ Bit16u seg;
+ Bit16u offset;
+ Bit32u data;
+ {
+ ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push bx
+ push ds
+ mov ax, 4[bp] ; segment
+ mov ds, ax
+ mov bx, 6[bp] ; offset
+ mov ax, 8[bp] ; data word
+ mov [bx], ax ; write data word
+ add bx, #2
+ mov ax, 10[bp] ; data word
+ mov [bx], ax ; write data word
+ pop ds
+ pop bx
+ pop ax
+
+ pop bp
+ ASM_END
+ }
+
+ // Bit32u (unsigned long) and long helper functions
+ ASM_START
+
+ ;; and function
+ landl:
+ landul:
+ SEG SS
+ and ax,[di]
+ SEG SS
+ and bx,2[di]
+ ret
+
+ ;; add function
+ laddl:
+ laddul:
+ SEG SS
+ add ax,[di]
+ SEG SS
+ adc bx,2[di]
+ ret
+
+ ;; cmp function
+ lcmpl:
+ lcmpul:
+ and eax, #0x0000FFFF
+ shl ebx, #16
+ or eax, ebx
+ shr ebx, #16
+ SEG SS
+ cmp eax, dword ptr [di]
+ ret
+
+ ;; sub function
+ lsubl:
+ lsubul:
+ SEG SS
+ sub ax,[di]
+ SEG SS
+ sbb bx,2[di]
+ ret
+
+ ;; mul function
+ lmull:
+ lmulul:
+ and eax, #0x0000FFFF
+ shl ebx, #16
+ or eax, ebx
+ SEG SS
+ mul eax, dword ptr [di]
+ mov ebx, eax
+ shr ebx, #16
+ ret
+
+ ;; dec function
+ ldecl:
+ ldecul:
+ SEG SS
+ dec dword ptr [bx]
+ ret
+
+ ;; or function
+ lorl:
+ lorul:
+ SEG SS
+ or ax,[di]
+ SEG SS
+ or bx,2[di]
+ ret
+
+ ;; inc function
+ lincl:
+ lincul:
+ SEG SS
+ inc dword ptr [bx]
+ ret
+
+ ;; tst function
+ ltstl:
+ ltstul:
+ and eax, #0x0000FFFF
+ shl ebx, #16
+ or eax, ebx
+ shr ebx, #16
+ test eax, eax
+ ret
+
+ ;; sr function
+ lsrul:
+ mov cx,di
+ jcxz lsr_exit
+ and eax, #0x0000FFFF
+ shl ebx, #16
+ or eax, ebx
+ lsr_loop:
+ shr eax, #1
+ loop lsr_loop
+ mov ebx, eax
+ shr ebx, #16
+ lsr_exit:
+ ret
+
+ ;; sl function
+ lsll:
+ lslul:
+ mov cx,di
+ jcxz lsl_exit
+ and eax, #0x0000FFFF
+ shl ebx, #16
+ or eax, ebx
+ lsl_loop:
+ shl eax, #1
+ loop lsl_loop
+ mov ebx, eax
+ shr ebx, #16
+ lsl_exit:
+ ret
+
+ idiv_:
+ cwd
+ idiv bx
+ ret
+
+ idiv_u:
+ xor dx,dx
+ div bx
+ ret
+
+ ldivul:
+ and eax, #0x0000FFFF
+ shl ebx, #16
+ or eax, ebx
+ xor edx, edx
+ SEG SS
+ mov bx, 2[di]
+ shl ebx, #16
+ SEG SS
+ mov bx, [di]
+ div ebx
+ mov ebx, eax
+ shr ebx, #16
+ ret
+
+ ASM_END
+
+// for access to RAM area which is used by interrupt vectors
+// and BIOS Data Area
+
+typedef struct {
+ unsigned char filler1[0x400];
+ unsigned char filler2[0x6c];
+ Bit16u ticks_low;
+ Bit16u ticks_high;
+ Bit8u midnight_flag;
+ } bios_data_t;
+
+#define BiosData ((bios_data_t *) 0)
+
+#if BX_USE_ATADRV
+ typedef struct {
+ Bit16u heads; // # heads
+ Bit16u cylinders; // # cylinders
+ Bit16u spt; // # sectors / track
+ } chs_t;
+
+ // DPTE definition
+ typedef struct {
+ Bit16u iobase1;
+ Bit16u iobase2;
+ Bit8u prefix;
+ Bit8u unused;
+ Bit8u irq;
+ Bit8u blkcount;
+ Bit8u dma;
+ Bit8u pio;
+ Bit16u options;
+ Bit16u reserved;
+ Bit8u revision;
+ Bit8u checksum;
+ } dpte_t;
+
+ typedef struct {
+ Bit8u iface; // ISA or PCI
+ Bit16u iobase1; // IO Base 1
+ Bit16u iobase2; // IO Base 2
+ Bit8u irq; // IRQ
+ } ata_channel_t;
+
+ typedef struct {
+ Bit8u type; // Detected type of ata (ata/atapi/none/unknown)
+ Bit8u device; // Detected type of attached devices (hd/cd/none)
+ Bit8u removable; // Removable device flag
+ Bit8u lock; // Locks for removable devices
+ Bit8u mode; // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
+ Bit16u blksize; // block size
+
+ Bit8u translation; // type of translation
+ chs_t lchs; // Logical CHS
+ chs_t pchs; // Physical CHS
+
+ Bit32u sectors_low; // Total sectors count
+ Bit32u sectors_high;
+ } ata_device_t;
+
+ typedef struct {
+ // ATA channels info
+ ata_channel_t channels[BX_MAX_ATA_INTERFACES];
+
+ // ATA devices info
+ ata_device_t devices[BX_MAX_ATA_DEVICES];
+ //
+ // map between (bios hd id - 0x80) and ata channels
+ Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES];
+
+ // map between (bios cd id - 0xE0) and ata channels
+ Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES];
+
+ // Buffer for DPTE table
+ dpte_t dpte;
+
+ // Count of transferred sectors and bytes
+ Bit16u trsfsectors;
+ Bit32u trsfbytes;
+
+ } ata_t;
+
+#if BX_ELTORITO_BOOT
+ // ElTorito Device Emulation data
+ typedef struct {
+ Bit8u active;
+ Bit8u media;
+ Bit8u emulated_drive;
+ Bit8u controller_index;
+ Bit16u device_spec;
+ Bit32u ilba;
+ Bit16u buffer_segment;
+ Bit16u load_segment;
+ Bit16u sector_count;
+
+ // Virtual device
+ chs_t vdevice;
+ } cdemu_t;
+#endif // BX_ELTORITO_BOOT
+
+ // for access to EBDA area
+ // The EBDA structure should conform to
+ // http://www.frontiernet.net/~fys/rombios.htm document
+ // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
+ // EBDA must be at most 768 bytes; it lives at EBDA_SEG, and the boot
+ // device tables are at IPL_SEG
+ typedef struct {
+ unsigned char filler1[0x3D];
+
+ // FDPT - Can be splitted in data members if needed
+ unsigned char fdpt0[0x10];
+ unsigned char fdpt1[0x10];
+
+ unsigned char filler2[0xC4];
+
+ // ATA Driver data
+ ata_t ata;
+
+#if BX_ELTORITO_BOOT
+ // El Torito Emulation data
+ cdemu_t cdemu;
+#endif // BX_ELTORITO_BOOT
+
+ } ebda_data_t;
+
+ #define EbdaData ((ebda_data_t *) 0)
+
+ // for access to the int13ext structure
+ typedef struct {
+ Bit8u size;
+ Bit8u reserved;
+ Bit16u count;
+ Bit16u offset;
+ Bit16u segment;
+ Bit32u lba1;
+ Bit32u lba2;
+ } int13ext_t;
+
+ #define Int13Ext ((int13ext_t *) 0)
+
+ // Disk Physical Table definition
+ typedef struct {
+ Bit16u size;
+ Bit16u infos;
+ Bit32u cylinders;
+ Bit32u heads;
+ Bit32u spt;
+ Bit32u sector_count1;
+ Bit32u sector_count2;
+ Bit16u blksize;
+ Bit16u dpte_offset;
+ Bit16u dpte_segment;
+ Bit16u key;
+ Bit8u dpi_length;
+ Bit8u reserved1;
+ Bit16u reserved2;
+ Bit8u host_bus[4];
+ Bit8u iface_type[8];
+ Bit8u iface_path[8];
+ Bit8u device_path[8];
+ Bit8u reserved3;
+ Bit8u checksum;
+ } dpt_t;
+
+ #define Int13DPT ((dpt_t *) 0)
+
+#endif // BX_USE_ATADRV
+
+typedef struct {
+ union {
+ struct {
+ Bit16u di, si, bp, sp;
+ Bit16u bx, dx, cx, ax;
+ } r16;
+ struct {
+ Bit16u filler[4];
+ Bit8u bl, bh, dl, dh, cl, ch, al, ah;
+ } r8;
+ } u;
+ } pusha_regs_t;
+
+typedef struct {
+ union {
+ struct {
+ Bit32u edi, esi, ebp, esp;
+ Bit32u ebx, edx, ecx, eax;
+ } r32;
+ struct {
+ Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
+ Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
+ } r16;
+ struct {
+ Bit32u filler[4];
+ Bit8u bl, bh;
+ Bit16u filler1;
+ Bit8u dl, dh;
+ Bit16u filler2;
+ Bit8u cl, ch;
+ Bit16u filler3;
+ Bit8u al, ah;
+ Bit16u filler4;
+ } r8;
+ } u;
+} pushad_regs_t;
+
+typedef struct {
+ union {
+ struct {
+ Bit16u flags;
+ } r16;
+ struct {
+ Bit8u flagsl;
+ Bit8u flagsh;
+ } r8;
+ } u;
+ } flags_t;
+
+#define SetCF(x) x.u.r8.flagsl |= 0x01
+#define SetZF(x) x.u.r8.flagsl |= 0x40
+#define ClearCF(x) x.u.r8.flagsl &= 0xfe
+#define ClearZF(x) x.u.r8.flagsl &= 0xbf
+#define GetCF(x) (x.u.r8.flagsl & 0x01)
+
+typedef struct {
+ Bit16u ip;
+ Bit16u cs;
+ flags_t flags;
+ } iret_addr_t;
+
+typedef struct {
+ Bit16u type;
+ Bit16u flags;
+ Bit32u vector;
+ Bit32u description;
+ Bit32u reserved;
+ } ipl_entry_t;
+
+
+
+static Bit8u inb();
+static Bit8u inb_cmos();
+static void outb();
+static void outb_cmos();
+static Bit16u inw();
+static void outw();
+static void init_rtc();
+static bx_bool rtc_updating();
+
+static Bit8u read_byte();
+static Bit16u read_word();
+static void write_byte();
+static void write_word();
+static void bios_printf();
+
+static Bit8u inhibit_mouse_int_and_events();
+static void enable_mouse_int_and_events();
+static Bit8u send_to_mouse_ctrl();
+static Bit8u get_mouse_data();
+static void set_kbd_command_byte();
+
+static void int09_function();
+static void int13_harddisk();
+static void int13_cdrom();
+static void int13_cdemu();
+static void int13_eltorito();
+static void int13_diskette_function();
+static void int14_function();
+static void int15_function();
+static void int16_function();
+static void int17_function();
+static void int19_function();
+static void int1a_function();
+static void int70_function();
+static void int74_function();
+static Bit16u get_CS();
+static Bit16u get_SS();
+static unsigned int enqueue_key();
+static unsigned int dequeue_key();
+static void get_hd_geometry();
+static void set_diskette_ret_status();
+static void set_diskette_current_cyl();
+static void determine_floppy_media();
+static bx_bool floppy_drive_exists();
+static bx_bool floppy_drive_recal();
+static bx_bool floppy_media_known();
+static bx_bool floppy_media_sense();
+static bx_bool set_enable_a20();
+static void debugger_on();
+static void debugger_off();
+static void keyboard_init();
+static void keyboard_panic();
+static void shutdown_status_panic();
+static void nmi_handler_msg();
+static void delay_ticks();
+static void delay_ticks_and_check_for_keystroke();
+
+static void interactive_bootkey();
+static void print_bios_banner();
+static void print_boot_device();
+static void print_boot_failure();
+static void print_cdromboot_failure();
+
+# if BX_USE_ATADRV
+
+// ATA / ATAPI driver
+void ata_init();
+void ata_detect();
+void ata_reset();
+
+Bit16u ata_cmd_non_data();
+Bit16u ata_cmd_data_in();
+Bit16u ata_cmd_data_out();
+Bit16u ata_cmd_packet();
+
+Bit16u atapi_get_sense();
+Bit16u atapi_is_ready();
+Bit16u atapi_is_cdrom();
+
+#endif // BX_USE_ATADRV
+
+#if BX_ELTORITO_BOOT
+
+void cdemu_init();
+Bit8u cdemu_isactive();
+Bit8u cdemu_emulated_drive();
+
+Bit16u cdrom_boot();
+
+#endif // BX_ELTORITO_BOOT
+
+static char bios_cvs_version_string[] = "$Revision$ $Date$";
+
+#define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
+
+#if DEBUG_ATA
+# define BX_DEBUG_ATA(a...) BX_DEBUG(a)
+#else
+# define BX_DEBUG_ATA(a...)
+#endif
+#if DEBUG_INT13_HD
+# define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
+#else
+# define BX_DEBUG_INT13_HD(a...)
+#endif
+#if DEBUG_INT13_CD
+# define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
+#else
+# define BX_DEBUG_INT13_CD(a...)
+#endif
+#if DEBUG_INT13_ET
+# define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
+#else
+# define BX_DEBUG_INT13_ET(a...)
+#endif
+#if DEBUG_INT13_FL
+# define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
+#else
+# define BX_DEBUG_INT13_FL(a...)
+#endif
+#if DEBUG_INT15
+# define BX_DEBUG_INT15(a...) BX_DEBUG(a)
+#else
+# define BX_DEBUG_INT15(a...)
+#endif
+#if DEBUG_INT16
+# define BX_DEBUG_INT16(a...) BX_DEBUG(a)
+#else
+# define BX_DEBUG_INT16(a...)
+#endif
+#if DEBUG_INT1A
+# define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
+#else
+# define BX_DEBUG_INT1A(a...)
+#endif
+#if DEBUG_INT74
+# define BX_DEBUG_INT74(a...) BX_DEBUG(a)
+#else
+# define BX_DEBUG_INT74(a...)
+#endif
+
+#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
+#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
+#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
+#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
+#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
+#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
+#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
+#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
+
+#define GET_AL() ( AX & 0x00ff )
+#define GET_BL() ( BX & 0x00ff )
+#define GET_CL() ( CX & 0x00ff )
+#define GET_DL() ( DX & 0x00ff )
+#define GET_AH() ( AX >> 8 )
+#define GET_BH() ( BX >> 8 )
+#define GET_CH() ( CX >> 8 )
+#define GET_DH() ( DX >> 8 )
+
+#define GET_ELDL() ( ELDX & 0x00ff )
+#define GET_ELDH() ( ELDX >> 8 )
+
+#define SET_CF() FLAGS |= 0x0001
+#define CLEAR_CF() FLAGS &= 0xfffe
+#define GET_CF() (FLAGS & 0x0001)
+
+#define SET_ZF() FLAGS |= 0x0040
+#define CLEAR_ZF() FLAGS &= 0xffbf
+#define GET_ZF() (FLAGS & 0x0040)
+
+#define UNSUPPORTED_FUNCTION 0x86
+
+#define none 0
+#define MAX_SCAN_CODE 0x58
+
+static struct {
+ Bit16u normal;
+ Bit16u shift;
+ Bit16u control;
+ Bit16u alt;
+ Bit8u lock_flags;
+ } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
+ { 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, 0x40 }, /* Q */
+ { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
+ { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
+ { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
+ { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
+ { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
+ { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
+ { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
+ { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
+ { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* 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, 0x40 }, /* A */
+ { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
+ { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
+ { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
+ { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
+ { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
+ { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
+ { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
+ { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* 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, 0x40 }, /* Z */
+ { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
+ { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
+ { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
+ { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
+ { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
+ { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* 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, 0x20 }, /* 7 Home */
+ { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
+ { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
+ { 0x4a2d, 0x4a2d, none, none, none }, /* - */
+ { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
+ { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
+ { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
+ { 0x4e2b, 0x4e2b, none, none, none }, /* + */
+ { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
+ { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
+ { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
+ { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
+ { 0x5300, 0x532e, none, none, 0x20 }, /* 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 */
+ };
+
+ Bit8u
+inb(port)
+ Bit16u port;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push dx
+ mov dx, 4[bp]
+ in al, dx
+ pop dx
+
+ pop bp
+ASM_END
+}
+
+#if BX_USE_ATADRV
+ Bit16u
+inw(port)
+ Bit16u port;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push dx
+ mov dx, 4[bp]
+ in ax, dx
+ pop dx
+
+ pop bp
+ASM_END
+}
+#endif
+
+ void
+outb(port, val)
+ Bit16u port;
+ Bit8u val;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push dx
+ mov dx, 4[bp]
+ mov al, 6[bp]
+ out dx, al
+ pop dx
+ pop ax
+
+ pop bp
+ASM_END
+}
+
+#if BX_USE_ATADRV
+ void
+outw(port, val)
+ Bit16u port;
+ Bit16u val;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push dx
+ mov dx, 4[bp]
+ mov ax, 6[bp]
+ out dx, ax
+ pop dx
+ pop ax
+
+ pop bp
+ASM_END
+}
+#endif
+
+ void
+outb_cmos(cmos_reg, val)
+ Bit8u cmos_reg;
+ Bit8u val;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ mov al, 4[bp] ;; cmos_reg
+ out 0x70, al
+ mov al, 6[bp] ;; val
+ out 0x71, al
+
+ pop bp
+ASM_END
+}
+
+ Bit8u
+inb_cmos(cmos_reg)
+ Bit8u cmos_reg;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ mov al, 4[bp] ;; cmos_reg
+ out 0x70, al
+ in al, 0x71
+
+ pop bp
+ASM_END
+}
+
+ void
+init_rtc()
+{
+ outb_cmos(0x0a, 0x26);
+ outb_cmos(0x0b, 0x02);
+ inb_cmos(0x0c);
+ inb_cmos(0x0d);
+}
+
+ bx_bool
+rtc_updating()
+{
+ // 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 244useconds.
+ // The count I use below guarantees coverage or more than
+ // this time, with any reasonable IPS setting.
+
+ Bit16u count;
+
+ count = 25000;
+ while (--count != 0) {
+ if ( (inb_cmos(0x0a) & 0x80) == 0 )
+ return(0);
+ }
+ return(1); // update-in-progress never transitioned to 0
+}
+
+
+ Bit8u
+read_byte(seg, offset)
+ Bit16u seg;
+ Bit16u offset;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push bx
+ push ds
+ mov ax, 4[bp] ; segment
+ mov ds, ax
+ mov bx, 6[bp] ; offset
+ mov al, [bx]
+ ;; al = return value (byte)
+ pop ds
+ pop bx
+
+ pop bp
+ASM_END
+}
+
+ Bit16u
+read_word(seg, offset)
+ Bit16u seg;
+ Bit16u offset;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push bx
+ push ds
+ mov ax, 4[bp] ; segment
+ mov ds, ax
+ mov bx, 6[bp] ; offset
+ mov ax, [bx]
+ ;; ax = return value (word)
+ pop ds
+ pop bx
+
+ pop bp
+ASM_END
+}
+
+ void
+write_byte(seg, offset, data)
+ Bit16u seg;
+ Bit16u offset;
+ Bit8u data;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push bx
+ push ds
+ mov ax, 4[bp] ; segment
+ mov ds, ax
+ mov bx, 6[bp] ; offset
+ mov al, 8[bp] ; data byte
+ mov [bx], al ; write data byte
+ pop ds
+ pop bx
+ pop ax
+
+ pop bp
+ASM_END
+}
+
+ void
+write_word(seg, offset, data)
+ Bit16u seg;
+ Bit16u offset;
+ Bit16u data;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push bx
+ push ds
+ mov ax, 4[bp] ; segment
+ mov ds, ax
+ mov bx, 6[bp] ; offset
+ mov ax, 8[bp] ; data word
+ mov [bx], ax ; write data word
+ pop ds
+ pop bx
+ pop ax
+
+ pop bp
+ASM_END
+}
+
+ Bit16u
+get_CS()
+{
+ASM_START
+ mov ax, cs
+ASM_END
+}
+
+ Bit16u
+get_SS()
+{
+ASM_START
+ mov ax, ss
+ASM_END
+}
+
+#if BX_DEBUG_SERIAL
+/* serial debug port*/
+#define BX_DEBUG_PORT 0x03f8
+
+/* data */
+#define UART_RBR 0x00
+#define UART_THR 0x00
+
+/* control */
+#define UART_IER 0x01
+#define UART_IIR 0x02
+#define UART_FCR 0x02
+#define UART_LCR 0x03
+#define UART_MCR 0x04
+#define UART_DLL 0x00
+#define UART_DLM 0x01
+
+/* status */
+#define UART_LSR 0x05
+#define UART_MSR 0x06
+#define UART_SCR 0x07
+
+int uart_can_tx_byte(base_port)
+ Bit16u base_port;
+{
+ return inb(base_port + UART_LSR) & 0x20;
+}
+
+void uart_wait_to_tx_byte(base_port)
+ Bit16u base_port;
+{
+ while (!uart_can_tx_byte(base_port));
+}
+
+void uart_wait_until_sent(base_port)
+ Bit16u base_port;
+{
+ while (!(inb(base_port + UART_LSR) & 0x40));
+}
+
+void uart_tx_byte(base_port, data)
+ Bit16u base_port;
+ Bit8u data;
+{
+ uart_wait_to_tx_byte(base_port);
+ outb(base_port + UART_THR, data);
+ uart_wait_until_sent(base_port);
+}
+#endif
+
+ void
+wrch(c)
+ Bit8u c;
+{
+ ASM_START
+ push bp
+ mov bp, sp
+
+ push bx
+ mov ah, #0x0e
+ mov al, 4[bp]
+ xor bx,bx
+ int #0x10
+ pop bx
+
+ pop bp
+ ASM_END
+}
+
+ void
+send(action, c)
+ Bit16u action;
+ Bit8u c;
+{
+#if BX_DEBUG_SERIAL
+ if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
+ uart_tx_byte(BX_DEBUG_PORT, c);
+#endif
+#if BX_VIRTUAL_PORTS
+ if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
+ if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
+#endif
+ if (action & BIOS_PRINTF_SCREEN) {
+ if (c == '\n') wrch('\r');
+ wrch(c);
+ }
+}
+
+ void
+put_int(action, val, width, neg)
+ Bit16u action;
+ short val, width;
+ bx_bool neg;
+{
+ short nval = val / 10;
+ if (nval)
+ put_int(action, nval, width - 1, neg);
+ else {
+ while (--width > 0) send(action, ' ');
+ if (neg) send(action, '-');
+ }
+ send(action, val - (nval * 10) + '0');
+}
+
+ void
+put_uint(action, val, width, neg)
+ Bit16u action;
+ unsigned short val;
+ short width;
+ bx_bool neg;
+{
+ unsigned short nval = val / 10;
+ if (nval)
+ put_uint(action, nval, width - 1, neg);
+ else {
+ while (--width > 0) send(action, ' ');
+ if (neg) send(action, '-');
+ }
+ send(action, val - (nval * 10) + '0');
+}
+
+ void
+put_luint(action, val, width, neg)
+ Bit16u action;
+ unsigned long val;
+ short width;
+ bx_bool neg;
+{
+ unsigned long nval = val / 10;
+ if (nval)
+ put_luint(action, nval, width - 1, neg);
+ else {
+ while (--width > 0) send(action, ' ');
+ if (neg) send(action, '-');
+ }
+ send(action, val - (nval * 10) + '0');
+}
+
+void put_str(action, segment, offset)
+ Bit16u action;
+ Bit16u segment;
+ Bit16u offset;
+{
+ Bit8u c;
+
+ while (c = read_byte(segment, offset)) {
+ send(action, c);
+ offset++;
+ }
+}
+
+ void
+delay_ticks(ticks)
+ Bit16u ticks;
+{
+ long ticks_to_wait, delta;
+ Bit32u prev_ticks, t;
+
+ /*
+ * The 0:046c wraps around at 'midnight' according to a 18.2Hz clock.
+ * We also have to be careful about interrupt storms.
+ */
+ASM_START
+ pushf
+ sti
+ASM_END
+ ticks_to_wait = ticks;
+ prev_ticks = read_dword(0x0, 0x46c);
+ do
+ {
+ASM_START
+ hlt
+ASM_END
+ t = read_dword(0x0, 0x46c);
+ if (t > prev_ticks)
+ {
+ delta = t - prev_ticks; /* The temp var is required or bcc screws up. */
+ ticks_to_wait -= delta;
+ }
+ else if (t < prev_ticks)
+ {
+ ticks_to_wait -= t; /* wrapped */
+ }
+
+ prev_ticks = t;
+ } while (ticks_to_wait > 0);
+ASM_START
+ cli
+ popf
+ASM_END
+}
+
+ Bit8u
+check_for_keystroke()
+{
+ASM_START
+ mov ax, #0x100
+ int #0x16
+ jz no_key
+ mov al, #1
+ jmp done
+no_key:
+ xor al, al
+done:
+ASM_END
+}
+
+ Bit8u
+get_keystroke()
+{
+ASM_START
+ mov ax, #0x0
+ int #0x16
+ xchg ah, al
+ASM_END
+}
+
+ void
+delay_ticks_and_check_for_keystroke(ticks, count)
+ Bit16u ticks, count;
+{
+ Bit16u i;
+ for (i = 1; i <= count; i++) {
+ delay_ticks(ticks);
+ if (check_for_keystroke())
+ break;
+ }
+}
+
+//--------------------------------------------------------------------------
+// bios_printf()
+// A compact variable argument printf function.
+//
+// Supports %[format_width][length]format
+// where format can be x,X,u,d,s,S,c
+// and the optional length modifier is l (ell)
+//--------------------------------------------------------------------------
+ void
+bios_printf(action, s)
+ Bit16u action;
+ Bit8u *s;
+{
+ Bit8u c, format_char;
+ bx_bool in_format;
+ short i;
+ Bit16u *arg_ptr;
+ Bit16u arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
+
+ arg_ptr = &s;
+ arg_seg = get_SS();
+
+ in_format = 0;
+ format_width = 0;
+
+ if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
+#if BX_VIRTUAL_PORTS
+ outb(PANIC_PORT2, 0x00);
+#endif
+ bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
+ }
+
+ while (c = read_byte(get_CS(), s)) {
+ if ( c == '%' ) {
+ in_format = 1;
+ format_width = 0;
+ }
+ else if (in_format) {
+ if ( (c>='0') && (c<='9') ) {
+ format_width = (format_width * 10) + (c - '0');
+ }
+ else {
+ arg_ptr++; // increment to next arg
+ arg = read_word(arg_seg, arg_ptr);
+ if (c == 'x' || c == 'X') {
+ if (format_width == 0)
+ format_width = 4;
+ if (c == 'x')
+ hexadd = 'a';
+ else
+ hexadd = 'A';
+ for (i=format_width-1; i>=0; i--) {
+ nibble = (arg >> (4 * i)) & 0x000f;
+ send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
+ }
+ }
+ else if (c == 'u') {
+ put_uint(action, arg, format_width, 0);
+ }
+ else if (c == 'l') {
+ s++;
+ c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
+ arg_ptr++; /* increment to next arg */
+ hibyte = read_word(arg_seg, arg_ptr);
+ if (c == 'd') {
+ if (hibyte & 0x8000)
+ put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
+ else
+ put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
+ }
+ else if (c == 'u') {
+ put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
+ }
+ else if (c == 'x' || c == 'X')
+ {
+ if (format_width == 0)
+ format_width = 8;
+ if (c == 'x')
+ hexadd = 'a';
+ else
+ hexadd = 'A';
+ for (i=format_width-1; i>=0; i--) {
+ nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
+ send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
+ }
+ }
+ }
+ else if (c == 'd') {
+ if (arg & 0x8000)
+ put_int(action, -arg, format_width - 1, 1);
+ else
+ put_int(action, arg, format_width, 0);
+ }
+ else if (c == 's') {
+ put_str(action, get_CS(), arg);
+ }
+ else if (c == 'S') {
+ hibyte = arg;
+ arg_ptr++;
+ arg = read_word(arg_seg, arg_ptr);
+ put_str(action, hibyte, arg);
+ }
+ else if (c == 'c') {
+ send(action, arg);
+ }
+ else
+ BX_PANIC("bios_printf: unknown format\n");
+ in_format = 0;
+ }
+ }
+ else {
+ send(action, c);
+ }
+ s ++;
+ }
+
+ if (action & BIOS_PRINTF_HALT) {
+ // freeze in a busy loop.
+ASM_START
+ cli
+ halt2_loop:
+ hlt
+ jmp halt2_loop
+ASM_END
+ }
+}
+
+//--------------------------------------------------------------------------
+// keyboard_init
+//--------------------------------------------------------------------------
+// this file is based on LinuxBIOS implementation of keyboard.c
+// could convert to #asm to gain space
+ void
+keyboard_init()
+{
+ Bit16u max;
+
+ /* ------------------- Flush buffers ------------------------*/
+ /* Wait until buffer is empty */
+ max=0xffff;
+ while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
+
+ /* flush incoming keys */
+ max=0x2000;
+ while (--max > 0) {
+ outb(0x80, 0x00);
+ if (inb(0x64) & 0x01) {
+ inb(0x60);
+ max = 0x2000;
+ }
+ }
+
+ // Due to timer issues, and if the IPS setting is > 15000000,
+ // the incoming keys might not be flushed here. That will
+ // cause a panic a few lines below. See sourceforge bug report :
+ // [ 642031 ] FATAL: Keyboard RESET error:993
+
+ /* ------------------- controller side ----------------------*/
+ /* send cmd = 0xAA, self test 8042 */
+ outb(0x64, 0xaa);
+
+ /* Wait until buffer is empty */
+ max=0xffff;
+ while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
+ if (max==0x0) keyboard_panic(00);
+
+ /* Wait for data */
+ max=0xffff;
+ while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
+ if (max==0x0) keyboard_panic(01);
+
+ /* read self-test result, 0x55 should be returned from 0x60 */
+ if ((inb(0x60) != 0x55)){
+ keyboard_panic(991);
+ }
+
+ /* send cmd = 0xAB, keyboard interface test */
+ outb(0x64,0xab);
+
+ /* Wait until buffer is empty */
+ max=0xffff;
+ while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
+ if (max==0x0) keyboard_panic(10);
+
+ /* Wait for data */
+ max=0xffff;
+ while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
+ if (max==0x0) keyboard_panic(11);
+
+ /* read keyboard interface test result, */
+ /* 0x00 should be returned form 0x60 */
+ if ((inb(0x60) != 0x00)) {
+ keyboard_panic(992);
+ }
+
+ /* Enable Keyboard clock */
+ outb(0x64,0xae);
+ outb(0x64,0xa8);
+
+ /* ------------------- keyboard side ------------------------*/
+ /* reset kerboard and self test (keyboard side) */
+ outb(0x60, 0xff);
+
+ /* Wait until buffer is empty */
+ max=0xffff;
+ while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
+ if (max==0x0) keyboard_panic(20);
+
+ /* Wait for data */
+ max=0xffff;
+ while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
+ if (max==0x0) keyboard_panic(21);
+
+ /* keyboard should return ACK */
+ if ((inb(0x60) != 0xfa)) {
+ keyboard_panic(993);
+ }
+
+ /* Wait for data */
+ max=0xffff;
+ while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
+ if (max==0x0) keyboard_panic(31);
+
+ if ((inb(0x60) != 0xaa)) {
+ keyboard_panic(994);
+ }
+
+ /* Disable keyboard */
+ outb(0x60, 0xf5);
+
+ /* Wait until buffer is empty */
+ max=0xffff;
+ while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
+ if (max==0x0) keyboard_panic(40);
+
+ /* Wait for data */
+ max=0xffff;
+ while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
+ if (max==0x0) keyboard_panic(41);
+
+ /* keyboard should return ACK */
+ if ((inb(0x60) != 0xfa)) {
+ keyboard_panic(995);
+ }
+
+ /* Write Keyboard Mode */
+ outb(0x64, 0x60);
+
+ /* Wait until buffer is empty */
+ max=0xffff;
+ while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
+ if (max==0x0) keyboard_panic(50);
+
+ /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
+ outb(0x60, 0x61);
+
+ /* Wait until buffer is empty */
+ max=0xffff;
+ while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
+ if (max==0x0) keyboard_panic(60);
+
+ /* Enable keyboard */
+ outb(0x60, 0xf4);
+
+ /* Wait until buffer is empty */
+ max=0xffff;
+ while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
+ if (max==0x0) keyboard_panic(70);
+
+ /* Wait for data */
+ max=0xffff;
+ while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
+ if (max==0x0) keyboard_panic(70);
+
+ /* keyboard should return ACK */
+ if ((inb(0x60) != 0xfa)) {
+ keyboard_panic(996);
+ }
+
+ outb(0x80, 0x77);
+}
+
+//--------------------------------------------------------------------------
+// keyboard_panic
+//--------------------------------------------------------------------------
+ void
+keyboard_panic(status)
+ Bit16u status;
+{
+ // If you're getting a 993 keyboard panic here,
+ // please see the comment in keyboard_init
+
+ BX_PANIC("Keyboard error:%u\n",status);
+}
+
+//--------------------------------------------------------------------------
+// shutdown_status_panic
+// called when the shutdown statsu is not implemented, displays the status
+//--------------------------------------------------------------------------
+ void
+shutdown_status_panic(status)
+ Bit16u status;
+{
+ BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
+}
+
+void s3_resume_panic()
+{
+ BX_PANIC("Returned from s3_resume.\n");
+}
+
+//--------------------------------------------------------------------------
+// print_bios_banner
+// displays a the bios version
+//--------------------------------------------------------------------------
+void
+print_bios_banner()
+{
+ printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
+ BIOS_BUILD_DATE, bios_cvs_version_string);
+ printf(
+#if BX_APM
+ "apmbios "
+#endif
+#if BX_PCIBIOS
+ "pcibios "
+#endif
+#if BX_ELTORITO_BOOT
+ "eltorito "
+#endif
+#if BX_ROMBIOS32
+ "rombios32 "
+#endif
+ "\n\n");
+}
+
+//--------------------------------------------------------------------------
+// BIOS Boot Specification 1.0.1 compatibility
+//
+// Very basic support for the BIOS Boot Specification, which allows expansion
+// ROMs to register themselves as boot devices, instead of just stealing the
+// INT 19h boot vector.
+//
+// This is a hack: to do it properly requires a proper PnP BIOS and we aren't
+// one; we just lie to the option ROMs to make them behave correctly.
+// We also don't support letting option ROMs register as bootable disk
+// drives (BCVs), only as bootable devices (BEVs).
+//
+// http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
+//--------------------------------------------------------------------------
+
+static char drivetypes[][10]={"", "Floppy","Hard Disk","CD-Rom", "Network"};
+
+static void
+init_boot_vectors()
+{
+ ipl_entry_t e;
+ Bit16u count = 0;
+ Bit16u ss = get_SS();
+
+ /* Clear out the IPL table. */
+ memsetb(IPL_SEG, IPL_TABLE_OFFSET, 0, IPL_SIZE);
+
+ /* User selected device not set */
+ write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
+
+ /* Floppy drive */
+ e.type = IPL_TYPE_FLOPPY; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
+ memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
+ count++;
+
+ /* First HDD */
+ e.type = IPL_TYPE_HARDDISK; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
+ memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
+ count++;
+
+#if BX_ELTORITO_BOOT
+ /* CDROM */
+ e.type = IPL_TYPE_CDROM; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
+ memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
+ count++;
+#endif
+
+ /* Remember how many devices we have */
+ write_word(IPL_SEG, IPL_COUNT_OFFSET, count);
+ /* Not tried booting anything yet */
+ write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xffff);
+}
+
+static Bit8u
+get_boot_vector(i, e)
+Bit16u i; ipl_entry_t *e;
+{
+ Bit16u count;
+ Bit16u ss = get_SS();
+ /* Get the count of boot devices, and refuse to overrun the array */
+ count = read_word(IPL_SEG, IPL_COUNT_OFFSET);
+ if (i >= count) return 0;
+ /* OK to read this device */
+ memcpyb(ss, e, IPL_SEG, IPL_TABLE_OFFSET + i * sizeof (*e), sizeof (*e));
+ return 1;
+}
+
+#if BX_ELTORITO_BOOT
+ void
+interactive_bootkey()
+{
+ ipl_entry_t e;
+ Bit16u count;
+ char description[33];
+ Bit8u scan_code;
+ Bit8u i;
+ Bit16u ss = get_SS();
+ Bit16u valid_choice = 0;
+
+ while (check_for_keystroke())
+ get_keystroke();
+
+ printf("Press F12 for boot menu.\n\n");
+
+ delay_ticks_and_check_for_keystroke(11, 5); /* ~3 seconds */
+ if (check_for_keystroke())
+ {
+ scan_code = get_keystroke();
+ if (scan_code == 0x86) /* F12 */
+ {
+ while (check_for_keystroke())
+ get_keystroke();
+
+ printf("Select boot device:\n\n");
+
+ count = read_word(IPL_SEG, IPL_COUNT_OFFSET);
+ for (i = 0; i < count; i++)
+ {
+ memcpyb(ss, &e, IPL_SEG, IPL_TABLE_OFFSET + i * sizeof (e), sizeof (e));
+ printf("%d. ", i+1);
+ switch(e.type)
+ {
+ case IPL_TYPE_FLOPPY:
+ case IPL_TYPE_HARDDISK:
+ case IPL_TYPE_CDROM:
+ printf("%s\n", drivetypes[e.type]);
+ break;
+ case IPL_TYPE_BEV:
+ printf("%s", drivetypes[4]);
+ if (e.description != 0)
+ {
+ memcpyb(ss, &description, (Bit16u)(e.description >> 16), (Bit16u)(e.description & 0xffff), 32);
+ description[32] = 0;
+ printf(" [%S]", ss, description);
+ }
+ printf("\n");
+ break;
+ }
+ }
+
+ count++;
+ while (!valid_choice) {
+ scan_code = get_keystroke();
+ if (scan_code == 0x01 || scan_code == 0x58) /* ESC or F12 */
+ {
+ valid_choice = 1;
+ }
+ else if (scan_code <= count)
+ {
+ valid_choice = 1;
+ scan_code -= 1;
+ /* Set user selected device */
+ write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, scan_code);
+ }
+ }
+ printf("\n");
+ }
+ }
+}
+#endif // BX_ELTORITO_BOOT
+
+//--------------------------------------------------------------------------
+// print_boot_device
+// displays the boot device
+//--------------------------------------------------------------------------
+
+void
+print_boot_device(e)
+ ipl_entry_t *e;
+{
+ Bit16u type;
+ char description[33];
+ Bit16u ss = get_SS();
+ type = e->type;
+ /* NIC appears as type 0x80 */
+ if (type == IPL_TYPE_BEV) type = 0x4;
+ if (type == 0 || type > 0x4) BX_PANIC("Bad drive type\n");
+ printf("Booting from %s", drivetypes[type]);
+ /* print product string if BEV */
+ if (type == 4 && e->description != 0) {
+ /* first 32 bytes are significant */
+ memcpyb(ss, &description, (Bit16u)(e->description >> 16), (Bit16u)(e->description & 0xffff), 32);
+ /* terminate string */
+ description[32] = 0;
+ printf(" [%S]", ss, description);
+ }
+ printf("...\n");
+}
+
+//--------------------------------------------------------------------------
+// print_boot_failure
+// displays the reason why boot failed
+//--------------------------------------------------------------------------
+ void
+print_boot_failure(type, reason)
+ Bit16u type; Bit8u reason;
+{
+ if (type == 0 || type > 0x3) BX_PANIC("Bad drive type\n");
+
+ printf("Boot failed");
+ if (type < 4) {
+ /* Report the reason too */
+ if (reason==0)
+ printf(": not a bootable disk");
+ else
+ printf(": could not read the boot disk");
+ }
+ printf("\n\n");
+}
+
+//--------------------------------------------------------------------------
+// print_cdromboot_failure
+// displays the reason why boot failed
+//--------------------------------------------------------------------------
+ void
+print_cdromboot_failure( code )
+ Bit16u code;
+{
+ bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
+
+ return;
+}
+
+void
+nmi_handler_msg()
+{
+ BX_PANIC("NMI Handler called\n");
+}
+
+void
+int18_panic_msg()
+{
+ BX_PANIC("INT18: BOOT FAILURE\n");
+}
+
+void
+log_bios_start()
+{
+#if BX_DEBUG_SERIAL
+ outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
+#endif
+ BX_INFO("%s\n", bios_cvs_version_string);
+}
+
+ bx_bool
+set_enable_a20(val)
+ bx_bool val;
+{
+ Bit8u oldval;
+
+ // Use PS2 System Control port A to set A20 enable
+
+ // get current setting first
+ oldval = inb(0x92);
+
+ // change A20 status
+ if (val)
+ outb(0x92, oldval | 0x02);
+ else
+ outb(0x92, oldval & 0xfd);
+
+ return((oldval & 0x02) != 0);
+}
+
+ void
+debugger_on()
+{
+ outb(0xfedc, 0x01);
+}
+
+ void
+debugger_off()
+{
+ outb(0xfedc, 0x00);
+}
+
+int
+s3_resume()
+{
+ Bit32u s3_wakeup_vector;
+ Bit8u s3_resume_flag;
+
+ s3_resume_flag = read_byte(0x40, 0xb0);
+ s3_wakeup_vector = read_dword(0x40, 0xb2);
+
+ BX_INFO("S3 resume called %x 0x%lx\n", s3_resume_flag, s3_wakeup_vector);
+ if (s3_resume_flag != 0xFE || !s3_wakeup_vector)
+ return 0;
+
+ write_byte(0x40, 0xb0, 0);
+
+ /* setup wakeup vector */
+ write_word(0x40, 0xb6, (s3_wakeup_vector & 0xF)); /* IP */
+ write_word(0x40, 0xb8, (s3_wakeup_vector >> 4)); /* CS */
+
+ BX_INFO("S3 resume jump to %x:%x\n", (s3_wakeup_vector >> 4),
+ (s3_wakeup_vector & 0xF));
+ASM_START
+ jmpf [0x04b6]
+ASM_END
+ return 1;
+}
+
+#if BX_USE_ATADRV
+
+// ---------------------------------------------------------------------------
+// Start of ATA/ATAPI Driver
+// ---------------------------------------------------------------------------
+
+// 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 6 // alternate status in pio_base_addr2+6
+#define ATA_CB_DC 6 // device control out pio_base_addr2+6
+#define ATA_CB_DA 7 // device address in pio_base_addr2+7
+
+#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_CFA_ERASE_SECTORS 0xC0
+#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
+#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
+#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
+#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
+#define ATA_CMD_CHECK_POWER_MODE1 0xE5
+#define ATA_CMD_CHECK_POWER_MODE2 0x98
+#define ATA_CMD_DEVICE_RESET 0x08
+#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
+#define ATA_CMD_FLUSH_CACHE 0xE7
+#define ATA_CMD_FORMAT_TRACK 0x50
+#define ATA_CMD_IDENTIFY_DEVICE 0xEC
+#define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
+#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
+#define ATA_CMD_IDLE1 0xE3
+#define ATA_CMD_IDLE2 0x97
+#define ATA_CMD_IDLE_IMMEDIATE1 0xE1
+#define ATA_CMD_IDLE_IMMEDIATE2 0x95
+#define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
+#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
+#define ATA_CMD_NOP 0x00
+#define ATA_CMD_PACKET 0xA0
+#define ATA_CMD_READ_BUFFER 0xE4
+#define ATA_CMD_READ_DMA 0xC8
+#define ATA_CMD_READ_DMA_QUEUED 0xC7
+#define ATA_CMD_READ_MULTIPLE 0xC4
+#define ATA_CMD_READ_SECTORS 0x20
+#define ATA_CMD_READ_VERIFY_SECTORS 0x40
+#define ATA_CMD_RECALIBRATE 0x10
+#define ATA_CMD_REQUEST_SENSE 0x03
+#define ATA_CMD_SEEK 0x70
+#define ATA_CMD_SET_FEATURES 0xEF
+#define ATA_CMD_SET_MULTIPLE_MODE 0xC6
+#define ATA_CMD_SLEEP1 0xE6
+#define ATA_CMD_SLEEP2 0x99
+#define ATA_CMD_STANDBY1 0xE2
+#define ATA_CMD_STANDBY2 0x96
+#define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
+#define ATA_CMD_STANDBY_IMMEDIATE2 0x94
+#define ATA_CMD_WRITE_BUFFER 0xE8
+#define ATA_CMD_WRITE_DMA 0xCA
+#define ATA_CMD_WRITE_DMA_QUEUED 0xCC
+#define ATA_CMD_WRITE_MULTIPLE 0xC5
+#define ATA_CMD_WRITE_SECTORS 0x30
+#define ATA_CMD_WRITE_VERIFY 0x3C
+
+#define ATA_IFACE_NONE 0x00
+#define ATA_IFACE_ISA 0x00
+#define ATA_IFACE_PCI 0x01
+
+#define ATA_TYPE_NONE 0x00
+#define ATA_TYPE_UNKNOWN 0x01
+#define ATA_TYPE_ATA 0x02
+#define ATA_TYPE_ATAPI 0x03
+
+#define ATA_DEVICE_NONE 0x00
+#define ATA_DEVICE_HD 0xFF
+#define ATA_DEVICE_CDROM 0x05
+
+#define ATA_MODE_NONE 0x00
+#define ATA_MODE_PIO16 0x00
+#define ATA_MODE_PIO32 0x01
+#define ATA_MODE_ISADMA 0x02
+#define ATA_MODE_PCIDMA 0x03
+#define ATA_MODE_USEIRQ 0x10
+
+#define ATA_TRANSLATION_NONE 0
+#define ATA_TRANSLATION_LBA 1
+#define ATA_TRANSLATION_LARGE 2
+#define ATA_TRANSLATION_RECHS 3
+
+#define ATA_DATA_NO 0x00
+#define ATA_DATA_IN 0x01
+#define ATA_DATA_OUT 0x02
+
+// ---------------------------------------------------------------------------
+// ATA/ATAPI driver : initialization
+// ---------------------------------------------------------------------------
+void ata_init( )
+{
+ Bit16u ebda_seg=read_word(0x0040,0x000E);
+ Bit8u channel, device;
+
+ // Channels info init.
+ for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
+ write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
+ write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
+ write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
+ write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
+ }
+
+ // Devices info init.
+ for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
+ write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
+ write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
+ write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
+ write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
+ write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
+ write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
+ write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
+ write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
+ write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
+ write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
+ write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
+ write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
+ write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
+
+ write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low,0L);
+ write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_high,0L);
+ }
+
+ // hdidmap and cdidmap init.
+ for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
+ write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
+ write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
+ }
+
+ write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
+ write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
+}
+
+#define TIMEOUT 0
+#define BSY 1
+#define NOT_BSY 2
+#define NOT_BSY_DRQ 3
+#define NOT_BSY_NOT_DRQ 4
+#define NOT_BSY_RDY 5
+
+#define IDE_TIMEOUT 32000u //32 seconds max for IDE ops
+
+int await_ide();
+static int await_ide(when_done,base,timeout)
+ Bit8u when_done;
+ Bit16u base;
+ Bit16u timeout;
+{
+ Bit32u time=0,last=0;
+ Bit16u status;
+ Bit8u result;
+ status = inb(base + ATA_CB_STAT); // for the times you're supposed to throw one away
+ for(;;) {
+ status = inb(base+ATA_CB_STAT);
+ time++;
+ if (when_done == BSY)
+ result = status & ATA_CB_STAT_BSY;
+ else if (when_done == NOT_BSY)
+ result = !(status & ATA_CB_STAT_BSY);
+ else if (when_done == NOT_BSY_DRQ)
+ result = !(status & ATA_CB_STAT_BSY) && (status & ATA_CB_STAT_DRQ);
+ else if (when_done == NOT_BSY_NOT_DRQ)
+ result = !(status & ATA_CB_STAT_BSY) && !(status & ATA_CB_STAT_DRQ);
+ else if (when_done == NOT_BSY_RDY)
+ result = !(status & ATA_CB_STAT_BSY) && (status & ATA_CB_STAT_RDY);
+ else if (when_done == TIMEOUT)
+ result = 0;
+
+ if (result) return 0;
+ if (time>>16 != last) // mod 2048 each 16 ms
+ {
+ last = time >>16;
+ BX_DEBUG_ATA("await_ide: (TIMEOUT,BSY,!BSY,!BSY_DRQ,!BSY_!DRQ,!BSY_RDY) %d time= %ld timeout= %d\n",when_done,time>>11, timeout);
+ }
+ if (status & ATA_CB_STAT_ERR)
+ {
+ BX_DEBUG_ATA("await_ide: ERROR (TIMEOUT,BSY,!BSY,!BSY_DRQ,!BSY_!DRQ,!BSY_RDY) %d time= %ld timeout= %d\n",when_done,time>>11, timeout);
+ return -1;
+ }
+ if ((timeout == 0) || ((time>>11) > timeout)) break;
+ }
+ BX_INFO("IDE time out\n");
+ return -1;
+}
+
+// ---------------------------------------------------------------------------
+// ATA/ATAPI driver : device detection
+// ---------------------------------------------------------------------------
+
+void ata_detect( )
+{
+ Bit16u ebda_seg=read_word(0x0040,0x000E);
+ Bit8u hdcount, cdcount, device, type;
+ Bit8u buffer[0x0200];
+
+#if BX_MAX_ATA_INTERFACES > 0
+ write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
+ write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
+ write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
+ write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
+#endif
+#if BX_MAX_ATA_INTERFACES > 1
+ write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
+ write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
+ write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
+ write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
+#endif
+#if BX_MAX_ATA_INTERFACES > 2
+ write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
+ write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
+ write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
+ write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
+#endif
+#if BX_MAX_ATA_INTERFACES > 3
+ write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
+ write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
+ write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
+ write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
+#endif
+#if BX_MAX_ATA_INTERFACES > 4
+#error Please fill the ATA interface informations
+#endif
+
+ // Device detection
+ hdcount=cdcount=0;
+
+ for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
+ Bit16u iobase1, iobase2;
+ Bit8u channel, slave, shift;
+ Bit8u sc, sn, cl, ch, st;
+
+ channel = device / 2;
+ slave = device % 2;
+
+ iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
+ iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
+
+ // Disable interrupts
+ outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
+
+ // Look for device
+ outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
+ outb(iobase1+ATA_CB_SC, 0x55);
+ outb(iobase1+ATA_CB_SN, 0xaa);
+ outb(iobase1+ATA_CB_SC, 0xaa);
+ outb(iobase1+ATA_CB_SN, 0x55);
+ outb(iobase1+ATA_CB_SC, 0x55);
+ outb(iobase1+ATA_CB_SN, 0xaa);
+
+ // If we found something
+ sc = inb(iobase1+ATA_CB_SC);
+ sn = inb(iobase1+ATA_CB_SN);
+
+ if ( (sc == 0x55) && (sn == 0xaa) ) {
+ write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
+
+ // reset the channel
+ ata_reset(device);
+
+ // check for ATA or ATAPI
+ outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
+ sc = inb(iobase1+ATA_CB_SC);
+ sn = inb(iobase1+ATA_CB_SN);
+ if ((sc==0x01) && (sn==0x01)) {
+ cl = inb(iobase1+ATA_CB_CL);
+ ch = inb(iobase1+ATA_CB_CH);
+ st = inb(iobase1+ATA_CB_STAT);
+
+ if ((cl==0x14) && (ch==0xeb)) {
+ write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
+ } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
+ write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
+ } else if ((cl==0xff) && (ch==0xff)) {
+ write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
+ }
+ }
+ }
+
+ type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
+
+ // Now we send a IDENTIFY command to ATA device
+ if(type == ATA_TYPE_ATA) {
+ Bit32u sectors_low, sectors_high;
+ Bit16u cylinders, heads, spt, blksize;
+ Bit8u translation, removable, mode;
+
+ //Temporary values to do the transfer
+ write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
+ write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
+
+ if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, 0L, get_SS(),buffer) !=0 )
+ BX_PANIC("ata-detect: Failed to detect ATA device\n");
+
+ removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
+ mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
+ blksize = read_word(get_SS(),buffer+10);
+
+ cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
+ heads = read_word(get_SS(),buffer+(3*2)); // word 3
+ spt = read_word(get_SS(),buffer+(6*2)); // word 6
+
+ if (read_word(get_SS(),buffer+(83*2)) & (1 << 10)) { // word 83 - lba48 support
+ sectors_low = read_dword(get_SS(),buffer+(100*2)); // word 100 and word 101
+ sectors_high = read_dword(get_SS(),buffer+(102*2)); // word 102 and word 103
+ } else {
+ sectors_low = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
+ sectors_high = 0;
+ }
+
+ write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
+ write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
+ write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
+ write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
+ write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
+ write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
+ write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
+ write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low, sectors_low);
+ write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_high, sectors_high);
+ BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
+
+ translation = inb_cmos(0x39 + channel/2);
+ for (shift=device%4; shift>0; shift--) translation >>= 2;
+ translation &= 0x03;
+
+ write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
+
+ switch (translation) {
+ case ATA_TRANSLATION_NONE:
+ BX_INFO("none");
+ break;
+ case ATA_TRANSLATION_LBA:
+ BX_INFO("lba");
+ break;
+ case ATA_TRANSLATION_LARGE:
+ BX_INFO("large");
+ break;
+ case ATA_TRANSLATION_RECHS:
+ BX_INFO("r-echs");
+ break;
+ }
+ switch (translation) {
+ case ATA_TRANSLATION_NONE:
+ break;
+ case ATA_TRANSLATION_LBA:
+ spt = 63;
+ sectors_low /= 63;
+ heads = sectors_low / 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 = sectors_low / heads;
+ break;
+ case ATA_TRANSLATION_RECHS:
+ // Take care not to overflow
+ if (heads==16) {
+ if(cylinders>61439) cylinders=61439;
+ heads=15;
+ cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
+ }
+ // then go through the large bitshift process
+ case ATA_TRANSLATION_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;
+ BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
+
+ write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
+ write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
+ write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
+
+ // fill hdidmap
+ write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
+ hdcount++;
+ }
+
+ // Now we send a IDENTIFY command to ATAPI device
+ if(type == ATA_TYPE_ATAPI) {
+
+ Bit8u type, removable, mode;
+ Bit16u blksize;
+
+ //Temporary values to do the transfer
+ write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
+ write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
+
+ if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, 0L, get_SS(),buffer) != 0)
+ BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
+
+ type = read_byte(get_SS(),buffer+1) & 0x1f;
+ removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
+ mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
+ blksize = 2048;
+
+ write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
+ write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
+ write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
+ write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
+
+ // fill cdidmap
+ write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
+ cdcount++;
+ }
+
+ {
+ Bit32u sizeinmb;
+ Bit16u ataversion;
+ Bit8u c, i, version, model[41];
+
+ switch (type) {
+ case ATA_TYPE_ATA:
+ sizeinmb = (read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_high) << 21)
+ | (read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low) >> 11);
+ case ATA_TYPE_ATAPI:
+ // Read ATA/ATAPI version
+ ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
+ for(version=15;version>0;version--) {
+ if((ataversion&(1<<version))!=0)
+ break;
+ }
+
+ // Read model name
+ for(i=0;i<20;i++){
+ write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
+ write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
+ }
+
+ // Reformat
+ write_byte(get_SS(),model+40,0x00);
+ for(i=39;i>0;i--){
+ if(read_byte(get_SS(),model+i)==0x20)
+ write_byte(get_SS(),model+i,0x00);
+ else break;
+ }
+ if (i>36) {
+ write_byte(get_SS(),model+36,0x00);
+ for(i=35;i>32;i--){
+ write_byte(get_SS(),model+i,0x2E);
+ }
+ }
+ break;
+ }
+
+ switch (type) {
+ case ATA_TYPE_ATA:
+ printf("ata%d %s: ",channel,slave?" slave":"master");
+ i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
+ if (sizeinmb < (1UL<<16))
+ printf(" ATA-%d Hard-Disk (%4u MBytes)\n", version, (Bit16u)sizeinmb);
+ else
+ printf(" ATA-%d Hard-Disk (%4u GBytes)\n", version, (Bit16u)(sizeinmb>>10));
+ break;
+ case ATA_TYPE_ATAPI:
+ printf("ata%d %s: ",channel,slave?" slave":"master");
+ i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
+ if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
+ printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
+ else
+ printf(" ATAPI-%d Device\n",version);
+ break;
+ case ATA_TYPE_UNKNOWN:
+ printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
+ break;
+ }
+ }
+ }
+
+ // Store the devices counts
+ write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
+ write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
+ write_byte(0x40,0x75, hdcount);
+
+ printf("\n");
+
+ // FIXME : should use bios=cmos|auto|disable bits
+ // FIXME : should know about translation bits
+ // FIXME : move hard_drive_post here
+
+}
+
+// ---------------------------------------------------------------------------
+// ATA/ATAPI driver : software reset
+// ---------------------------------------------------------------------------
+// ATA-3
+// 8.2.1 Software reset - Device 0
+
+void ata_reset(device)
+Bit16u device;
+{
+ Bit16u ebda_seg=read_word(0x0040,0x000E);
+ Bit16u iobase1, iobase2;
+ Bit8u channel, slave, sn, sc;
+ Bit8u type;
+ Bit16u max;
+
+ channel = device / 2;
+ slave = device % 2;
+
+ iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
+ iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
+
+ // Reset
+
+// 8.2.1 (a) -- set SRST in DC
+ outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
+
+// 8.2.1 (b) -- wait for BSY
+ await_ide(BSY, iobase1, 20);
+
+// 8.2.1 (f) -- clear SRST
+ outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
+
+ type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
+ if (type != ATA_TYPE_NONE) {
+
+// 8.2.1 (g) -- check for sc==sn==0x01
+ // select device
+ outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
+ sc = inb(iobase1+ATA_CB_SC);
+ sn = inb(iobase1+ATA_CB_SN);
+
+ if ( (sc==0x01) && (sn==0x01) ) {
+ if (type == ATA_TYPE_ATA) //ATA
+ await_ide(NOT_BSY_RDY, iobase1, IDE_TIMEOUT);
+ else //ATAPI
+ await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
+ }
+
+// 8.2.1 (h) -- wait for not BSY
+ await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
+ }
+
+ // Enable interrupts
+ outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+}
+
+// ---------------------------------------------------------------------------
+// ATA/ATAPI driver : execute a non data command
+// ---------------------------------------------------------------------------
+
+Bit16u ata_cmd_non_data()
+{return 0;}
+
+// ---------------------------------------------------------------------------
+// ATA/ATAPI driver : execute a data-in command
+// ---------------------------------------------------------------------------
+ // returns
+ // 0 : no error
+ // 1 : BUSY bit set
+ // 2 : read error
+ // 3 : expected DRQ=1
+ // 4 : no sectors left to read/verify
+ // 5 : more sectors to read/verify
+ // 6 : no sectors left to write
+ // 7 : more sectors to write
+Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba_low, lba_high, segment, offset)
+Bit16u device, command, count, cylinder, head, sector, segment, offset;
+Bit32u lba_low, lba_high;
+{
+ Bit16u ebda_seg=read_word(0x0040,0x000E);
+ Bit16u iobase1, iobase2, blksize;
+ Bit8u channel, slave;
+ Bit8u status, current, mode;
+
+ channel = device / 2;
+ slave = device % 2;
+
+ iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
+ iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
+ mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
+ blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
+ if (mode == ATA_MODE_PIO32) blksize>>=2;
+ else blksize>>=1;
+
+ // Reset count of transferred data
+ write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
+ write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
+ current = 0;
+
+ status = inb(iobase1 + ATA_CB_STAT);
+ if (status & ATA_CB_STAT_BSY) return 1;
+
+ outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
+
+ // sector will be 0 only on lba access. Convert to lba-chs
+ if (sector == 0) {
+ if ((count >= 1 << 8) || lba_high || (lba_low + count >= 1UL << 28)) {
+ outb(iobase1 + ATA_CB_FR, 0x00);
+ outb(iobase1 + ATA_CB_SC, (count >> 8) & 0xff);
+ outb(iobase1 + ATA_CB_SN, lba_low >> 24);
+ outb(iobase1 + ATA_CB_CL, lba_high & 0xff);
+ outb(iobase1 + ATA_CB_CH, lba_high >> 8);
+ command |= 0x04;
+ count &= (1UL << 8) - 1;
+ lba_low &= (1UL << 24) - 1;
+ }
+ sector = (Bit16u) (lba_low & 0x000000ffL);
+ cylinder = (Bit16u) ((lba_low>>8) & 0x0000ffffL);
+ head = ((Bit16u) ((lba_low>>24) & 0x0000000fL)) | ATA_CB_DH_LBA;
+ }
+
+ outb(iobase1 + ATA_CB_FR, 0x00);
+ outb(iobase1 + ATA_CB_SC, count);
+ outb(iobase1 + ATA_CB_SN, sector);
+ outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
+ outb(iobase1 + ATA_CB_CH, cylinder >> 8);
+ outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
+ outb(iobase1 + ATA_CB_CMD, command);
+
+ await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
+ status = inb(iobase1 + ATA_CB_STAT);
+
+ if (status & ATA_CB_STAT_ERR) {
+ BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
+ return 2;
+ } else if ( !(status & ATA_CB_STAT_DRQ) ) {
+ BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
+ return 3;
+ }
+
+ // FIXME : move seg/off translation here
+
+ASM_START
+ sti ;; enable higher priority interrupts
+ASM_END
+
+ while (1) {
+
+ASM_START
+ push bp
+ mov bp, sp
+ mov di, _ata_cmd_data_in.offset + 2[bp]
+ mov ax, _ata_cmd_data_in.segment + 2[bp]
+ mov cx, _ata_cmd_data_in.blksize + 2[bp]
+
+ ;; adjust if there will be an overrun. 2K max sector size
+ cmp di, #0xf800 ;;
+ jbe ata_in_no_adjust
+
+ata_in_adjust:
+ sub di, #0x0800 ;; sub 2 kbytes from offset
+ add ax, #0x0080 ;; add 2 Kbytes to segment
+
+ata_in_no_adjust:
+ mov es, ax ;; segment in es
+
+ mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
+
+ mov ah, _ata_cmd_data_in.mode + 2[bp]
+ cmp ah, #ATA_MODE_PIO32
+ je ata_in_32
+
+ata_in_16:
+ rep
+ insw ;; CX words transfered from port(DX) to ES:[DI]
+ jmp ata_in_done
+
+ata_in_32:
+ rep
+ insd ;; CX dwords transfered from port(DX) to ES:[DI]
+
+ata_in_done:
+ mov _ata_cmd_data_in.offset + 2[bp], di
+ mov _ata_cmd_data_in.segment + 2[bp], es
+ pop bp
+ASM_END
+
+ current++;
+ write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
+ count--;
+ await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
+ status = inb(iobase1 + ATA_CB_STAT);
+ if (count == 0) {
+ if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
+ != ATA_CB_STAT_RDY ) {
+ BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
+ return 4;
+ }
+ break;
+ }
+ else {
+ if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
+ != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
+ BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
+ return 5;
+ }
+ continue;
+ }
+ }
+ // Enable interrupts
+ outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+// ATA/ATAPI driver : execute a data-out command
+// ---------------------------------------------------------------------------
+ // returns
+ // 0 : no error
+ // 1 : BUSY bit set
+ // 2 : read error
+ // 3 : expected DRQ=1
+ // 4 : no sectors left to read/verify
+ // 5 : more sectors to read/verify
+ // 6 : no sectors left to write
+ // 7 : more sectors to write
+Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba_low, lba_high, segment, offset)
+Bit16u device, command, count, cylinder, head, sector, segment, offset;
+Bit32u lba_low, lba_high;
+{
+ Bit16u ebda_seg=read_word(0x0040,0x000E);
+ Bit16u iobase1, iobase2, blksize;
+ Bit8u channel, slave;
+ Bit8u status, current, mode;
+
+ channel = device / 2;
+ slave = device % 2;
+
+ iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
+ iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
+ mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
+ blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
+ if (mode == ATA_MODE_PIO32) blksize>>=2;
+ else blksize>>=1;
+
+ // Reset count of transferred data
+ write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
+ write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
+ current = 0;
+
+ status = inb(iobase1 + ATA_CB_STAT);
+ if (status & ATA_CB_STAT_BSY) return 1;
+
+ outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
+
+ // sector will be 0 only on lba access. Convert to lba-chs
+ if (sector == 0) {
+ if ((count >= 1 << 8) || lba_high || (lba_low + count >= 1UL << 28)) {
+ outb(iobase1 + ATA_CB_FR, 0x00);
+ outb(iobase1 + ATA_CB_SC, (count >> 8) & 0xff);
+ outb(iobase1 + ATA_CB_SN, lba_low >> 24);
+ outb(iobase1 + ATA_CB_CL, lba_high & 0xff);
+ outb(iobase1 + ATA_CB_CH, lba_high >> 8);
+ command |= 0x04;
+ count &= (1UL << 8) - 1;
+ lba_low &= (1UL << 24) - 1;
+ }
+ sector = (Bit16u) (lba_low & 0x000000ffL);
+ cylinder = (Bit16u) ((lba_low>>8) & 0x0000ffffL);
+ head = ((Bit16u) ((lba_low>>24) & 0x0000000fL)) | ATA_CB_DH_LBA;
+ }
+
+ outb(iobase1 + ATA_CB_FR, 0x00);
+ outb(iobase1 + ATA_CB_SC, count);
+ outb(iobase1 + ATA_CB_SN, sector);
+ outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
+ outb(iobase1 + ATA_CB_CH, cylinder >> 8);
+ outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
+ outb(iobase1 + ATA_CB_CMD, command);
+
+ await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
+ status = inb(iobase1 + ATA_CB_STAT);
+
+ if (status & ATA_CB_STAT_ERR) {
+ BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
+ return 2;
+ } else if ( !(status & ATA_CB_STAT_DRQ) ) {
+ BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
+ return 3;
+ }
+
+ // FIXME : move seg/off translation here
+
+ASM_START
+ sti ;; enable higher priority interrupts
+ASM_END
+
+ while (1) {
+
+ASM_START
+ push bp
+ mov bp, sp
+ mov si, _ata_cmd_data_out.offset + 2[bp]
+ mov ax, _ata_cmd_data_out.segment + 2[bp]
+ mov cx, _ata_cmd_data_out.blksize + 2[bp]
+
+ ;; adjust if there will be an overrun. 2K max sector size
+ cmp si, #0xf800 ;;
+ jbe ata_out_no_adjust
+
+ata_out_adjust:
+ sub si, #0x0800 ;; sub 2 kbytes from offset
+ add ax, #0x0080 ;; add 2 Kbytes to segment
+
+ata_out_no_adjust:
+ mov es, ax ;; segment in es
+
+ mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
+
+ mov ah, _ata_cmd_data_out.mode + 2[bp]
+ cmp ah, #ATA_MODE_PIO32
+ je ata_out_32
+
+ata_out_16:
+ seg ES
+ rep
+ outsw ;; CX words transfered from port(DX) to ES:[SI]
+ jmp ata_out_done
+
+ata_out_32:
+ seg ES
+ rep
+ outsd ;; CX dwords transfered from port(DX) to ES:[SI]
+
+ata_out_done:
+ mov _ata_cmd_data_out.offset + 2[bp], si
+ mov _ata_cmd_data_out.segment + 2[bp], es
+ pop bp
+ASM_END
+
+ current++;
+ write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
+ count--;
+ status = inb(iobase1 + ATA_CB_STAT);
+ if (count == 0) {
+ if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
+ != ATA_CB_STAT_RDY ) {
+ BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
+ return 6;
+ }
+ break;
+ }
+ else {
+ if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
+ != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
+ BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
+ return 7;
+ }
+ continue;
+ }
+ }
+ // Enable interrupts
+ outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+// ATA/ATAPI driver : execute a packet command
+// ---------------------------------------------------------------------------
+ // returns
+ // 0 : no error
+ // 1 : error in parameters
+ // 2 : BUSY bit set
+ // 3 : error
+ // 4 : not ready
+Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
+Bit8u cmdlen,inout;
+Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
+Bit16u header;
+Bit32u length;
+{
+ Bit16u ebda_seg=read_word(0x0040,0x000E);
+ Bit16u iobase1, iobase2;
+ Bit16u lcount, lbefore, lafter, count;
+ Bit8u channel, slave;
+ Bit8u status, mode, lmode;
+ Bit32u total, transfer;
+
+ channel = device / 2;
+ slave = device % 2;
+
+ // Data out is not supported yet
+ if (inout == ATA_DATA_OUT) {
+ BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
+ return 1;
+ }
+
+ // The header length must be even
+ if (header & 1) {
+ BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
+ return 1;
+ }
+
+ iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
+ iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
+ mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
+ transfer= 0L;
+
+ if (cmdlen < 12) cmdlen=12;
+ if (cmdlen > 12) cmdlen=16;
+ cmdlen>>=1;
+
+ // Reset count of transferred data
+ write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
+ write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
+
+ status = inb(iobase1 + ATA_CB_STAT);
+ if (status & ATA_CB_STAT_BSY) return 2;
+
+ outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
+ outb(iobase1 + ATA_CB_FR, 0x00);
+ outb(iobase1 + ATA_CB_SC, 0x00);
+ outb(iobase1 + ATA_CB_SN, 0x00);
+ outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
+ outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
+ outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
+ outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
+
+ // Device should ok to receive command
+ await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
+ status = inb(iobase1 + ATA_CB_STAT);
+
+ if (status & ATA_CB_STAT_ERR) {
+ BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
+ return 3;
+ } else if ( !(status & ATA_CB_STAT_DRQ) ) {
+ BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
+ return 4;
+ }
+
+ // Normalize address
+ cmdseg += (cmdoff / 16);
+ cmdoff %= 16;
+
+ // Send command to device
+ASM_START
+ sti ;; enable higher priority interrupts
+
+ push bp
+ mov bp, sp
+
+ mov si, _ata_cmd_packet.cmdoff + 2[bp]
+ mov ax, _ata_cmd_packet.cmdseg + 2[bp]
+ mov cx, _ata_cmd_packet.cmdlen + 2[bp]
+ mov es, ax ;; segment in es
+
+ mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
+
+ seg ES
+ rep
+ outsw ;; CX words transfered from port(DX) to ES:[SI]
+
+ pop bp
+ASM_END
+
+ if (inout == ATA_DATA_NO) {
+ await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
+ status = inb(iobase1 + ATA_CB_STAT);
+ }
+ else {
+ Bit16u loops = 0;
+ Bit8u sc;
+ while (1) {
+
+ if (loops == 0) {//first time through
+ status = inb(iobase2 + ATA_CB_ASTAT);
+ await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
+ }
+ else
+ await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
+ loops++;
+
+ status = inb(iobase1 + ATA_CB_STAT);
+ sc = inb(iobase1 + ATA_CB_SC);
+
+ // Check if command completed
+ if(((inb(iobase1 + ATA_CB_SC)&0x7)==0x3) &&
+ ((status & (ATA_CB_STAT_RDY | ATA_CB_STAT_ERR)) == ATA_CB_STAT_RDY)) break;
+
+ if (status & ATA_CB_STAT_ERR) {
+ BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
+ return 3;
+ }
+
+ // Normalize address
+ bufseg += (bufoff / 16);
+ bufoff %= 16;
+
+ // Get the byte count
+ lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
+
+ // adjust to read what we want
+ if(header>lcount) {
+ lbefore=lcount;
+ header-=lcount;
+ lcount=0;
+ }
+ else {
+ lbefore=header;
+ header=0;
+ lcount-=lbefore;
+ }
+
+ if(lcount>length) {
+ lafter=lcount-length;
+ lcount=length;
+ length=0;
+ }
+ else {
+ lafter=0;
+ length-=lcount;
+ }
+
+ // Save byte count
+ count = lcount;
+
+ BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
+ BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
+
+ // If counts not dividable by 4, use 16bits mode
+ lmode = mode;
+ if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
+ if (lcount & 0x03) lmode=ATA_MODE_PIO16;
+ if (lafter & 0x03) lmode=ATA_MODE_PIO16;
+
+ // adds an extra byte if count are odd. before is always even
+ if (lcount & 0x01) {
+ lcount+=1;
+ if ((lafter > 0) && (lafter & 0x01)) {
+ lafter-=1;
+ }
+ }
+
+ if (lmode == ATA_MODE_PIO32) {
+ lcount>>=2; lbefore>>=2; lafter>>=2;
+ }
+ else {
+ lcount>>=1; lbefore>>=1; lafter>>=1;
+ }
+
+ ; // FIXME bcc bug
+
+ASM_START
+ push bp
+ mov bp, sp
+
+ mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
+
+ mov cx, _ata_cmd_packet.lbefore + 2[bp]
+ jcxz ata_packet_no_before
+
+ mov ah, _ata_cmd_packet.lmode + 2[bp]
+ cmp ah, #ATA_MODE_PIO32
+ je ata_packet_in_before_32
+
+ata_packet_in_before_16:
+ in ax, dx
+ loop ata_packet_in_before_16
+ jmp ata_packet_no_before
+
+ata_packet_in_before_32:
+ push eax
+ata_packet_in_before_32_loop:
+ in eax, dx
+ loop ata_packet_in_before_32_loop
+ pop eax
+
+ata_packet_no_before:
+ mov cx, _ata_cmd_packet.lcount + 2[bp]
+ jcxz ata_packet_after
+
+ mov di, _ata_cmd_packet.bufoff + 2[bp]
+ mov ax, _ata_cmd_packet.bufseg + 2[bp]
+ mov es, ax
+
+ mov ah, _ata_cmd_packet.lmode + 2[bp]
+ cmp ah, #ATA_MODE_PIO32
+ je ata_packet_in_32
+
+ata_packet_in_16:
+ rep
+ insw ;; CX words transfered tp port(DX) to ES:[DI]
+ jmp ata_packet_after
+
+ata_packet_in_32:
+ rep
+ insd ;; CX dwords transfered to port(DX) to ES:[DI]
+
+ata_packet_after:
+ mov cx, _ata_cmd_packet.lafter + 2[bp]
+ jcxz ata_packet_done
+
+ mov ah, _ata_cmd_packet.lmode + 2[bp]
+ cmp ah, #ATA_MODE_PIO32
+ je ata_packet_in_after_32
+
+ata_packet_in_after_16:
+ in ax, dx
+ loop ata_packet_in_after_16
+ jmp ata_packet_done
+
+ata_packet_in_after_32:
+ push eax
+ata_packet_in_after_32_loop:
+ in eax, dx
+ loop ata_packet_in_after_32_loop
+ pop eax
+
+ata_packet_done:
+ pop bp
+ASM_END
+
+ // Compute new buffer address
+ bufoff += count;
+
+ // Save transferred bytes count
+ transfer += count;
+ write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
+ }
+ }
+
+ // Final check, device must be ready
+ if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
+ != ATA_CB_STAT_RDY ) {
+ BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
+ return 4;
+ }
+
+ // Enable interrupts
+ outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+// End of ATA/ATAPI Driver
+// ---------------------------------------------------------------------------
+
+// ---------------------------------------------------------------------------
+// Start of ATA/ATAPI generic functions
+// ---------------------------------------------------------------------------
+
+ Bit16u
+atapi_get_sense(device, seg, asc, ascq)
+ Bit16u device;
+{
+ Bit8u atacmd[12];
+ Bit8u buffer[18];
+ Bit8u i;
+
+ memsetb(get_SS(),atacmd,0,12);
+
+ // Request SENSE
+ atacmd[0]=ATA_CMD_REQUEST_SENSE;
+ atacmd[4]=sizeof(buffer);
+ if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 18L, ATA_DATA_IN, get_SS(), buffer) != 0)
+ return 0x0002;
+
+ write_byte(seg,asc,buffer[12]);
+ write_byte(seg,ascq,buffer[13]);
+
+ return 0;
+}
+
+ Bit16u
+atapi_is_ready(device)
+ Bit16u device;
+{
+ Bit8u packet[12];
+ Bit8u buf[8];
+ Bit32u block_len;
+ Bit32u sectors;
+ Bit32u timeout; //measured in ms
+ Bit32u time;
+ Bit8u asc, ascq;
+ Bit8u in_progress;
+ Bit16u ebda_seg = read_word(0x0040,0x000E);
+ if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI) {
+ printf("not implemented for non-ATAPI device\n");
+ return -1;
+ }
+
+ BX_DEBUG_ATA("ata_detect_medium: begin\n");
+ memsetb(get_SS(),packet, 0, sizeof packet);
+ packet[0] = 0x25; /* READ CAPACITY */
+
+ /* Retry READ CAPACITY 50 times unless MEDIUM NOT PRESENT
+ * is reported by the device. If the device reports "IN PROGRESS",
+ * 30 seconds is added. */
+ timeout = 5000;
+ time = 0;
+ in_progress = 0;
+ while (time < timeout) {
+ if (ata_cmd_packet(device, sizeof(packet), get_SS(), packet, 0, 8L, ATA_DATA_IN, get_SS(), buf) == 0)
+ goto ok;
+
+ if (atapi_get_sense(device, get_SS(), &asc, &ascq) == 0) {
+ if (asc == 0x3a) { /* MEDIUM NOT PRESENT */
+ BX_DEBUG_ATA("Device reports MEDIUM NOT PRESENT\n");
+ return -1;
+ }
+
+ if (asc == 0x04 && ascq == 0x01 && !in_progress) {
+ /* IN PROGRESS OF BECOMING READY */
+ printf("Waiting for device to detect medium... ");
+ /* Allow 30 seconds more */
+ timeout = 30000;
+ in_progress = 1;
+ }
+ }
+ time += 100;
+ }
+ BX_DEBUG_ATA("read capacity failed\n");
+ return -1;
+ok:
+
+ block_len = (Bit32u) buf[4] << 24
+ | (Bit32u) buf[5] << 16
+ | (Bit32u) buf[6] << 8
+ | (Bit32u) buf[7] << 0;
+ BX_DEBUG_ATA("block_len=%u\n", block_len);
+
+ if (block_len!= 2048 && block_len!= 512)
+ {
+ printf("Unsupported sector size %u\n", block_len);
+ return -1;
+ }
+ write_dword(ebda_seg,&EbdaData->ata.devices[device].blksize, block_len);
+
+ sectors = (Bit32u) buf[0] << 24
+ | (Bit32u) buf[1] << 16
+ | (Bit32u) buf[2] << 8
+ | (Bit32u) buf[3] << 0;
+
+ BX_DEBUG_ATA("sectors=%u\n", sectors);
+ if (block_len == 2048)
+ sectors <<= 2; /* # of sectors in 512-byte "soft" sector */
+ if (sectors != read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low))
+ printf("%dMB medium detected\n", sectors>>(20-9));
+ write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low, sectors);
+ return 0;
+}
+
+ Bit16u
+atapi_is_cdrom(device)
+ Bit8u device;
+{
+ Bit16u ebda_seg=read_word(0x0040,0x000E);
+
+ if (device >= BX_MAX_ATA_DEVICES)
+ return 0;
+
+ if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
+ return 0;
+
+ if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
+ return 0;
+
+ return 1;
+}
+
+// ---------------------------------------------------------------------------
+// End of ATA/ATAPI generic functions
+// ---------------------------------------------------------------------------
+
+#endif // BX_USE_ATADRV
+
+#if BX_ELTORITO_BOOT
+
+// ---------------------------------------------------------------------------
+// Start of El-Torito boot functions
+// ---------------------------------------------------------------------------
+
+ void
+cdemu_init()
+{
+ Bit16u ebda_seg=read_word(0x0040,0x000E);
+
+ // the only important data is this one for now
+ write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
+}
+
+ Bit8u
+cdemu_isactive()
+{
+ Bit16u ebda_seg=read_word(0x0040,0x000E);
+
+ return(read_byte(ebda_seg,&EbdaData->cdemu.active));
+}
+
+ Bit8u
+cdemu_emulated_drive()
+{
+ Bit16u ebda_seg=read_word(0x0040,0x000E);
+
+ return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
+}
+
+static char isotag[6]="CD001";
+static char eltorito[24]="EL TORITO SPECIFICATION";
+//
+// Returns ah: emulated drive, al: error code
+//
+ Bit16u
+cdrom_boot()
+{
+ Bit16u ebda_seg=read_word(0x0040,0x000E);
+ Bit8u atacmd[12], buffer[2048];
+ Bit32u lba;
+ Bit16u boot_segment, nbsectors, i, error;
+ Bit8u device;
+
+ // Find out the first cdrom
+ for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
+ if (atapi_is_cdrom(device)) break;
+ }
+
+ // if not found
+ if(device >= BX_MAX_ATA_DEVICES) return 2;
+
+ if(error = atapi_is_ready(device) != 0)
+ BX_INFO("ata_is_ready returned %d\n",error);
+
+ // Read the Boot Record Volume Descriptor
+ memsetb(get_SS(),atacmd,0,12);
+ atacmd[0]=0x28; // READ command
+ atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
+ atacmd[8]=(0x01 & 0x00ff); // Sectors
+ atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
+ atacmd[3]=(0x11 & 0x00ff0000) >> 16;
+ atacmd[4]=(0x11 & 0x0000ff00) >> 8;
+ atacmd[5]=(0x11 & 0x000000ff);
+ if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
+ return 3;
+
+ // Validity checks
+ if(buffer[0]!=0)return 4;
+ for(i=0;i<5;i++){
+ if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
+ }
+ for(i=0;i<23;i++)
+ if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
+
+ // ok, now we calculate the Boot catalog address
+ lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
+
+ // And we read the Boot Catalog
+ memsetb(get_SS(),atacmd,0,12);
+ atacmd[0]=0x28; // READ command
+ atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
+ atacmd[8]=(0x01 & 0x00ff); // Sectors
+ atacmd[2]=(lba & 0xff000000) >> 24; // LBA
+ atacmd[3]=(lba & 0x00ff0000) >> 16;
+ atacmd[4]=(lba & 0x0000ff00) >> 8;
+ atacmd[5]=(lba & 0x000000ff);
+ if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
+ 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
+
+ write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
+ if(buffer[0x21]==0){
+ // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
+ // Win2000 cd boot needs to know it booted from cd
+ write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
+ }
+ else if(buffer[0x21]<4)
+ write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
+ else
+ write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
+
+ write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
+ write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
+
+ boot_segment=buffer[0x23]*0x100+buffer[0x22];
+ if(boot_segment==0x0000)boot_segment=0x07C0;
+
+ write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
+ write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
+
+ nbsectors=buffer[0x27]*0x100+buffer[0x26];
+ write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
+
+ lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
+ write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
+
+ // And we read the image in memory
+ memsetb(get_SS(),atacmd,0,12);
+ atacmd[0]=0x28; // READ command
+ atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
+ atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
+ atacmd[2]=(lba & 0xff000000) >> 24; // LBA
+ atacmd[3]=(lba & 0x00ff0000) >> 16;
+ atacmd[4]=(lba & 0x0000ff00) >> 8;
+ atacmd[5]=(lba & 0x000000ff);
+ if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
+ return 12;
+
+ // Remember the media type
+ switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
+ case 0x01: // 1.2M floppy
+ write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
+ write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
+ write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
+ break;
+ case 0x02: // 1.44M floppy
+ write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
+ write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
+ write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
+ break;
+ case 0x03: // 2.88M floppy
+ write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
+ write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
+ write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
+ break;
+ case 0x04: // Harddrive
+ write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
+ write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
+ (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
+ write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
+ break;
+ }
+
+ if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
+ // Increase bios installed hardware number of devices
+ if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
+ write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
+ else
+ write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
+ }
+
+
+ // everything is ok, so from now on, the emulation is active
+ if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
+ write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
+
+ // return the boot drive + no error
+ return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
+}
+
+// ---------------------------------------------------------------------------
+// End of El-Torito boot functions
+// ---------------------------------------------------------------------------
+#endif // BX_ELTORITO_BOOT
+
+ void
+int14_function(regs, ds, iret_addr)
+ pusha_regs_t regs; // regs pushed from PUSHA instruction
+ Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
+ iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
+{
+ Bit16u addr,timer,val16;
+ Bit8u timeout;
+
+ ASM_START
+ sti
+ ASM_END
+
+ addr = read_word(0x0040, (regs.u.r16.dx << 1));
+ timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
+ if ((regs.u.r16.dx < 4) && (addr > 0)) {
+ switch (regs.u.r8.ah) {
+ case 0:
+ outb(addr+3, inb(addr+3) | 0x80);
+ if (regs.u.r8.al & 0xE0 == 0) {
+ outb(addr, 0x17);
+ outb(addr+1, 0x04);
+ } else {
+ val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
+ outb(addr, val16 & 0xFF);
+ outb(addr+1, val16 >> 8);
+ }
+ outb(addr+3, regs.u.r8.al & 0x1F);
+ regs.u.r8.ah = inb(addr+5);
+ regs.u.r8.al = inb(addr+6);
+ ClearCF(iret_addr.flags);
+ break;
+ case 1:
+ timer = read_word(0x0040, 0x006C);
+ while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
+ val16 = read_word(0x0040, 0x006C);
+ if (val16 != timer) {
+ timer = val16;
+ timeout--;
+ }
+ }
+ if (timeout) outb(addr, regs.u.r8.al);
+ regs.u.r8.ah = inb(addr+5);
+ if (!timeout) regs.u.r8.ah |= 0x80;
+ ClearCF(iret_addr.flags);
+ break;
+ case 2:
+ timer = read_word(0x0040, 0x006C);
+ while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
+ val16 = read_word(0x0040, 0x006C);
+ if (val16 != timer) {
+ timer = val16;
+ timeout--;
+ }
+ }
+ if (timeout) {
+ regs.u.r8.ah = 0;
+ regs.u.r8.al = inb(addr);
+ } else {
+ regs.u.r8.ah = inb(addr+5);
+ }
+ ClearCF(iret_addr.flags);
+ break;
+ case 3:
+ regs.u.r8.ah = inb(addr+5);
+ regs.u.r8.al = inb(addr+6);
+ ClearCF(iret_addr.flags);
+ break;
+ default:
+ SetCF(iret_addr.flags); // Unsupported
+ }
+ } else {
+ SetCF(iret_addr.flags); // Unsupported
+ }
+}
+
+ void
+int15_function(regs, ES, DS, FLAGS)
+ pusha_regs_t regs; // REGS pushed via pusha
+ Bit16u ES, DS, FLAGS;
+{
+ Bit16u ebda_seg=read_word(0x0040,0x000E);
+ bx_bool prev_a20_enable;
+ Bit16u base15_00;
+ Bit8u base23_16;
+ Bit16u ss;
+ Bit16u CX,DX;
+
+ Bit16u bRegister;
+ Bit8u irqDisable;
+
+BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
+
+ switch (regs.u.r8.ah) {
+ case 0x24: /* A20 Control */
+ switch (regs.u.r8.al) {
+ case 0x00:
+ set_enable_a20(0);
+ CLEAR_CF();
+ regs.u.r8.ah = 0;
+ break;
+ case 0x01:
+ set_enable_a20(1);
+ CLEAR_CF();
+ regs.u.r8.ah = 0;
+ break;
+ case 0x02:
+ regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
+ CLEAR_CF();
+ regs.u.r8.ah = 0;
+ break;
+ case 0x03:
+ CLEAR_CF();
+ regs.u.r8.ah = 0;
+ regs.u.r16.bx = 3;
+ break;
+ default:
+ BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
+ SET_CF();
+ regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+ }
+ break;
+
+ case 0x41:
+ SET_CF();
+ regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+ break;
+
+ case 0x4f:
+ /* keyboard intercept */
+#if BX_CPU < 2
+ regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+#else
+ // nop
+#endif
+ SET_CF();
+ break;
+
+ case 0x52: // removable media eject
+ CLEAR_CF();
+ regs.u.r8.ah = 0; // "ok ejection may proceed"
+ break;
+
+ case 0x83: {
+ if( regs.u.r8.al == 0 ) {
+ // Set Interval requested.
+ if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
+ // Interval not already set.
+ write_byte( 0x40, 0xA0, 1 ); // Set status byte.
+ write_word( 0x40, 0x98, ES ); // Byte location, segment
+ write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
+ write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
+ write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
+ CLEAR_CF( );
+ irqDisable = inb( 0xA1 );
+ outb( 0xA1, irqDisable & 0xFE );
+ bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
+ outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
+ } else {
+ // Interval already set.
+ BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
+ SET_CF();
+ regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+ }
+ } else if( regs.u.r8.al == 1 ) {
+ // Clear Interval requested
+ write_byte( 0x40, 0xA0, 0 ); // Clear status byte
+ CLEAR_CF( );
+ bRegister = inb_cmos( 0xB );
+ outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
+ } else {
+ BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
+ SET_CF();
+ regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+ regs.u.r8.al--;
+ }
+
+ break;
+ }
+
+ case 0x87:
+#if BX_CPU < 3
+# error "Int15 function 87h not supported on < 80386"
+#endif
+ // +++ should probably have descriptor checks
+ // +++ should have exception handlers
+
+ // turn off interrupts
+ASM_START
+ cli
+ASM_END
+
+ prev_a20_enable = set_enable_a20(1); // enable A20 line
+
+ // 128K max of transfer on 386+ ???
+ // source == destination ???
+
+ // ES:SI points to descriptor table
+ // offset use initially comments
+ // ==============================================
+ // 00..07 Unused zeros Null descriptor
+ // 08..0f GDT zeros filled in by BIOS
+ // 10..17 source ssssssss source of data
+ // 18..1f dest dddddddd destination of data
+ // 20..27 CS zeros filled in by BIOS
+ // 28..2f SS zeros filled in by BIOS
+
+ //es:si
+ //eeee0
+ //0ssss
+ //-----
+
+// check for access rights of source & dest here
+
+ // Initialize GDT descriptor
+ base15_00 = (ES << 4) + regs.u.r16.si;
+ base23_16 = ES >> 12;
+ if (base15_00 < (ES<<4))
+ base23_16++;
+ write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
+ write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
+ write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
+ write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
+ write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
+
+ // Initialize CS descriptor
+ write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
+ write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
+ write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
+ write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
+ write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
+
+ // Initialize SS descriptor
+ ss = get_SS();
+ base15_00 = ss << 4;
+ base23_16 = ss >> 12;
+ write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
+ write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
+ write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
+ write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
+ write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
+
+ CX = regs.u.r16.cx;
+ASM_START
+ // Compile generates locals offset info relative to SP.
+ // Get CX (word count) from stack.
+ mov bx, sp
+ SEG SS
+ mov cx, _int15_function.CX [bx]
+
+ // since we need to set SS:SP, save them to the BDA
+ // for future restore
+ push eax
+ xor eax, eax
+ mov ds, ax
+ mov 0x0469, ss
+ mov 0x0467, sp
+
+ SEG ES
+ lgdt [si + 0x08]
+ SEG CS
+ lidt [pmode_IDT_info]
+ ;; perhaps do something with IDT here
+
+ ;; set PE bit in CR0
+ mov eax, cr0
+ or al, #0x01
+ mov cr0, eax
+ ;; far jump to flush CPU queue after transition to protected mode
+ JMP_AP(0x0020, protected_mode)
+
+protected_mode:
+ ;; GDT points to valid descriptor table, now load SS, DS, ES
+ mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
+ mov ss, ax
+ mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
+ mov ds, ax
+ mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
+ mov es, ax
+ xor si, si
+ xor di, di
+ cld
+ rep
+ movsw ;; move CX words from DS:SI to ES:DI
+
+ ;; make sure DS and ES limits are 64KB
+ mov ax, #0x28
+ mov ds, ax
+ mov es, ax
+
+ ;; reset PG bit in CR0 ???
+ mov eax, cr0
+ and al, #0xFE
+ mov cr0, eax
+
+ ;; far jump to flush CPU queue after transition to real mode
+ JMP_AP(0xf000, real_mode)
+
+real_mode:
+ ;; restore IDT to normal real-mode defaults
+ SEG CS
+ lidt [rmode_IDT_info]
+
+ // restore SS:SP from the BDA
+ xor ax, ax
+ mov ds, ax
+ mov ss, 0x0469
+ mov sp, 0x0467
+ pop eax
+ASM_END
+
+ set_enable_a20(prev_a20_enable);
+
+ // turn back on interrupts
+ASM_START
+ sti
+ASM_END
+
+ regs.u.r8.ah = 0;
+ CLEAR_CF();
+ break;
+
+
+ case 0x88:
+ // Get the amount of extended memory (above 1M)
+#if BX_CPU < 2
+ regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+ SET_CF();
+#else
+ regs.u.r8.al = inb_cmos(0x30);
+ regs.u.r8.ah = inb_cmos(0x31);
+
+ // According to Ralf Brown's interrupt the limit should be 15M,
+ // but real machines mostly return max. 63M.
+ if(regs.u.r16.ax > 0xffc0)
+ regs.u.r16.ax = 0xffc0;
+
+ CLEAR_CF();
+#endif
+ break;
+
+ case 0x90:
+ /* Device busy interrupt. Called by Int 16h when no key available */
+ break;
+
+ case 0x91:
+ /* Interrupt complete. Called by Int 16h when key becomes available */
+ break;
+
+ case 0xbf:
+ BX_INFO("*** int 15h function AH=bf not yet supported!\n");
+ SET_CF();
+ regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+ break;
+
+ case 0xC0:
+#if 0
+ SET_CF();
+ regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+ break;
+#endif
+ CLEAR_CF();
+ regs.u.r8.ah = 0;
+ regs.u.r16.bx = BIOS_CONFIG_TABLE;
+ ES = 0xF000;
+ break;
+
+ case 0xc1:
+ ES = ebda_seg;
+ CLEAR_CF();
+ break;
+
+ case 0xd8:
+ bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
+ SET_CF();
+ regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+ break;
+
+ default:
+ BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
+ (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
+ SET_CF();
+ regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+ break;
+ }
+}
+
+#if BX_USE_PS2_MOUSE
+ void
+int15_function_mouse(regs, ES, DS, FLAGS)
+ pusha_regs_t regs; // REGS pushed via pusha
+ Bit16u ES, DS, FLAGS;
+{
+ Bit16u ebda_seg=read_word(0x0040,0x000E);
+ Bit8u mouse_flags_1, mouse_flags_2;
+ Bit16u mouse_driver_seg;
+ Bit16u mouse_driver_offset;
+ Bit8u comm_byte, prev_command_byte;
+ Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
+
+BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
+
+ switch (regs.u.r8.ah) {
+ case 0xC2:
+ // Return Codes status in AH
+ // =========================
+ // 00: success
+ // 01: invalid subfunction (AL > 7)
+ // 02: invalid input value (out of allowable range)
+ // 03: interface error
+ // 04: resend command received from mouse controller,
+ // device driver should attempt command again
+ // 05: cannot enable mouse, since no far call has been installed
+ // 80/86: mouse service not implemented
+
+ switch (regs.u.r8.al) {
+ case 0: // Disable/Enable Mouse
+BX_DEBUG_INT15("case 0:\n");
+ switch (regs.u.r8.bh) {
+ case 0: // Disable Mouse
+BX_DEBUG_INT15("case 0: disable mouse\n");
+ inhibit_mouse_int_and_events(); // disable IRQ12 and packets
+ ret = send_to_mouse_ctrl(0xF5); // disable mouse command
+ if (ret == 0) {
+ ret = get_mouse_data(&mouse_data1);
+ if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
+ CLEAR_CF();
+ regs.u.r8.ah = 0;
+ return;
+ }
+ }
+
+ // error
+ SET_CF();
+ regs.u.r8.ah = ret;
+ return;
+ break;
+
+ case 1: // Enable Mouse
+BX_DEBUG_INT15("case 1: enable mouse\n");
+ mouse_flags_2 = read_byte(ebda_seg, 0x0027);
+ if ( (mouse_flags_2 & 0x80) == 0 ) {
+ BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
+ SET_CF(); // error
+ regs.u.r8.ah = 5; // no far call installed
+ return;
+ }
+ inhibit_mouse_int_and_events(); // disable IRQ12 and packets
+ ret = send_to_mouse_ctrl(0xF4); // enable mouse command
+ if (ret == 0) {
+ ret = get_mouse_data(&mouse_data1);
+ if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
+ enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
+ CLEAR_CF();
+ regs.u.r8.ah = 0;
+ return;
+ }
+ }
+ SET_CF();
+ regs.u.r8.ah = ret;
+ return;
+
+ default: // invalid subfunction
+ BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
+ SET_CF(); // error
+ regs.u.r8.ah = 1; // invalid subfunction
+ return;
+ }
+ break;
+
+ case 1: // Reset Mouse
+ case 5: // Initialize Mouse
+BX_DEBUG_INT15("case 1 or 5:\n");
+ if (regs.u.r8.al == 5) {
+ if (regs.u.r8.bh != 3) {
+ SET_CF();
+ regs.u.r8.ah = 0x02; // invalid input
+ return;
+ }
+ mouse_flags_2 = read_byte(ebda_seg, 0x0027);
+ mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
+ mouse_flags_1 = 0x00;
+ write_byte(ebda_seg, 0x0026, mouse_flags_1);
+ write_byte(ebda_seg, 0x0027, mouse_flags_2);
+ }
+
+ inhibit_mouse_int_and_events(); // disable IRQ12 and packets
+ ret = send_to_mouse_ctrl(0xFF); // reset mouse command
+ if (ret == 0) {
+ ret = get_mouse_data(&mouse_data3);
+ // if no mouse attached, it will return RESEND
+ if (mouse_data3 == 0xfe) {
+ SET_CF();
+ return;
+ }
+ if (mouse_data3 != 0xfa)
+ BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
+ if ( ret == 0 ) {
+ ret = get_mouse_data(&mouse_data1);
+ if ( ret == 0 ) {
+ ret = get_mouse_data(&mouse_data2);
+ if ( ret == 0 ) {
+ // turn IRQ12 and packet generation on
+ enable_mouse_int_and_events();
+ CLEAR_CF();
+ regs.u.r8.ah = 0;
+ regs.u.r8.bl = mouse_data1;
+ regs.u.r8.bh = mouse_data2;
+ return;
+ }
+ }
+ }
+ }
+
+ // error
+ SET_CF();
+ regs.u.r8.ah = ret;
+ return;
+
+ case 2: // Set Sample Rate
+BX_DEBUG_INT15("case 2:\n");
+ switch (regs.u.r8.bh) {
+ case 0: mouse_data1 = 10; break; // 10 reports/sec
+ case 1: mouse_data1 = 20; break; // 20 reports/sec
+ case 2: mouse_data1 = 40; break; // 40 reports/sec
+ case 3: mouse_data1 = 60; break; // 60 reports/sec
+ case 4: mouse_data1 = 80; break; // 80 reports/sec
+ case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
+ case 6: mouse_data1 = 200; break; // 200 reports/sec
+ default: mouse_data1 = 0;
+ }
+ if (mouse_data1 > 0) {
+ ret = send_to_mouse_ctrl(0xF3); // set sample rate command
+ if (ret == 0) {
+ ret = get_mouse_data(&mouse_data2);
+ ret = send_to_mouse_ctrl(mouse_data1);
+ ret = get_mouse_data(&mouse_data2);
+ CLEAR_CF();
+ regs.u.r8.ah = 0;
+ } else {
+ // error
+ SET_CF();
+ regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+ }
+ } else {
+ // error
+ SET_CF();
+ regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+ }
+ break;
+
+ case 3: // Set Resolution
+BX_DEBUG_INT15("case 3:\n");
+ // 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
+ comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
+ if (regs.u.r8.bh < 4) {
+ ret = send_to_mouse_ctrl(0xE8); // set resolution command
+ if (ret == 0) {
+ ret = get_mouse_data(&mouse_data1);
+ if (mouse_data1 != 0xfa)
+ BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
+ ret = send_to_mouse_ctrl(regs.u.r8.bh);
+ ret = get_mouse_data(&mouse_data1);
+ if (mouse_data1 != 0xfa)
+ BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
+ CLEAR_CF();
+ regs.u.r8.ah = 0;
+ } else {
+ // error
+ SET_CF();
+ regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+ }
+ } else {
+ // error
+ SET_CF();
+ regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+ }
+ set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
+ break;
+
+ case 4: // Get Device ID
+BX_DEBUG_INT15("case 4:\n");
+ inhibit_mouse_int_and_events(); // disable IRQ12 and packets
+ ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
+ if (ret == 0) {
+ ret = get_mouse_data(&mouse_data1);
+ ret = get_mouse_data(&mouse_data2);
+ CLEAR_CF();
+ regs.u.r8.ah = 0;
+ regs.u.r8.bh = mouse_data2;
+ } else {
+ // error
+ SET_CF();
+ regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+ }
+ break;
+
+ case 6: // Return Status & Set Scaling Factor...
+BX_DEBUG_INT15("case 6:\n");
+ switch (regs.u.r8.bh) {
+ case 0: // Return Status
+ comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
+ ret = send_to_mouse_ctrl(0xE9); // get mouse info command
+ if (ret == 0) {
+ ret = get_mouse_data(&mouse_data1);
+ if (mouse_data1 != 0xfa)
+ BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
+ if (ret == 0) {
+ ret = get_mouse_data(&mouse_data1);
+ if ( ret == 0 ) {
+ ret = get_mouse_data(&mouse_data2);
+ if ( ret == 0 ) {
+ ret = get_mouse_data(&mouse_data3);
+ if ( ret == 0 ) {
+ CLEAR_CF();
+ regs.u.r8.ah = 0;
+ regs.u.r8.bl = mouse_data1;
+ regs.u.r8.cl = mouse_data2;
+ regs.u.r8.dl = mouse_data3;
+ set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ // error
+ SET_CF();
+ regs.u.r8.ah = ret;
+ set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
+ return;
+
+ case 1: // Set Scaling Factor to 1:1
+ case 2: // Set Scaling Factor to 2:1
+ comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
+ if (regs.u.r8.bh == 1) {
+ ret = send_to_mouse_ctrl(0xE6);
+ } else {
+ ret = send_to_mouse_ctrl(0xE7);
+ }
+ if (ret == 0) {
+ get_mouse_data(&mouse_data1);
+ ret = (mouse_data1 != 0xFA);
+ }
+ if (ret == 0) {
+ CLEAR_CF();
+ regs.u.r8.ah = 0;
+ } else {
+ // error
+ SET_CF();
+ regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+ }
+ set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
+ break;
+
+ default:
+ BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
+ }
+ break;
+
+ case 7: // Set Mouse Handler Address
+BX_DEBUG_INT15("case 7:\n");
+ mouse_driver_seg = ES;
+ mouse_driver_offset = regs.u.r16.bx;
+ write_word(ebda_seg, 0x0022, mouse_driver_offset);
+ write_word(ebda_seg, 0x0024, mouse_driver_seg);
+ mouse_flags_2 = read_byte(ebda_seg, 0x0027);
+ if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
+ /* remove handler */
+ if ( (mouse_flags_2 & 0x80) != 0 ) {
+ mouse_flags_2 &= ~0x80;
+ inhibit_mouse_int_and_events(); // disable IRQ12 and packets
+ }
+ }
+ else {
+ /* install handler */
+ mouse_flags_2 |= 0x80;
+ }
+ write_byte(ebda_seg, 0x0027, mouse_flags_2);
+ CLEAR_CF();
+ regs.u.r8.ah = 0;
+ break;
+
+ default:
+BX_DEBUG_INT15("case default:\n");
+ regs.u.r8.ah = 1; // invalid function
+ SET_CF();
+ }
+ break;
+
+ default:
+ BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
+ (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
+ SET_CF();
+ regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+ break;
+ }
+}
+#endif // BX_USE_PS2_MOUSE
+
+
+void set_e820_range(ES, DI, start, end, extra_start, extra_end, type)
+ Bit16u ES;
+ Bit16u DI;
+ Bit32u start;
+ Bit32u end;
+ Bit8u extra_start;
+ Bit8u extra_end;
+ Bit16u type;
+{
+ write_word(ES, DI, start);
+ write_word(ES, DI+2, start >> 16);
+ write_word(ES, DI+4, extra_start);
+ write_word(ES, DI+6, 0x00);
+
+ end -= start;
+ extra_end -= extra_start;
+ write_word(ES, DI+8, end);
+ write_word(ES, DI+10, end >> 16);
+ write_word(ES, DI+12, extra_end);
+ write_word(ES, DI+14, 0x0000);
+
+ write_word(ES, DI+16, type);
+ write_word(ES, DI+18, 0x0);
+}
+
+ void
+int15_function32(regs, ES, DS, FLAGS)
+ pushad_regs_t regs; // REGS pushed via pushad
+ Bit16u ES, DS, FLAGS;
+{
+ Bit32u extended_memory_size=0; // 64bits long
+ Bit32u extra_lowbits_memory_size=0;
+ Bit16u CX,DX;
+ Bit8u extra_highbits_memory_size=0;
+
+BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
+
+ switch (regs.u.r8.ah) {
+ case 0x86:
+ // Wait for CX:DX microseconds. currently using the
+ // refresh request port 0x61 bit4, toggling every 15usec
+
+ CX = regs.u.r16.cx;
+ DX = regs.u.r16.dx;
+
+ASM_START
+ sti
+
+ ;; Get the count in eax
+ mov bx, sp
+ SEG SS
+ mov ax, _int15_function32.CX [bx]
+ shl eax, #16
+ SEG SS
+ mov ax, _int15_function32.DX [bx]
+
+ ;; convert to numbers of 15usec ticks
+ mov ebx, #15
+ xor edx, edx
+ div eax, ebx
+ mov ecx, eax
+
+ ;; wait for ecx number of refresh requests
+ in al, #0x61
+ and al,#0x10
+ mov ah, al
+
+ or ecx, ecx
+ je int1586_tick_end
+int1586_tick:
+ in al, #0x61
+ and al,#0x10
+ cmp al, ah
+ je int1586_tick
+ mov ah, al
+ dec ecx
+ jnz int1586_tick
+int1586_tick_end:
+ASM_END
+
+ break;
+
+ case 0xe8:
+ switch(regs.u.r8.al)
+ {
+ case 0x20: // coded by osmaker aka K.J.
+ if(regs.u.r32.edx == 0x534D4150)
+ {
+ extended_memory_size = inb_cmos(0x35);
+ extended_memory_size <<= 8;
+ extended_memory_size |= inb_cmos(0x34);
+ extended_memory_size *= 64;
+ // greater than EFF00000???
+ if(extended_memory_size > 0x3bc000) {
+ extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
+ }
+ extended_memory_size *= 1024;
+ extended_memory_size += (16L * 1024 * 1024);
+
+ if(extended_memory_size <= (16L * 1024 * 1024)) {
+ extended_memory_size = inb_cmos(0x31);
+ extended_memory_size <<= 8;
+ extended_memory_size |= inb_cmos(0x30);
+ extended_memory_size *= 1024;
+ extended_memory_size += (1L * 1024 * 1024);
+ }
+
+ extra_lowbits_memory_size = inb_cmos(0x5c);
+ extra_lowbits_memory_size <<= 8;
+ extra_lowbits_memory_size |= inb_cmos(0x5b);
+ extra_lowbits_memory_size *= 64;
+ extra_lowbits_memory_size *= 1024;
+ extra_highbits_memory_size = inb_cmos(0x5d);
+
+ switch(regs.u.r16.bx)
+ {
+ case 0:
+ set_e820_range(ES, regs.u.r16.di,
+ 0x0000000L, 0x0009f000L, 0, 0, 1);
+ regs.u.r32.ebx = 1;
+ break;
+ case 1:
+ set_e820_range(ES, regs.u.r16.di,
+ 0x0009f000L, 0x000a0000L, 0, 0, 2);
+ regs.u.r32.ebx = 2;
+ break;
+ case 2:
+ set_e820_range(ES, regs.u.r16.di,
+ 0x000e8000L, 0x00100000L, 0, 0, 2);
+ regs.u.r32.ebx = 3;
+ break;
+ case 3:
+#if BX_ROMBIOS32
+ set_e820_range(ES, regs.u.r16.di,
+ 0x00100000L,
+ extended_memory_size - ACPI_DATA_SIZE ,0, 0, 1);
+ regs.u.r32.ebx = 4;
+#else
+ set_e820_range(ES, regs.u.r16.di,
+ 0x00100000L,
+ extended_memory_size, 1);
+ regs.u.r32.ebx = 5;
+#endif
+ break;
+ case 4:
+ set_e820_range(ES, regs.u.r16.di,
+ extended_memory_size - ACPI_DATA_SIZE,
+ extended_memory_size ,0, 0, 3); // ACPI RAM
+ regs.u.r32.ebx = 5;
+ break;
+ case 5:
+ /* 256KB BIOS area at the end of 4 GB */
+ set_e820_range(ES, regs.u.r16.di,
+ 0xfffc0000L, 0x00000000L ,0, 0, 2);
+ if (extra_highbits_memory_size || extra_lowbits_memory_size)
+ regs.u.r32.ebx = 6;
+ else
+ regs.u.r32.ebx = 0;
+ break;
+ case 6:
+ /* Maping of memory above 4 GB */
+ set_e820_range(ES, regs.u.r16.di, 0x00000000L,
+ extra_lowbits_memory_size, 1, extra_highbits_memory_size
+ + 1, 1);
+ regs.u.r32.ebx = 0;
+ break;
+ default: /* AX=E820, DX=534D4150, BX unrecognized */
+ goto int15_unimplemented;
+ break;
+ }
+ regs.u.r32.eax = 0x534D4150;
+ regs.u.r32.ecx = 0x14;
+ CLEAR_CF();
+ } else {
+ // if DX != 0x534D4150)
+ goto int15_unimplemented;
+ }
+ break;
+
+ case 0x01:
+ // do we have any reason to fail here ?
+ CLEAR_CF();
+
+ // my real system sets ax and bx to 0
+ // this is confirmed by Ralph Brown list
+ // but syslinux v1.48 is known to behave
+ // strangely if ax is set to 0
+ // regs.u.r16.ax = 0;
+ // regs.u.r16.bx = 0;
+
+ // Get the amount of extended memory (above 1M)
+ regs.u.r8.cl = inb_cmos(0x30);
+ regs.u.r8.ch = inb_cmos(0x31);
+
+ // limit to 15M
+ if(regs.u.r16.cx > 0x3c00)
+ {
+ regs.u.r16.cx = 0x3c00;
+ }
+
+ // Get the amount of extended memory above 16M in 64k blocs
+ regs.u.r8.dl = inb_cmos(0x34);
+ regs.u.r8.dh = inb_cmos(0x35);
+
+ // Set configured memory equal to extended memory
+ regs.u.r16.ax = regs.u.r16.cx;
+ regs.u.r16.bx = regs.u.r16.dx;
+ break;
+ default: /* AH=0xE8?? but not implemented */
+ goto int15_unimplemented;
+ }
+ break;
+ int15_unimplemented:
+ // fall into the default
+ default:
+ BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
+ (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
+ SET_CF();
+ regs.u.r8.ah = UNSUPPORTED_FUNCTION;
+ break;
+ }
+}
+
+ void
+int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
+ Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
+{
+ Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
+ Bit16u kbd_code, max;
+
+ BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
+
+ shift_flags = read_byte(0x0040, 0x17);
+ led_flags = read_byte(0x0040, 0x97);
+ if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
+ASM_START
+ cli
+ASM_END
+ outb(0x60, 0xed);
+ while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
+ if ((inb(0x60) == 0xfa)) {
+ led_flags &= 0xf8;
+ led_flags |= ((shift_flags >> 4) & 0x07);
+ outb(0x60, led_flags & 0x07);
+ while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
+ inb(0x60);
+ write_byte(0x0040, 0x97, led_flags);
+ }
+ASM_START
+ sti
+ASM_END
+ }
+
+ switch (GET_AH()) {
+ case 0x00: /* read keyboard input */
+
+ if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
+ BX_PANIC("KBD: int16h: out of keyboard input\n");
+ }
+ if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
+ else if (ascii_code == 0xE0) ascii_code = 0;
+ AX = (scan_code << 8) | ascii_code;
+ break;
+
+ case 0x01: /* check keyboard status */
+ if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
+ SET_ZF();
+ return;
+ }
+ if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
+ else if (ascii_code == 0xE0) ascii_code = 0;
+ AX = (scan_code << 8) | ascii_code;
+ CLEAR_ZF();
+ break;
+
+ case 0x02: /* get shift flag status */
+ shift_flags = read_byte(0x0040, 0x17);
+ SET_AL(shift_flags);
+ break;
+
+ case 0x05: /* store key-stroke into buffer */
+ if ( !enqueue_key(GET_CH(), GET_CL()) ) {
+ SET_AL(1);
+ }
+ else {
+ SET_AL(0);
+ }
+ break;
+
+ case 0x09: /* GET KEYBOARD FUNCTIONALITY */
+ // 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
+ //
+ SET_AL(0x30);
+ break;
+
+ case 0x0A: /* GET KEYBOARD ID */
+ count = 2;
+ kbd_code = 0x0;
+ outb(0x60, 0xf2);
+ /* Wait for data */
+ max=0xffff;
+ while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
+ if (max>0x0) {
+ if ((inb(0x60) == 0xfa)) {
+ do {
+ max=0xffff;
+ while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
+ if (max>0x0) {
+ kbd_code >>= 8;
+ kbd_code |= (inb(0x60) << 8);
+ }
+ } while (--count>0);
+ }
+ }
+ BX=kbd_code;
+ break;
+
+ case 0x10: /* read MF-II keyboard input */
+
+ if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
+ BX_PANIC("KBD: int16h: out of keyboard input\n");
+ }
+ if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
+ AX = (scan_code << 8) | ascii_code;
+ break;
+
+ case 0x11: /* check MF-II keyboard status */
+ if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
+ SET_ZF();
+ return;
+ }
+ if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
+ AX = (scan_code << 8) | ascii_code;
+ CLEAR_ZF();
+ break;
+
+ case 0x12: /* get extended keyboard status */
+ shift_flags = read_byte(0x0040, 0x17);
+ SET_AL(shift_flags);
+ shift_flags = read_byte(0x0040, 0x18) & 0x73;
+ shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
+ SET_AH(shift_flags);
+ BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
+ break;
+
+ case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
+ SET_AH(0x80); // function int16 ah=0x10-0x12 supported
+ break;
+
+ case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
+ // don't change AH : function int16 ah=0x20-0x22 NOT supported
+ break;
+
+ case 0x6F:
+ if (GET_AL() == 0x08)
+ SET_AH(0x02); // unsupported, aka normal keyboard
+
+ default:
+ BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
+ }
+}
+
+ unsigned int
+dequeue_key(scan_code, ascii_code, incr)
+ Bit8u *scan_code;
+ Bit8u *ascii_code;
+ unsigned int incr;
+{
+ Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
+ Bit16u ss;
+ Bit8u acode, scode;
+
+#if BX_CPU < 2
+ buffer_start = 0x001E;
+ buffer_end = 0x003E;
+#else
+ buffer_start = read_word(0x0040, 0x0080);
+ buffer_end = read_word(0x0040, 0x0082);
+#endif
+
+ buffer_head = read_word(0x0040, 0x001a);
+ buffer_tail = read_word(0x0040, 0x001c);
+
+ if (buffer_head != buffer_tail) {
+ ss = get_SS();
+ acode = read_byte(0x0040, buffer_head);
+ scode = read_byte(0x0040, buffer_head+1);
+ write_byte(ss, ascii_code, acode);
+ write_byte(ss, scan_code, scode);
+
+ if (incr) {
+ buffer_head += 2;
+ if (buffer_head >= buffer_end)
+ buffer_head = buffer_start;
+ write_word(0x0040, 0x001a, buffer_head);
+ }
+ return(1);
+ }
+ else {
+ return(0);
+ }
+}
+
+static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
+
+ Bit8u
+inhibit_mouse_int_and_events()
+{
+ Bit8u command_byte, prev_command_byte;
+
+ // Turn off IRQ generation and aux data line
+ if ( inb(0x64) & 0x02 )
+ BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
+ outb(0x64, 0x20); // get command byte
+ while ( (inb(0x64) & 0x01) != 0x01 );
+ prev_command_byte = inb(0x60);
+ command_byte = prev_command_byte;
+ //while ( (inb(0x64) & 0x02) );
+ if ( inb(0x64) & 0x02 )
+ BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
+ command_byte &= 0xfd; // turn off IRQ 12 generation
+ command_byte |= 0x20; // disable mouse serial clock line
+ outb(0x64, 0x60); // write command byte
+ outb(0x60, command_byte);
+ return(prev_command_byte);
+}
+
+ void
+enable_mouse_int_and_events()
+{
+ Bit8u command_byte;
+
+ // Turn on IRQ generation and aux data line
+ if ( inb(0x64) & 0x02 )
+ BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
+ outb(0x64, 0x20); // get command byte
+ while ( (inb(0x64) & 0x01) != 0x01 );
+ command_byte = inb(0x60);
+ //while ( (inb(0x64) & 0x02) );
+ if ( inb(0x64) & 0x02 )
+ BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
+ command_byte |= 0x02; // turn on IRQ 12 generation
+ command_byte &= 0xdf; // enable mouse serial clock line
+ outb(0x64, 0x60); // write command byte
+ outb(0x60, command_byte);
+}
+
+ Bit8u
+send_to_mouse_ctrl(sendbyte)
+ Bit8u sendbyte;
+{
+ Bit8u response;
+
+ // wait for chance to write to ctrl
+ if ( inb(0x64) & 0x02 )
+ BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
+ outb(0x64, 0xD4);
+ outb(0x60, sendbyte);
+ return(0);
+}
+
+
+ Bit8u
+get_mouse_data(data)
+ Bit8u *data;
+{
+ Bit8u response;
+ Bit16u ss;
+
+ while ( (inb(0x64) & 0x21) != 0x21 ) {
+ }
+
+ response = inb(0x60);
+
+ ss = get_SS();
+ write_byte(ss, data, response);
+ return(0);
+}
+
+ void
+set_kbd_command_byte(command_byte)
+ Bit8u command_byte;
+{
+ if ( inb(0x64) & 0x02 )
+ BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
+ outb(0x64, 0xD4);
+
+ outb(0x64, 0x60); // write command byte
+ outb(0x60, command_byte);
+}
+
+ void
+int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
+ Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
+{
+ Bit8u scancode, asciicode, shift_flags;
+ Bit8u mf2_flags, mf2_state;
+
+ //
+ // DS has been set to F000 before call
+ //
+
+
+ scancode = GET_AL();
+
+ if (scancode == 0) {
+ BX_INFO("KBD: int09 handler: AL=0\n");
+ return;
+ }
+
+
+ shift_flags = read_byte(0x0040, 0x17);
+ mf2_flags = read_byte(0x0040, 0x18);
+ mf2_state = read_byte(0x0040, 0x96);
+ asciicode = 0;
+
+ switch (scancode) {
+ case 0x3a: /* Caps Lock press */
+ shift_flags ^= 0x40;
+ write_byte(0x0040, 0x17, shift_flags);
+ mf2_flags |= 0x40;
+ write_byte(0x0040, 0x18, mf2_flags);
+ break;
+ case 0xba: /* Caps Lock release */
+ mf2_flags &= ~0x40;
+ write_byte(0x0040, 0x18, mf2_flags);
+ break;
+
+ case 0x2a: /* L Shift press */
+ shift_flags |= 0x02;
+ write_byte(0x0040, 0x17, shift_flags);
+ break;
+ case 0xaa: /* L Shift release */
+ shift_flags &= ~0x02;
+ write_byte(0x0040, 0x17, shift_flags);
+ break;
+
+ case 0x36: /* R Shift press */
+ shift_flags |= 0x01;
+ write_byte(0x0040, 0x17, shift_flags);
+ break;
+ case 0xb6: /* R Shift release */
+ shift_flags &= ~0x01;
+ write_byte(0x0040, 0x17, shift_flags);
+ break;
+
+ case 0x1d: /* Ctrl press */
+ if ((mf2_state & 0x01) == 0) {
+ shift_flags |= 0x04;
+ write_byte(0x0040, 0x17, shift_flags);
+ if (mf2_state & 0x02) {
+ mf2_state |= 0x04;
+ write_byte(0x0040, 0x96, mf2_state);
+ } else {
+ mf2_flags |= 0x01;
+ write_byte(0x0040, 0x18, mf2_flags);
+ }
+ }
+ break;
+ case 0x9d: /* Ctrl release */
+ if ((mf2_state & 0x01) == 0) {
+ shift_flags &= ~0x04;
+ write_byte(0x0040, 0x17, shift_flags);
+ if (mf2_state & 0x02) {
+ mf2_state &= ~0x04;
+ write_byte(0x0040, 0x96, mf2_state);
+ } else {
+ mf2_flags &= ~0x01;
+ write_byte(0x0040, 0x18, mf2_flags);
+ }
+ }
+ break;
+
+ case 0x38: /* Alt press */
+ shift_flags |= 0x08;
+ write_byte(0x0040, 0x17, shift_flags);
+ if (mf2_state & 0x02) {
+ mf2_state |= 0x08;
+ write_byte(0x0040, 0x96, mf2_state);
+ } else {
+ mf2_flags |= 0x02;
+ write_byte(0x0040, 0x18, mf2_flags);
+ }
+ break;
+ case 0xb8: /* Alt release */
+ shift_flags &= ~0x08;
+ write_byte(0x0040, 0x17, shift_flags);
+ if (mf2_state & 0x02) {
+ mf2_state &= ~0x08;
+ write_byte(0x0040, 0x96, mf2_state);
+ } else {
+ mf2_flags &= ~0x02;
+ write_byte(0x0040, 0x18, mf2_flags);
+ }
+ break;
+
+ case 0x45: /* Num Lock press */
+ if ((mf2_state & 0x03) == 0) {
+ mf2_flags |= 0x20;
+ write_byte(0x0040, 0x18, mf2_flags);
+ shift_flags ^= 0x20;
+ write_byte(0x0040, 0x17, shift_flags);
+ }
+ break;
+ case 0xc5: /* Num Lock release */
+ if ((mf2_state & 0x03) == 0) {
+ mf2_flags &= ~0x20;
+ write_byte(0x0040, 0x18, mf2_flags);
+ }
+ break;
+
+ case 0x46: /* Scroll Lock press */
+ mf2_flags |= 0x10;
+ write_byte(0x0040, 0x18, mf2_flags);
+ shift_flags ^= 0x10;
+ write_byte(0x0040, 0x17, shift_flags);
+ break;
+
+ case 0xc6: /* Scroll Lock release */
+ mf2_flags &= ~0x10;
+ write_byte(0x0040, 0x18, mf2_flags);
+ break;
+
+ default:
+ if (scancode & 0x80) {
+ break; /* toss key releases ... */
+ }
+ if (scancode > MAX_SCAN_CODE) {
+ BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
+ return;
+ }
+ if (shift_flags & 0x08) { /* ALT */
+ asciicode = scan_to_scanascii[scancode].alt;
+ scancode = scan_to_scanascii[scancode].alt >> 8;
+ } else if (shift_flags & 0x04) { /* CONTROL */
+ asciicode = scan_to_scanascii[scancode].control;
+ scancode = scan_to_scanascii[scancode].control >> 8;
+ } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
+ /* extended keys handling */
+ asciicode = 0xe0;
+ scancode = scan_to_scanascii[scancode].normal >> 8;
+ } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
+ /* check if lock state should be ignored
+ * because a SHIFT key are pressed */
+
+ if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
+ asciicode = scan_to_scanascii[scancode].normal;
+ scancode = scan_to_scanascii[scancode].normal >> 8;
+ } else {
+ asciicode = scan_to_scanascii[scancode].shift;
+ scancode = scan_to_scanascii[scancode].shift >> 8;
+ }
+ } else {
+ /* check if lock is on */
+ if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
+ asciicode = scan_to_scanascii[scancode].shift;
+ scancode = scan_to_scanascii[scancode].shift >> 8;
+ } else {
+ asciicode = scan_to_scanascii[scancode].normal;
+ scancode = scan_to_scanascii[scancode].normal >> 8;
+ }
+ }
+ if (scancode==0 && asciicode==0) {
+ BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
+ }
+ enqueue_key(scancode, asciicode);
+ break;
+ }
+ if ((scancode & 0x7f) != 0x1d) {
+ mf2_state &= ~0x01;
+ }
+ mf2_state &= ~0x02;
+ write_byte(0x0040, 0x96, mf2_state);
+}
+
+ unsigned int
+enqueue_key(scan_code, ascii_code)
+ Bit8u scan_code, ascii_code;
+{
+ Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
+
+#if BX_CPU < 2
+ buffer_start = 0x001E;
+ buffer_end = 0x003E;
+#else
+ buffer_start = read_word(0x0040, 0x0080);
+ buffer_end = read_word(0x0040, 0x0082);
+#endif
+
+ buffer_head = read_word(0x0040, 0x001A);
+ buffer_tail = read_word(0x0040, 0x001C);
+
+ temp_tail = buffer_tail;
+ buffer_tail += 2;
+ if (buffer_tail >= buffer_end)
+ buffer_tail = buffer_start;
+
+ if (buffer_tail == buffer_head) {
+ return(0);
+ }
+
+ write_byte(0x0040, temp_tail, ascii_code);
+ write_byte(0x0040, temp_tail+1, scan_code);
+ write_word(0x0040, 0x001C, buffer_tail);
+ return(1);
+}
+
+
+ void
+int74_function(make_farcall, Z, Y, X, status)
+ Bit16u make_farcall, Z, Y, X, status;
+{
+ Bit16u ebda_seg=read_word(0x0040,0x000E);
+ Bit8u in_byte, index, package_count;
+ Bit8u mouse_flags_1, mouse_flags_2;
+
+BX_DEBUG_INT74("entering int74_function\n");
+ make_farcall = 0;
+
+ in_byte = inb(0x64);
+ if ( (in_byte & 0x21) != 0x21 ) {
+ return;
+ }
+ in_byte = inb(0x60);
+BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
+
+ mouse_flags_1 = read_byte(ebda_seg, 0x0026);
+ mouse_flags_2 = read_byte(ebda_seg, 0x0027);
+
+ if ( (mouse_flags_2 & 0x80) != 0x80 ) {
+ return;
+ }
+
+ package_count = mouse_flags_2 & 0x07;
+ index = mouse_flags_1 & 0x07;
+ write_byte(ebda_seg, 0x28 + index, in_byte);
+
+ if ( (index+1) >= package_count ) {
+BX_DEBUG_INT74("int74_function: make_farcall=1\n");
+ status = read_byte(ebda_seg, 0x0028 + 0);
+ X = read_byte(ebda_seg, 0x0028 + 1);
+ Y = read_byte(ebda_seg, 0x0028 + 2);
+ Z = 0;
+ mouse_flags_1 = 0;
+ // check if far call handler installed
+ if (mouse_flags_2 & 0x80)
+ make_farcall = 1;
+ }
+ else {
+ mouse_flags_1++;
+ }
+ write_byte(ebda_seg, 0x0026, mouse_flags_1);
+}
+
+#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
+
+#if BX_USE_ATADRV
+
+ void
+int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
+ Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
+{
+ Bit32u lba_low, lba_high;
+ Bit16u ebda_seg=read_word(0x0040,0x000E);
+ Bit16u cylinder, head, sector;
+ Bit16u segment, offset;
+ Bit16u npc, nph, npspt, nlc, nlh, nlspt;
+ Bit16u size, count;
+ Bit8u device, status;
+
+ BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
+
+ write_byte(0x0040, 0x008e, 0); // clear completion flag
+
+ // basic check : device has to be defined
+ if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
+ BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
+ goto int13_fail;
+ }
+
+ // Get the ata channel
+ device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
+
+ // basic check : device has to be valid
+ if (device >= BX_MAX_ATA_DEVICES) {
+ BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
+ goto int13_fail;
+ }
+
+ switch (GET_AH()) {
+
+ case 0x00: /* disk controller reset */
+ ata_reset (device);
+ goto int13_success;
+ break;
+
+ case 0x01: /* read disk status */
+ status = read_byte(0x0040, 0x0074);
+ SET_AH(status);
+ SET_DISK_RET_STATUS(0);
+ /* set CF if error status read */
+ if (status) goto int13_fail_nostatus;
+ else goto int13_success_noah;
+ break;
+
+ case 0x02: // read disk sectors
+ case 0x03: // write disk sectors
+ case 0x04: // verify disk sectors
+
+ count = GET_AL();
+ cylinder = GET_CH();
+ cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
+ sector = (GET_CL() & 0x3f);
+ head = GET_DH();
+
+ segment = ES;
+ offset = BX;
+
+ if ((count > 128) || (count == 0) || (sector == 0)) {
+ BX_INFO("int13_harddisk: function %02x, parameter out of range!\n",GET_AH());
+ goto int13_fail;
+ }
+
+ nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
+ nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
+ nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
+
+ // sanity check on cyl heads, sec
+ if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
+ BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
+ goto int13_fail;
+ }
+
+ // FIXME verify
+ if ( GET_AH() == 0x04 ) goto int13_success;
+
+ nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
+ npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
+
+ // if needed, translate lchs to lba, and execute command
+ if ( (nph != nlh) || (npspt != nlspt)) {
+ lba_low = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
+ lba_high = 0;
+ sector = 0; // this forces the command to be lba
+ }
+
+ if ( GET_AH() == 0x02 )
+ status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba_low, lba_high, segment, offset);
+ else
+ status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba_low, lba_high, segment, offset);
+
+ // Set nb of sector transferred
+ SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
+
+ if (status != 0) {
+ BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
+ SET_AH(0x0c);
+ goto int13_fail_noah;
+ }
+
+ goto int13_success;
+ break;
+
+ case 0x05: /* format disk track */
+ BX_INFO("format disk track called\n");
+ goto int13_success;
+ return;
+ break;
+
+ case 0x08: /* read disk drive parameters */
+
+ // Get logical geometry from table
+ nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
+ nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
+ nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
+ count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
+
+ nlc = nlc - 2; /* 0 based , last sector not used */
+ SET_AL(0);
+ SET_CH(nlc & 0xff);
+ SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
+ SET_DH(nlh - 1);
+ SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
+
+ // FIXME should set ES & DI
+
+ goto int13_success;
+ break;
+
+ case 0x10: /* check drive ready */
+ // should look at 40:8E also???
+
+ // Read the status from controller
+ status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
+ if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
+ goto int13_success;
+ }
+ else {
+ SET_AH(0xAA);
+ goto int13_fail_noah;
+ }
+ break;
+
+ case 0x15: /* read disk drive size */
+
+ // Get logical geometry from table
+ nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
+ nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
+ nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
+
+ // Compute sector count seen by int13
+ lba_low = (Bit32u)(nlc - 1) * (Bit32u)nlh * (Bit32u)nlspt;
+ CX = lba_low >> 16;
+ DX = lba_low & 0xffff;
+
+ SET_AH(3); // hard disk accessible
+ goto int13_success_noah;
+ break;
+
+ case 0x41: // IBM/MS installation check
+ BX=0xaa55; // install check
+ SET_AH(0x30); // EDD 3.0
+ CX=0x0007; // ext disk access and edd, removable supported
+ goto int13_success_noah;
+ break;
+
+ case 0x42: // IBM/MS extended read
+ case 0x43: // IBM/MS extended write
+ case 0x44: // IBM/MS verify
+ case 0x47: // IBM/MS extended seek
+
+ count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
+ segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
+ offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
+
+ // Get 32 msb lba and check
+ lba_high=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
+ if (lba_high > read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_high) ) {
+ BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
+ goto int13_fail;
+ }
+
+ // Get 32 lsb lba and check
+ lba_low=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
+ if (lba_high == read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_high)
+ && lba_low >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_low) ) {
+ BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
+ goto int13_fail;
+ }
+
+ // If verify or seek
+ if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
+ goto int13_success;
+
+ // Execute the command
+ if ( GET_AH() == 0x42 )
+ status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba_low, lba_high, segment, offset);
+ else
+ status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba_low, lba_high, segment, offset);
+
+ count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
+ write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
+
+ if (status != 0) {
+ BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
+ SET_AH(0x0c);
+ goto int13_fail_noah;
+ }
+
+ goto int13_success;
+ break;
+
+ case 0x45: // IBM/MS lock/unlock drive
+ case 0x49: // IBM/MS extended media change
+ goto int13_success; // Always success for HD
+ break;
+
+ case 0x46: // IBM/MS eject media
+ SET_AH(0xb2); // Volume Not Removable
+ goto int13_fail_noah; // Always fail for HD
+ break;
+
+ case 0x48: // IBM/MS get drive parameters
+ size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
+
+ // Buffer is too small
+ if(size < 0x1a)
+ goto int13_fail;
+
+ // EDD 1.x
+ if(size >= 0x1a) {
+ Bit16u blksize;
+
+ npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
+ nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
+ npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
+ lba_low = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_low);
+ lba_high = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_high);
+ blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
+
+ write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
+ if (lba_high || (lba_low/npspt)/nph > 0x3fff)
+ {
+ write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x00); // geometry is invalid
+ write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0x3fff);
+ }
+ else
+ {
+ write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
+ write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
+ }
+ write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
+ write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
+ write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba_low);
+ write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, lba_high);
+ write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
+ }
+
+ // EDD 2.x
+ if(size >= 0x1e) {
+ Bit8u channel, dev, irq, mode, checksum, i, translation;
+ Bit16u iobase1, iobase2, options;
+
+ write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
+
+ write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
+ write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
+
+ // Fill in dpte
+ channel = device / 2;
+ iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
+ iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
+ irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
+ mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
+ translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
+
+ options = (translation==ATA_TRANSLATION_NONE?0:1)<<3; // chs translation
+ options |= (1<<4); // lba translation
+ options |= (mode==ATA_MODE_PIO32?1:0)<<7;
+ options |= (translation==ATA_TRANSLATION_LBA?1:0)<<9;
+ options |= (translation==ATA_TRANSLATION_RECHS?3:0)<<9;
+
+ write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
+ write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2 + ATA_CB_DC);
+ write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
+ write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
+ write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
+ write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
+ write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
+ write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
+ write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
+ write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
+ if (size >=0x42)
+ write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
+ else
+ write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x10);
+
+ checksum=0;
+ for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, ((Bit8u*)(&EbdaData->ata.dpte)) + i);
+ checksum = ~checksum;
+ write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
+ }
+
+ // EDD 3.x
+ if(size >= 0x42) {
+ Bit8u channel, iface, checksum, i;
+ Bit16u iobase1;
+
+ channel = device / 2;
+ iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
+ iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
+
+ write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
+ write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
+ write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
+ write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
+ write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
+
+ if (iface==ATA_IFACE_ISA) {
+ write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
+ write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
+ write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
+ write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
+ }
+ else {
+ // FIXME PCI
+ }
+ write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
+ write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
+ write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
+ write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
+
+ if (iface==ATA_IFACE_ISA) {
+ write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
+ write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
+ write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
+ }
+ else {
+ // FIXME PCI
+ }
+ write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
+ write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
+ write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
+ write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
+
+ checksum=0;
+ for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
+ checksum = ~checksum;
+ write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
+ }
+
+ goto int13_success;
+ break;
+
+ case 0x4e: // // IBM/MS set hardware configuration
+ // DMA, prefetch, PIO maximum not supported
+ switch (GET_AL()) {
+ case 0x01:
+ case 0x03:
+ case 0x04:
+ case 0x06:
+ goto int13_success;
+ break;
+ default :
+ goto int13_fail;
+ }
+ break;
+
+ case 0x09: /* initialize drive parameters */
+ case 0x0c: /* seek to specified cylinder */
+ case 0x0d: /* alternate disk reset */
+ case 0x11: /* recalibrate */
+ case 0x14: /* controller internal diagnostic */
+ BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
+ goto int13_success;
+ break;
+
+ case 0x0a: /* read disk sectors with ECC */
+ case 0x0b: /* write disk sectors with ECC */
+ case 0x18: // set media type for format
+ case 0x50: // IBM/MS send packet command
+ default:
+ BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
+ goto int13_fail;
+ break;
+ }
+
+int13_fail:
+ SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
+int13_fail_noah:
+ SET_DISK_RET_STATUS(GET_AH());
+int13_fail_nostatus:
+ SET_CF(); // error occurred
+ return;
+
+int13_success:
+ SET_AH(0x00); // no error
+int13_success_noah:
+ SET_DISK_RET_STATUS(0x00);
+ CLEAR_CF(); // no error
+ return;
+}
+
+// ---------------------------------------------------------------------------
+// Start of int13 for cdrom
+// ---------------------------------------------------------------------------
+
+ void
+int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
+ Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
+{
+ Bit16u ebda_seg=read_word(0x0040,0x000E);
+ Bit8u device, status, locks;
+ Bit8u atacmd[12];
+ Bit32u lba;
+ Bit16u count, segment, offset, i, size;
+
+ BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
+
+ SET_DISK_RET_STATUS(0x00);
+
+ /* basic check : device should be 0xE0+ */
+ if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
+ BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
+ goto int13_fail;
+ }
+
+ // Get the ata channel
+ device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
+
+ /* basic check : device has to be valid */
+ if (device >= BX_MAX_ATA_DEVICES) {
+ BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
+ goto int13_fail;
+ }
+
+ switch (GET_AH()) {
+
+ // all those functions return SUCCESS
+ case 0x00: /* disk controller reset */
+ case 0x09: /* initialize drive parameters */
+ case 0x0c: /* seek to specified cylinder */
+ case 0x0d: /* alternate disk reset */
+ case 0x10: /* check drive ready */
+ case 0x11: /* recalibrate */
+ case 0x14: /* controller internal diagnostic */
+ case 0x16: /* detect disk change */
+ goto int13_success;
+ break;
+
+ // all those functions return disk write-protected
+ case 0x03: /* write disk sectors */
+ case 0x05: /* format disk track */
+ case 0x43: // IBM/MS extended write
+ SET_AH(0x03);
+ goto int13_fail_noah;
+ break;
+
+ case 0x01: /* read disk status */
+ status = read_byte(0x0040, 0x0074);
+ SET_AH(status);
+ SET_DISK_RET_STATUS(0);
+
+ /* set CF if error status read */
+ if (status) goto int13_fail_nostatus;
+ else goto int13_success_noah;
+ break;
+
+ case 0x15: /* read disk drive size */
+ SET_AH(0x02);
+ goto int13_fail_noah;
+ break;
+
+ case 0x41: // IBM/MS installation check
+ BX=0xaa55; // install check
+ SET_AH(0x30); // EDD 2.1
+ CX=0x0007; // ext disk access, removable and edd
+ goto int13_success_noah;
+ break;
+
+ case 0x42: // IBM/MS extended read
+ case 0x44: // IBM/MS verify sectors
+ case 0x47: // IBM/MS extended seek
+
+ count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
+ segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
+ offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
+
+ // Can't use 64 bits lba
+ lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
+ if (lba != 0L) {
+ BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
+ goto int13_fail;
+ }
+
+ // Get 32 bits lba
+ lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
+
+ // If verify or seek
+ if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
+ goto int13_success;
+
+ memsetb(get_SS(),atacmd,0,12);
+ atacmd[0]=0x28; // READ command
+ atacmd[7]=(count & 0xff00) >> 8; // Sectors
+ atacmd[8]=(count & 0x00ff); // Sectors
+ atacmd[2]=(lba & 0xff000000) >> 24; // LBA
+ atacmd[3]=(lba & 0x00ff0000) >> 16;
+ atacmd[4]=(lba & 0x0000ff00) >> 8;
+ atacmd[5]=(lba & 0x000000ff);
+ status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
+
+ count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
+ write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
+
+ if (status != 0) {
+ BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
+ SET_AH(0x0c);
+ goto int13_fail_noah;
+ }
+
+ goto int13_success;
+ break;
+
+ case 0x45: // IBM/MS lock/unlock drive
+ if (GET_AL() > 2) goto int13_fail;
+
+ locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
+
+ switch (GET_AL()) {
+ case 0 : // lock
+ if (locks == 0xff) {
+ SET_AH(0xb4);
+ SET_AL(1);
+ goto int13_fail_noah;
+ }
+ write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
+ SET_AL(1);
+ break;
+ case 1 : // unlock
+ if (locks == 0x00) {
+ SET_AH(0xb0);
+ SET_AL(0);
+ goto int13_fail_noah;
+ }
+ write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
+ SET_AL(locks==0?0:1);
+ break;
+ case 2 : // status
+ SET_AL(locks==0?0:1);
+ break;
+ }
+ goto int13_success;
+ break;
+
+ case 0x46: // IBM/MS eject media
+ locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
+
+ if (locks != 0) {
+ SET_AH(0xb1); // media locked
+ goto int13_fail_noah;
+ }
+ // FIXME should handle 0x31 no media in device
+ // FIXME should handle 0xb5 valid request failed
+
+ // Call removable media eject
+ ASM_START
+ push bp
+ mov bp, sp
+
+ mov ah, #0x52
+ int #0x15
+ mov _int13_cdrom.status + 2[bp], ah
+ jnc int13_cdrom_rme_end
+ mov _int13_cdrom.status, #1
+int13_cdrom_rme_end:
+ pop bp
+ ASM_END
+
+ if (status != 0) {
+ SET_AH(0xb1); // media locked
+ goto int13_fail_noah;
+ }
+
+ goto int13_success;
+ break;
+
+ case 0x48: // IBM/MS get drive parameters
+ size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
+
+ // Buffer is too small
+ if(size < 0x1a)
+ goto int13_fail;
+
+ // EDD 1.x
+ if(size >= 0x1a) {
+ Bit16u cylinders, heads, spt, blksize;
+
+ blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
+
+ write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
+ write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
+ write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
+ write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
+ write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
+ write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
+ write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
+ write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
+ }
+
+ // EDD 2.x
+ if(size >= 0x1e) {
+ Bit8u channel, dev, irq, mode, checksum, i;
+ Bit16u iobase1, iobase2, options;
+
+ write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
+
+ write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
+ write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
+
+ // Fill in dpte
+ channel = device / 2;
+ iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
+ iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
+ irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
+ mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
+
+ // FIXME atapi device
+ options = (1<<4); // lba translation
+ options |= (1<<5); // removable device
+ options |= (1<<6); // atapi device
+ options |= (mode==ATA_MODE_PIO32?1:0<<7);
+
+ write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
+ write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2 + ATA_CB_DC);
+ write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
+ write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
+ write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
+ write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
+ write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
+ write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
+ write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
+ write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
+ write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
+
+ checksum=0;
+ for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, ((Bit8u*)(&EbdaData->ata.dpte)) + i);
+ checksum = ~checksum;
+ write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
+ }
+
+ // EDD 3.x
+ if(size >= 0x42) {
+ Bit8u channel, iface, checksum, i;
+ Bit16u iobase1;
+
+ channel = device / 2;
+ iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
+ iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
+
+ write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
+ write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
+ write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
+ write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
+ write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
+
+ if (iface==ATA_IFACE_ISA) {
+ write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
+ write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
+ write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
+ write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
+ }
+ else {
+ // FIXME PCI
+ }
+ write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
+ write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
+ write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
+ write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
+
+ if (iface==ATA_IFACE_ISA) {
+ write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
+ write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
+ write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
+ }
+ else {
+ // FIXME PCI
+ }
+ write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
+ write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
+ write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
+ write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
+
+ checksum=0;
+ for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
+ checksum = ~checksum;
+ write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
+ }
+
+ goto int13_success;
+ break;
+
+ case 0x49: // IBM/MS extended media change
+ // always send changed ??
+ SET_AH(06);
+ goto int13_fail_nostatus;
+ break;
+
+ case 0x4e: // // IBM/MS set hardware configuration
+ // DMA, prefetch, PIO maximum not supported
+ switch (GET_AL()) {
+ case 0x01:
+ case 0x03:
+ case 0x04:
+ case 0x06:
+ goto int13_success;
+ break;
+ default :
+ goto int13_fail;
+ }
+ break;
+
+ // all those functions return unimplemented
+ case 0x02: /* read sectors */
+ case 0x04: /* verify sectors */
+ case 0x08: /* read disk drive parameters */
+ case 0x0a: /* read disk sectors with ECC */
+ case 0x0b: /* write disk sectors with ECC */
+ case 0x18: /* set media type for format */
+ case 0x50: // ? - send packet command
+ default:
+ BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
+ goto int13_fail;
+ break;
+ }
+
+int13_fail:
+ SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
+int13_fail_noah:
+ SET_DISK_RET_STATUS(GET_AH());
+int13_fail_nostatus:
+ SET_CF(); // error occurred
+ return;
+
+int13_success:
+ SET_AH(0x00); // no error
+int13_success_noah:
+ SET_DISK_RET_STATUS(0x00);
+ CLEAR_CF(); // no error
+ return;
+}
+
+// ---------------------------------------------------------------------------
+// End of int13 for cdrom
+// ---------------------------------------------------------------------------
+
+#if BX_ELTORITO_BOOT
+// ---------------------------------------------------------------------------
+// Start of int13 for eltorito functions
+// ---------------------------------------------------------------------------
+
+ void
+int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
+ Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
+{
+ Bit16u ebda_seg=read_word(0x0040,0x000E);
+
+ BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
+ // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
+
+ switch (GET_AH()) {
+
+ // FIXME ElTorito Various. Should be implemented
+ case 0x4a: // ElTorito - Initiate disk emu
+ case 0x4c: // ElTorito - Initiate disk emu and boot
+ case 0x4d: // ElTorito - Return Boot catalog
+ BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
+ goto int13_fail;
+ break;
+
+ case 0x4b: // ElTorito - Terminate disk emu
+ // FIXME ElTorito Hardcoded
+ write_byte(DS,SI+0x00,0x13);
+ write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
+ write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
+ write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
+ write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
+ write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
+ write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
+ write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
+ write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
+ write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
+ write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
+ write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
+
+ // If we have to terminate emulation
+ if(GET_AL() == 0x00) {
+ // FIXME ElTorito Various. Should be handled accordingly to spec
+ write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
+ }
+
+ goto int13_success;
+ break;
+
+ default:
+ BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
+ goto int13_fail;
+ break;
+ }
+
+int13_fail:
+ SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
+ SET_DISK_RET_STATUS(GET_AH());
+ SET_CF(); // error occurred
+ return;
+
+int13_success:
+ SET_AH(0x00); // no error
+ SET_DISK_RET_STATUS(0x00);
+ CLEAR_CF(); // no error
+ return;
+}
+
+// ---------------------------------------------------------------------------
+// End of int13 for eltorito functions
+// ---------------------------------------------------------------------------
+
+// ---------------------------------------------------------------------------
+// Start of int13 when emulating a device from the cd
+// ---------------------------------------------------------------------------
+
+ void
+int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
+ Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
+{
+ Bit16u ebda_seg=read_word(0x0040,0x000E);
+ Bit8u device, status;
+ Bit16u vheads, vspt, vcylinders;
+ Bit16u head, sector, cylinder, nbsectors;
+ Bit32u vlba, ilba, slba, elba;
+ Bit16u before, segment, offset;
+ Bit8u atacmd[12];
+
+ BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
+
+ /* at this point, we are emulating a floppy/harddisk */
+
+ // Recompute the device number
+ device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
+ device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
+
+ SET_DISK_RET_STATUS(0x00);
+
+ /* basic checks : emulation should be active, dl should equal the emulated drive */
+ if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
+ || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
+ BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
+ goto int13_fail;
+ }
+
+ switch (GET_AH()) {
+
+ // all those functions return SUCCESS
+ case 0x00: /* disk controller reset */
+ case 0x09: /* initialize drive parameters */
+ case 0x0c: /* seek to specified cylinder */
+ case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
+ case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
+ case 0x11: /* recalibrate */
+ case 0x14: /* controller internal diagnostic */
+ case 0x16: /* detect disk change */
+ goto int13_success;
+ break;
+
+ // all those functions return disk write-protected
+ case 0x03: /* write disk sectors */
+ case 0x05: /* format disk track */
+ SET_AH(0x03);
+ goto int13_fail_noah;
+ break;
+
+ case 0x01: /* read disk status */
+ status=read_byte(0x0040, 0x0074);
+ SET_AH(status);
+ SET_DISK_RET_STATUS(0);
+
+ /* set CF if error status read */
+ if (status) goto int13_fail_nostatus;
+ else goto int13_success_noah;
+ break;
+
+ case 0x02: // read disk sectors
+ case 0x04: // verify disk sectors
+ vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
+ vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
+ vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
+
+ ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
+
+ sector = GET_CL() & 0x003f;
+ cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
+ head = GET_DH();
+ nbsectors = GET_AL();
+ segment = ES;
+ offset = BX;
+
+ // no sector to read ?
+ if(nbsectors==0) goto int13_success;
+
+ // sanity checks sco openserver needs this!
+ if ((sector > vspt)
+ || (cylinder >= vcylinders)
+ || (head >= vheads)) {
+ goto int13_fail;
+ }
+
+ // After controls, verify do nothing
+ if (GET_AH() == 0x04) goto int13_success;
+
+ segment = ES+(BX / 16);
+ offset = BX % 16;
+
+ // calculate the virtual lba inside the image
+ vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
+
+ // In advance so we don't loose the count
+ SET_AL(nbsectors);
+
+ // start lba on cd
+ slba = (Bit32u)vlba/4;
+ before= (Bit16u)vlba%4;
+
+ // end lba on cd
+ elba = (Bit32u)(vlba+nbsectors-1)/4;
+
+ memsetb(get_SS(),atacmd,0,12);
+ atacmd[0]=0x28; // READ command
+ atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
+ atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
+ atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
+ atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
+ atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
+ atacmd[5]=(ilba+slba & 0x000000ff);
+ if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
+ BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
+ SET_AH(0x02);
+ SET_AL(0);
+ goto int13_fail_noah;
+ }
+
+ goto int13_success;
+ break;
+
+ case 0x08: /* read disk drive parameters */
+ vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
+ vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
+ vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
+
+ SET_AL( 0x00 );
+ SET_BL( 0x00 );
+ SET_CH( vcylinders & 0xff );
+ SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
+ SET_DH( vheads );
+ SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
+ // FIXME ElTorito Harddisk. should send the HD count
+
+ switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
+ case 0x01: SET_BL( 0x02 ); break;
+ case 0x02: SET_BL( 0x04 ); break;
+ case 0x03: SET_BL( 0x06 ); break;
+ }
+
+ASM_START
+ push bp
+ mov bp, sp
+ mov ax, #diskette_param_table2
+ mov _int13_cdemu.DI+2[bp], ax
+ mov _int13_cdemu.ES+2[bp], cs
+ pop bp
+ASM_END
+ goto int13_success;
+ break;
+
+ case 0x15: /* read disk drive size */
+ // FIXME ElTorito Harddisk. What geometry to send ?
+ SET_AH(0x03);
+ goto int13_success_noah;
+ break;
+
+ // all those functions return unimplemented
+ case 0x0a: /* read disk sectors with ECC */
+ case 0x0b: /* write disk sectors with ECC */
+ case 0x18: /* set media type for format */
+ case 0x41: // IBM/MS installation check
+ // FIXME ElTorito Harddisk. Darwin would like to use EDD
+ case 0x42: // IBM/MS extended read
+ case 0x43: // IBM/MS extended write
+ case 0x44: // IBM/MS verify sectors
+ case 0x45: // IBM/MS lock/unlock drive
+ case 0x46: // IBM/MS eject media
+ case 0x47: // IBM/MS extended seek
+ case 0x48: // IBM/MS get drive parameters
+ case 0x49: // IBM/MS extended media change
+ case 0x4e: // ? - set hardware configuration
+ case 0x50: // ? - send packet command
+ default:
+ BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
+ goto int13_fail;
+ break;
+ }
+
+int13_fail:
+ SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
+int13_fail_noah:
+ SET_DISK_RET_STATUS(GET_AH());
+int13_fail_nostatus:
+ SET_CF(); // error occurred
+ return;
+
+int13_success:
+ SET_AH(0x00); // no error
+int13_success_noah:
+ SET_DISK_RET_STATUS(0x00);
+ CLEAR_CF(); // no error
+ return;
+}
+
+// ---------------------------------------------------------------------------
+// End of int13 when emulating a device from the cd
+// ---------------------------------------------------------------------------
+
+#endif // BX_ELTORITO_BOOT
+
+#else //BX_USE_ATADRV
+
+ void
+outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
+ Bit16u cylinder;
+ Bit16u hd_heads;
+ Bit16u head;
+ Bit16u hd_sectors;
+ Bit16u sector;
+ Bit16u dl;
+{
+ASM_START
+ push bp
+ mov bp, sp
+ push eax
+ push ebx
+ push edx
+ xor eax,eax
+ mov ax,4[bp] // cylinder
+ xor ebx,ebx
+ mov bl,6[bp] // hd_heads
+ imul ebx
+
+ mov bl,8[bp] // head
+ add eax,ebx
+ mov bl,10[bp] // hd_sectors
+ imul ebx
+ mov bl,12[bp] // sector
+ add eax,ebx
+
+ dec eax
+ mov dx,#0x1f3
+ out dx,al
+ mov dx,#0x1f4
+ mov al,ah
+ out dx,al
+ shr eax,#16
+ mov dx,#0x1f5
+ out dx,al
+ and ah,#0xf
+ mov bl,14[bp] // dl
+ and bl,#1
+ shl bl,#4
+ or ah,bl
+ or ah,#0xe0
+ mov al,ah
+ mov dx,#0x01f6
+ out dx,al
+ pop edx
+ pop ebx
+ pop eax
+ pop bp
+ASM_END
+}
+
+ void
+int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
+ Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
+{
+ Bit8u drive, num_sectors, sector, head, status, mod;
+ Bit8u drive_map;
+ Bit8u n_drives;
+ Bit16u cyl_mod, ax;
+ Bit16u max_cylinder, cylinder, total_sectors;
+ Bit16u hd_cylinders;
+ Bit8u hd_heads, hd_sectors;
+ Bit16u val16;
+ Bit8u sector_count;
+ unsigned int i;
+ Bit16u tempbx;
+ Bit16u dpsize;
+
+ Bit16u count, segment, offset;
+ Bit32u lba;
+ Bit16u error;
+
+ BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
+
+ write_byte(0x0040, 0x008e, 0); // clear completion flag
+
+ /* at this point, DL is >= 0x80 to be passed from the floppy int13h
+ handler code */
+ /* check how many disks first (cmos reg 0x12), return an error if
+ drive not present */
+ drive_map = inb_cmos(0x12);
+ drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
+ (((drive_map & 0x0f)==0) ? 0 : 2);
+ n_drives = (drive_map==0) ? 0 :
+ ((drive_map==3) ? 2 : 1);
+
+ if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
+ SET_AH(0x01);
+ SET_DISK_RET_STATUS(0x01);
+ SET_CF(); /* error occurred */
+ return;
+ }
+
+ switch (GET_AH()) {
+
+ case 0x00: /* disk controller reset */
+BX_DEBUG_INT13_HD("int13_f00\n");
+
+ SET_AH(0);
+ SET_DISK_RET_STATUS(0);
+ set_diskette_ret_status(0);
+ set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
+ set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
+ CLEAR_CF(); /* successful */
+ return;
+ break;
+
+ case 0x01: /* read disk status */
+BX_DEBUG_INT13_HD("int13_f01\n");
+ status = read_byte(0x0040, 0x0074);
+ SET_AH(status);
+ SET_DISK_RET_STATUS(0);
+ /* set CF if error status read */
+ if (status) SET_CF();
+ else CLEAR_CF();
+ return;
+ break;
+
+ case 0x04: // verify disk sectors
+ case 0x02: // read disk sectors
+ drive = GET_ELDL();
+ get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
+
+ num_sectors = GET_AL();
+ cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
+ sector = (GET_CL() & 0x3f);
+ head = GET_DH();
+
+
+ if (hd_cylinders > 1024) {
+ if (hd_cylinders <= 2048) {
+ cylinder <<= 1;
+ }
+ else if (hd_cylinders <= 4096) {
+ cylinder <<= 2;
+ }
+ else if (hd_cylinders <= 8192) {
+ cylinder <<= 3;
+ }
+ else { // hd_cylinders <= 16384
+ cylinder <<= 4;
+ }
+
+ ax = head / hd_heads;
+ cyl_mod = ax & 0xff;
+ head = ax >> 8;
+ cylinder |= cyl_mod;
+ }
+
+ if ( (cylinder >= hd_cylinders) ||
+ (sector > hd_sectors) ||
+ (head >= hd_heads) ) {
+ SET_AH(1);
+ SET_DISK_RET_STATUS(1);
+ SET_CF(); /* error occurred */
+ return;
+ }
+
+ if ( (num_sectors > 128) || (num_sectors == 0) )
+ BX_PANIC("int13_harddisk: num_sectors out of range!\n");
+
+ if (head > 15)
+ BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
+
+ if ( GET_AH() == 0x04 ) {
+ SET_AH(0);
+ SET_DISK_RET_STATUS(0);
+ CLEAR_CF();
+ return;
+ }
+
+ status = inb(0x1f7);
+ if (status & 0x80) {
+ BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
+ }
+ outb(0x01f2, num_sectors);
+ /* activate LBA? (tomv) */
+ if (hd_heads > 16) {
+BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
+ outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
+ }
+ else {
+ outb(0x01f3, sector);
+ outb(0x01f4, cylinder & 0x00ff);
+ outb(0x01f5, cylinder >> 8);
+ outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
+ }
+ outb(0x01f7, 0x20);
+
+ while (1) {
+ status = inb(0x1f7);
+ if ( !(status & 0x80) ) break;
+ }
+
+ if (status & 0x01) {
+ BX_PANIC("hard drive BIOS:(read/verify) read error\n");
+ } else if ( !(status & 0x08) ) {
+ BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
+ BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
+ }
+
+ sector_count = 0;
+ tempbx = BX;
+
+ASM_START
+ sti ;; enable higher priority interrupts
+ASM_END
+
+ while (1) {
+ASM_START
+ ;; store temp bx in real DI register
+ push bp
+ mov bp, sp
+ mov di, _int13_harddisk.tempbx + 2 [bp]
+ pop bp
+
+ ;; adjust if there will be an overrun
+ cmp di, #0xfe00
+ jbe i13_f02_no_adjust
+i13_f02_adjust:
+ sub di, #0x0200 ; sub 512 bytes from offset
+ mov ax, es
+ add ax, #0x0020 ; add 512 to segment
+ mov es, ax
+
+i13_f02_no_adjust:
+ mov cx, #0x0100 ;; counter (256 words = 512b)
+ mov dx, #0x01f0 ;; AT data read port
+
+ rep
+ insw ;; CX words transfered from port(DX) to ES:[DI]
+
+i13_f02_done:
+ ;; store real DI register back to temp bx
+ push bp
+ mov bp, sp
+ mov _int13_harddisk.tempbx + 2 [bp], di
+ pop bp
+ASM_END
+
+ sector_count++;
+ num_sectors--;
+ if (num_sectors == 0) {
+ status = inb(0x1f7);
+ if ( (status & 0xc9) != 0x40 )
+ BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
+ break;
+ }
+ else {
+ status = inb(0x1f7);
+ if ( (status & 0xc9) != 0x48 )
+ BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
+ continue;
+ }
+ }
+
+ SET_AH(0);
+ SET_DISK_RET_STATUS(0);
+ SET_AL(sector_count);
+ CLEAR_CF(); /* successful */
+ return;
+ break;
+
+
+ case 0x03: /* write disk sectors */
+BX_DEBUG_INT13_HD("int13_f03\n");
+ drive = GET_ELDL ();
+ get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
+
+ num_sectors = GET_AL();
+ cylinder = GET_CH();
+ cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
+ sector = (GET_CL() & 0x3f);
+ head = GET_DH();
+
+ if (hd_cylinders > 1024) {
+ if (hd_cylinders <= 2048) {
+ cylinder <<= 1;
+ }
+ else if (hd_cylinders <= 4096) {
+ cylinder <<= 2;
+ }
+ else if (hd_cylinders <= 8192) {
+ cylinder <<= 3;
+ }
+ else { // hd_cylinders <= 16384
+ cylinder <<= 4;
+ }
+
+ ax = head / hd_heads;
+ cyl_mod = ax & 0xff;
+ head = ax >> 8;
+ cylinder |= cyl_mod;
+ }
+
+ if ( (cylinder >= hd_cylinders) ||
+ (sector > hd_sectors) ||
+ (head >= hd_heads) ) {
+ SET_AH( 1);
+ SET_DISK_RET_STATUS(1);
+ SET_CF(); /* error occurred */
+ return;
+ }
+
+ if ( (num_sectors > 128) || (num_sectors == 0) )
+ BX_PANIC("int13_harddisk: num_sectors out of range!\n");
+
+ if (head > 15)
+ BX_PANIC("hard drive BIOS:(read) head > 15\n");
+
+ status = inb(0x1f7);
+ if (status & 0x80) {
+ BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
+ }
+// should check for Drive Ready Bit also in status reg
+ outb(0x01f2, num_sectors);
+
+ /* activate LBA? (tomv) */
+ if (hd_heads > 16) {
+BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
+ outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
+ }
+ else {
+ outb(0x01f3, sector);
+ outb(0x01f4, cylinder & 0x00ff);
+ outb(0x01f5, cylinder >> 8);
+ outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
+ }
+ outb(0x01f7, 0x30);
+
+ // wait for busy bit to turn off after seeking
+ while (1) {
+ status = inb(0x1f7);
+ if ( !(status & 0x80) ) break;
+ }
+
+ if ( !(status & 0x08) ) {
+ BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
+ BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
+ }
+
+ sector_count = 0;
+ tempbx = BX;
+
+ASM_START
+ sti ;; enable higher priority interrupts
+ASM_END
+
+ while (1) {
+ASM_START
+ ;; store temp bx in real SI register
+ push bp
+ mov bp, sp
+ mov si, _int13_harddisk.tempbx + 2 [bp]
+ pop bp
+
+ ;; adjust if there will be an overrun
+ cmp si, #0xfe00
+ jbe i13_f03_no_adjust
+i13_f03_adjust:
+ sub si, #0x0200 ; sub 512 bytes from offset
+ mov ax, es
+ add ax, #0x0020 ; add 512 to segment
+ mov es, ax
+
+i13_f03_no_adjust:
+ mov cx, #0x0100 ;; counter (256 words = 512b)
+ mov dx, #0x01f0 ;; AT data read port
+
+ seg ES
+ rep
+ outsw ;; CX words tranfered from ES:[SI] to port(DX)
+
+ ;; store real SI register back to temp bx
+ push bp
+ mov bp, sp
+ mov _int13_harddisk.tempbx + 2 [bp], si
+ pop bp
+ASM_END
+
+ sector_count++;
+ num_sectors--;
+ if (num_sectors == 0) {
+ status = inb(0x1f7);
+ if ( (status & 0xe9) != 0x40 )
+ BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
+ break;
+ }
+ else {
+ status = inb(0x1f7);
+ if ( (status & 0xc9) != 0x48 )
+ BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
+ continue;
+ }
+ }
+
+ SET_AH(0);
+ SET_DISK_RET_STATUS(0);
+ SET_AL(sector_count);
+ CLEAR_CF(); /* successful */
+ return;
+ break;
+
+ case 0x05: /* format disk track */
+BX_DEBUG_INT13_HD("int13_f05\n");
+ BX_PANIC("format disk track called\n");
+ /* nop */
+ SET_AH(0);
+ SET_DISK_RET_STATUS(0);
+ CLEAR_CF(); /* successful */
+ return;
+ break;
+
+ case 0x08: /* read disk drive parameters */
+BX_DEBUG_INT13_HD("int13_f08\n");
+
+ drive = GET_ELDL ();
+ get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
+
+ // translate CHS
+ //
+ if (hd_cylinders <= 1024) {
+ // hd_cylinders >>= 0;
+ // hd_heads <<= 0;
+ }
+ else if (hd_cylinders <= 2048) {
+ hd_cylinders >>= 1;
+ hd_heads <<= 1;
+ }
+ else if (hd_cylinders <= 4096) {
+ hd_cylinders >>= 2;
+ hd_heads <<= 2;
+ }
+ else if (hd_cylinders <= 8192) {
+ hd_cylinders >>= 3;
+ hd_heads <<= 3;
+ }
+ else { // hd_cylinders <= 16384
+ hd_cylinders >>= 4;
+ hd_heads <<= 4;
+ }
+
+ max_cylinder = hd_cylinders - 2; /* 0 based */
+ SET_AL(0);
+ SET_CH(max_cylinder & 0xff);
+ SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
+ SET_DH(hd_heads - 1);
+ SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
+ SET_AH(0);
+ SET_DISK_RET_STATUS(0);
+ CLEAR_CF(); /* successful */
+
+ return;
+ break;
+
+ case 0x09: /* initialize drive parameters */
+BX_DEBUG_INT13_HD("int13_f09\n");
+ SET_AH(0);
+ SET_DISK_RET_STATUS(0);
+ CLEAR_CF(); /* successful */
+ return;
+ break;
+
+ case 0x0a: /* read disk sectors with ECC */
+BX_DEBUG_INT13_HD("int13_f0a\n");
+ case 0x0b: /* write disk sectors with ECC */
+BX_DEBUG_INT13_HD("int13_f0b\n");
+ BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
+ return;
+ break;
+
+ case 0x0c: /* seek to specified cylinder */
+BX_DEBUG_INT13_HD("int13_f0c\n");
+ BX_INFO("int13h function 0ch (seek) not implemented!\n");
+ SET_AH(0);
+ SET_DISK_RET_STATUS(0);
+ CLEAR_CF(); /* successful */
+ return;
+ break;
+
+ case 0x0d: /* alternate disk reset */
+BX_DEBUG_INT13_HD("int13_f0d\n");
+ SET_AH(0);
+ SET_DISK_RET_STATUS(0);
+ CLEAR_CF(); /* successful */
+ return;
+ break;
+
+ case 0x10: /* check drive ready */
+BX_DEBUG_INT13_HD("int13_f10\n");
+ //SET_AH(0);
+ //SET_DISK_RET_STATUS(0);
+ //CLEAR_CF(); /* successful */
+ //return;
+ //break;
+
+ // should look at 40:8E also???
+ status = inb(0x01f7);
+ if ( (status & 0xc0) == 0x40 ) {
+ SET_AH(0);
+ SET_DISK_RET_STATUS(0);
+ CLEAR_CF(); // drive ready
+ return;
+ }
+ else {
+ SET_AH(0xAA);
+ SET_DISK_RET_STATUS(0xAA);
+ SET_CF(); // not ready
+ return;
+ }
+ break;
+
+ case 0x11: /* recalibrate */
+BX_DEBUG_INT13_HD("int13_f11\n");
+ SET_AH(0);
+ SET_DISK_RET_STATUS(0);
+ CLEAR_CF(); /* successful */
+ return;
+ break;
+
+ case 0x14: /* controller internal diagnostic */
+BX_DEBUG_INT13_HD("int13_f14\n");
+ SET_AH(0);
+ SET_DISK_RET_STATUS(0);
+ CLEAR_CF(); /* successful */
+ SET_AL(0);
+ return;
+ break;
+
+ case 0x15: /* read disk drive size */
+ drive = GET_ELDL();
+ get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
+ASM_START
+ push bp
+ mov bp, sp
+ mov al, _int13_harddisk.hd_heads + 2 [bp]
+ mov ah, _int13_harddisk.hd_sectors + 2 [bp]
+ mul al, ah ;; ax = heads * sectors
+ mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
+ dec bx ;; use (cylinders - 1) ???
+ mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
+ ;; now we need to move the 32bit result dx:ax to what the
+ ;; BIOS wants which is cx:dx.
+ ;; and then into CX:DX on the stack
+ mov _int13_harddisk.CX + 2 [bp], dx
+ mov _int13_harddisk.DX + 2 [bp], ax
+ pop bp
+ASM_END
+ SET_AH(3); // hard disk accessible
+ SET_DISK_RET_STATUS(0); // ??? should this be 0
+ CLEAR_CF(); // successful
+ return;
+ break;
+
+ case 0x18: // set media type for format
+ case 0x41: // IBM/MS
+ case 0x42: // IBM/MS
+ case 0x43: // IBM/MS
+ case 0x44: // IBM/MS
+ case 0x45: // IBM/MS lock/unlock drive
+ case 0x46: // IBM/MS eject media
+ case 0x47: // IBM/MS extended seek
+ case 0x49: // IBM/MS extended media change
+ case 0x50: // IBM/MS send packet command
+ default:
+ BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
+
+ SET_AH(1); // code=invalid function in AH or invalid parameter
+ SET_DISK_RET_STATUS(1);
+ SET_CF(); /* unsuccessful */
+ return;
+ break;
+ }
+}
+
+static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
+static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
+
+ void
+get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
+ Bit8u drive;
+ Bit16u *hd_cylinders;
+ Bit8u *hd_heads;
+ Bit8u *hd_sectors;
+{
+ Bit8u hd_type;
+ Bit16u ss;
+ Bit16u cylinders;
+ Bit8u iobase;
+
+ ss = get_SS();
+ if (drive == 0x80) {
+ hd_type = inb_cmos(0x12) & 0xf0;
+ if (hd_type != 0xf0)
+ BX_INFO(panic_msg_reg12h,0);
+ hd_type = inb_cmos(0x19); // HD0: extended type
+ if (hd_type != 47)
+ BX_INFO(panic_msg_reg19h,0,0x19);
+ iobase = 0x1b;
+ } else {
+ hd_type = inb_cmos(0x12) & 0x0f;
+ if (hd_type != 0x0f)
+ BX_INFO(panic_msg_reg12h,1);
+ hd_type = inb_cmos(0x1a); // HD1: extended type
+ if (hd_type != 47)
+ BX_INFO(panic_msg_reg19h,0,0x1a);
+ iobase = 0x24;
+ }
+
+ // cylinders
+ cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
+ write_word(ss, hd_cylinders, cylinders);
+
+ // heads
+ write_byte(ss, hd_heads, inb_cmos(iobase+2));
+
+ // sectors per track
+ write_byte(ss, hd_sectors, inb_cmos(iobase+8));
+}
+
+#endif //else BX_USE_ATADRV
+
+#if BX_SUPPORT_FLOPPY
+
+//////////////////////
+// FLOPPY functions //
+//////////////////////
+
+void floppy_reset_controller()
+{
+ Bit8u val8;
+
+ // Reset controller
+ val8 = inb(0x03f2);
+ outb(0x03f2, val8 & ~0x04);
+ outb(0x03f2, val8 | 0x04);
+
+ // Wait for controller to come out of reset
+ do {
+ val8 = inb(0x3f4);
+ } while ( (val8 & 0xc0) != 0x80 );
+}
+
+void floppy_prepare_controller(drive)
+ Bit16u drive;
+{
+ Bit8u val8, dor, prev_reset;
+
+ // set 40:3e bit 7 to 0
+ val8 = read_byte(0x0040, 0x003e);
+ val8 &= 0x7f;
+ write_byte(0x0040, 0x003e, val8);
+
+ // turn on motor of selected drive, DMA & int enabled, normal operation
+ prev_reset = inb(0x03f2) & 0x04;
+ if (drive)
+ dor = 0x20;
+ else
+ dor = 0x10;
+ dor |= 0x0c;
+ dor |= drive;
+ outb(0x03f2, dor);
+
+ // reset the disk motor timeout value of INT 08
+ write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
+
+ // wait for drive readiness
+ do {
+ val8 = inb(0x3f4);
+ } while ( (val8 & 0xc0) != 0x80 );
+
+ if (prev_reset == 0) {
+ // turn on interrupts
+ASM_START
+ sti
+ASM_END
+ // wait on 40:3e bit 7 to become 1
+ do {
+ val8 = read_byte(0x0040, 0x003e);
+ } while ( (val8 & 0x80) == 0 );
+ val8 &= 0x7f;
+ASM_START
+ cli
+ASM_END
+ write_byte(0x0040, 0x003e, val8);
+ }
+}
+
+ bx_bool
+floppy_media_known(drive)
+ Bit16u drive;
+{
+ Bit8u val8;
+ Bit16u media_state_offset;
+
+ val8 = read_byte(0x0040, 0x003e); // diskette recal status
+ if (drive)
+ val8 >>= 1;
+ val8 &= 0x01;
+ if (val8 == 0)
+ return(0);
+
+ media_state_offset = 0x0090;
+ if (drive)
+ media_state_offset += 1;
+
+ val8 = read_byte(0x0040, media_state_offset);
+ val8 = (val8 >> 4) & 0x01;
+ if (val8 == 0)
+ return(0);
+
+ // check pass, return KNOWN
+ return(1);
+}
+
+ bx_bool
+floppy_media_sense(drive)
+ Bit16u drive;
+{
+ bx_bool retval;
+ Bit16u media_state_offset;
+ Bit8u drive_type, config_data, media_state;
+
+ if (floppy_drive_recal(drive) == 0) {
+ return(0);
+ }
+
+ // for now cheat and get drive type from CMOS,
+ // assume media is same as drive type
+
+ // ** config_data **
+ // Bitfields for diskette media control:
+ // Bit(s) Description (Table M0028)
+ // 7-6 last data rate set by controller
+ // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
+ // 5-4 last diskette drive step rate selected
+ // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
+ // 3-2 {data rate at start of operation}
+ // 1-0 reserved
+
+ // ** media_state **
+ // Bitfields for diskette drive media state:
+ // Bit(s) Description (Table M0030)
+ // 7-6 data rate
+ // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
+ // 5 double stepping required (e.g. 360kB in 1.2MB)
+ // 4 media type established
+ // 3 drive capable of supporting 4MB media
+ // 2-0 on exit from BIOS, contains
+ // 000 trying 360kB in 360kB
+ // 001 trying 360kB in 1.2MB
+ // 010 trying 1.2MB in 1.2MB
+ // 011 360kB in 360kB established
+ // 100 360kB in 1.2MB established
+ // 101 1.2MB in 1.2MB established
+ // 110 reserved
+ // 111 all other formats/drives
+
+ drive_type = inb_cmos(0x10);
+ if (drive == 0)
+ drive_type >>= 4;
+ else
+ drive_type &= 0x0f;
+ if ( drive_type == 1 ) {
+ // 360K 5.25" drive
+ config_data = 0x00; // 0000 0000
+ media_state = 0x25; // 0010 0101
+ retval = 1;
+ }
+ else if ( drive_type == 2 ) {
+ // 1.2 MB 5.25" drive
+ config_data = 0x00; // 0000 0000
+ media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
+ retval = 1;
+ }
+ else if ( drive_type == 3 ) {
+ // 720K 3.5" drive
+ config_data = 0x00; // 0000 0000 ???
+ media_state = 0x17; // 0001 0111
+ retval = 1;
+ }
+ else if ( drive_type == 4 ) {
+ // 1.44 MB 3.5" drive
+ config_data = 0x00; // 0000 0000
+ media_state = 0x17; // 0001 0111
+ retval = 1;
+ }
+ else if ( drive_type == 5 ) {
+ // 2.88 MB 3.5" drive
+ config_data = 0xCC; // 1100 1100
+ media_state = 0xD7; // 1101 0111
+ retval = 1;
+ }
+ //
+ // Extended floppy size uses special cmos setting
+ else if ( drive_type == 6 ) {
+ // 160k 5.25" drive
+ config_data = 0x00; // 0000 0000
+ media_state = 0x27; // 0010 0111
+ retval = 1;
+ }
+ else if ( drive_type == 7 ) {
+ // 180k 5.25" drive
+ config_data = 0x00; // 0000 0000
+ media_state = 0x27; // 0010 0111
+ retval = 1;
+ }
+ else if ( drive_type == 8 ) {
+ // 320k 5.25" drive
+ config_data = 0x00; // 0000 0000
+ media_state = 0x27; // 0010 0111
+ retval = 1;
+ }
+
+ else {
+ // not recognized
+ config_data = 0x00; // 0000 0000
+ media_state = 0x00; // 0000 0000
+ retval = 0;
+ }
+
+ if (drive == 0)
+ media_state_offset = 0x90;
+ else
+ media_state_offset = 0x91;
+ write_byte(0x0040, 0x008B, config_data);
+ write_byte(0x0040, media_state_offset, media_state);
+
+ return(retval);
+}
+
+ bx_bool
+floppy_drive_recal(drive)
+ Bit16u drive;
+{
+ Bit8u val8;
+ Bit16u curr_cyl_offset;
+
+ floppy_prepare_controller(drive);
+
+ // send Recalibrate command (2 bytes) to controller
+ outb(0x03f5, 0x07); // 07: Recalibrate
+ outb(0x03f5, drive); // 0=drive0, 1=drive1
+
+ // turn on interrupts
+ASM_START
+ sti
+ASM_END
+
+ // wait on 40:3e bit 7 to become 1
+ do {
+ val8 = (read_byte(0x0040, 0x003e) & 0x80);
+ } while ( val8 == 0 );
+
+ val8 = 0; // separate asm from while() loop
+ // turn off interrupts
+ASM_START
+ cli
+ASM_END
+
+ // set 40:3e bit 7 to 0, and calibrated bit
+ val8 = read_byte(0x0040, 0x003e);
+ val8 &= 0x7f;
+ if (drive) {
+ val8 |= 0x02; // Drive 1 calibrated
+ curr_cyl_offset = 0x0095;
+ } else {
+ val8 |= 0x01; // Drive 0 calibrated
+ curr_cyl_offset = 0x0094;
+ }
+ write_byte(0x0040, 0x003e, val8);
+ write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
+
+ return(1);
+}
+
+
+
+ bx_bool
+floppy_drive_exists(drive)
+ Bit16u drive;
+{
+ Bit8u drive_type;
+
+ // check CMOS to see if drive exists
+ drive_type = inb_cmos(0x10);
+ if (drive == 0)
+ drive_type >>= 4;
+ else
+ drive_type &= 0x0f;
+ if ( drive_type == 0 )
+ return(0);
+ else
+ return(1);
+}
+
+ void
+int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
+ Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
+{
+ Bit8u drive, num_sectors, track, sector, head, status;
+ Bit16u base_address, base_count, base_es;
+ Bit8u page, mode_register, val8, dor;
+ Bit8u return_status[7];
+ Bit8u drive_type, num_floppies, ah;
+ Bit16u es, last_addr;
+
+ BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
+
+ ah = GET_AH();
+
+ switch ( ah ) {
+ case 0x00: // diskette controller reset
+BX_DEBUG_INT13_FL("floppy f00\n");
+ drive = GET_ELDL();
+ if (drive > 1) {
+ SET_AH(1); // invalid param
+ set_diskette_ret_status(1);
+ SET_CF();
+ return;
+ }
+ drive_type = inb_cmos(0x10);
+
+ if (drive == 0)
+ drive_type >>= 4;
+ else
+ drive_type &= 0x0f;
+ if (drive_type == 0) {
+ SET_AH(0x80); // drive not responding
+ set_diskette_ret_status(0x80);
+ SET_CF();
+ return;
+ }
+ SET_AH(0);
+ set_diskette_ret_status(0);
+ CLEAR_CF(); // successful
+ set_diskette_current_cyl(drive, 0); // current cylinder
+ return;
+
+ case 0x01: // Read Diskette Status
+ CLEAR_CF();
+ val8 = read_byte(0x0000, 0x0441);
+ SET_AH(val8);
+ if (val8) {
+ SET_CF();
+ }
+ return;
+
+ case 0x02: // Read Diskette Sectors
+ case 0x03: // Write Diskette Sectors
+ case 0x04: // Verify Diskette Sectors
+ num_sectors = GET_AL();
+ track = GET_CH();
+ sector = GET_CL();
+ head = GET_DH();
+ drive = GET_ELDL();
+
+ if ((drive > 1) || (head > 1) || (sector == 0) ||
+ (num_sectors == 0) || (num_sectors > 72)) {
+ BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
+ SET_AH(1);
+ set_diskette_ret_status(1);
+ SET_AL(0); // no sectors read
+ SET_CF(); // error occurred
+ return;
+ }
+
+ // see if drive exists
+ if (floppy_drive_exists(drive) == 0) {
+ SET_AH(0x80); // not responding
+ set_diskette_ret_status(0x80);
+ SET_AL(0); // no sectors read
+ SET_CF(); // error occurred
+ return;
+ }
+
+ // see if media in drive, and type is known
+ if (floppy_media_known(drive) == 0) {
+ if (floppy_media_sense(drive) == 0) {
+ SET_AH(0x0C); // Media type not found
+ set_diskette_ret_status(0x0C);
+ SET_AL(0); // no sectors read
+ SET_CF(); // error occurred
+ return;
+ }
+ }
+
+ if (ah == 0x02) {
+ // Read Diskette Sectors
+
+ //-----------------------------------
+ // set up DMA controller for transfer
+ //-----------------------------------
+
+ // es:bx = pointer to where to place information from diskette
+ // port 04: DMA-1 base and current address, channel 2
+ // port 05: DMA-1 base and current count, channel 2
+ page = (ES >> 12); // upper 4 bits
+ base_es = (ES << 4); // lower 16bits contributed by ES
+ base_address = base_es + BX; // lower 16 bits of address
+ // contributed by ES:BX
+ if ( base_address < base_es ) {
+ // in case of carry, adjust page by 1
+ page++;
+ }
+ base_count = (num_sectors * 512) - 1;
+
+ // check for 64K boundary overrun
+ last_addr = base_address + base_count;
+ if (last_addr < base_address) {
+ SET_AH(0x09);
+ set_diskette_ret_status(0x09);
+ SET_AL(0); // no sectors read
+ SET_CF(); // error occurred
+ return;
+ }
+
+ BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
+ outb(0x000a, 0x06);
+
+ BX_DEBUG_INT13_FL("clear flip-flop\n");
+ outb(0x000c, 0x00); // clear flip-flop
+ outb(0x0004, base_address);
+ outb(0x0004, base_address>>8);
+ BX_DEBUG_INT13_FL("clear flip-flop\n");
+ outb(0x000c, 0x00); // clear flip-flop
+ outb(0x0005, base_count);
+ outb(0x0005, base_count>>8);
+
+ // port 0b: DMA-1 Mode Register
+ mode_register = 0x46; // single mode, increment, autoinit disable,
+ // transfer type=write, channel 2
+ BX_DEBUG_INT13_FL("setting mode register\n");
+ outb(0x000b, mode_register);
+
+ BX_DEBUG_INT13_FL("setting page register\n");
+ // port 81: DMA-1 Page Register, channel 2
+ outb(0x0081, page);
+
+ BX_DEBUG_INT13_FL("unmask chan 2\n");
+ outb(0x000a, 0x02); // unmask channel 2
+
+ BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
+ outb(0x000a, 0x02);
+
+ //--------------------------------------
+ // set up floppy controller for transfer
+ //--------------------------------------
+ floppy_prepare_controller(drive);
+
+ // send read-normal-data command (9 bytes) to controller
+ outb(0x03f5, 0xe6); // e6: read normal data
+ outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
+ outb(0x03f5, track);
+ outb(0x03f5, head);
+ outb(0x03f5, sector);
+ outb(0x03f5, 2); // 512 byte sector size
+ outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
+ outb(0x03f5, 0); // Gap length
+ outb(0x03f5, 0xff); // Gap length
+
+ // turn on interrupts
+ ASM_START
+ sti
+ ASM_END
+
+ // wait on 40:3e bit 7 to become 1
+ do {
+ val8 = read_byte(0x0040, 0x0040);
+ if (val8 == 0) {
+ floppy_reset_controller();
+ SET_AH(0x80); // drive not ready (timeout)
+ set_diskette_ret_status(0x80);
+ SET_AL(0); // no sectors read
+ SET_CF(); // error occurred
+ return;
+ }
+ val8 = (read_byte(0x0040, 0x003e) & 0x80);
+ } while ( val8 == 0 );
+
+ val8 = 0; // separate asm from while() loop
+ // turn off interrupts
+ ASM_START
+ cli
+ ASM_END
+
+ // set 40:3e bit 7 to 0
+ val8 = read_byte(0x0040, 0x003e);
+ val8 &= 0x7f;
+ write_byte(0x0040, 0x003e, val8);
+
+ // check port 3f4 for accessibility to status bytes
+ val8 = inb(0x3f4);
+ if ( (val8 & 0xc0) != 0xc0 )
+ BX_PANIC("int13_diskette: ctrl not ready\n");
+
+ // read 7 return status bytes from controller
+ // using loop index broken, have to unroll...
+ return_status[0] = inb(0x3f5);
+ return_status[1] = inb(0x3f5);
+ return_status[2] = inb(0x3f5);
+ return_status[3] = inb(0x3f5);
+ return_status[4] = inb(0x3f5);
+ return_status[5] = inb(0x3f5);
+ return_status[6] = inb(0x3f5);
+ // record in BIOS Data Area
+ write_byte(0x0040, 0x0042, return_status[0]);
+ write_byte(0x0040, 0x0043, return_status[1]);
+ write_byte(0x0040, 0x0044, return_status[2]);
+ write_byte(0x0040, 0x0045, return_status[3]);
+ write_byte(0x0040, 0x0046, return_status[4]);
+ write_byte(0x0040, 0x0047, return_status[5]);
+ write_byte(0x0040, 0x0048, return_status[6]);
+
+ if ( (return_status[0] & 0xc0) != 0 ) {
+ SET_AH(0x20);
+ set_diskette_ret_status(0x20);
+ SET_AL(0); // no sectors read
+ SET_CF(); // error occurred
+ return;
+ }
+
+ // ??? should track be new val from return_status[3] ?
+ set_diskette_current_cyl(drive, track);
+ // AL = number of sectors read (same value as passed)
+ SET_AH(0x00); // success
+ CLEAR_CF(); // success
+ return;
+ } else if (ah == 0x03) {
+ // Write Diskette Sectors
+
+ //-----------------------------------
+ // set up DMA controller for transfer
+ //-----------------------------------
+
+ // es:bx = pointer to where to place information from diskette
+ // port 04: DMA-1 base and current address, channel 2
+ // port 05: DMA-1 base and current count, channel 2
+ page = (ES >> 12); // upper 4 bits
+ base_es = (ES << 4); // lower 16bits contributed by ES
+ base_address = base_es + BX; // lower 16 bits of address
+ // contributed by ES:BX
+ if ( base_address < base_es ) {
+ // in case of carry, adjust page by 1
+ page++;
+ }
+ base_count = (num_sectors * 512) - 1;
+
+ // check for 64K boundary overrun
+ last_addr = base_address + base_count;
+ if (last_addr < base_address) {
+ SET_AH(0x09);
+ set_diskette_ret_status(0x09);
+ SET_AL(0); // no sectors read
+ SET_CF(); // error occurred
+ return;
+ }
+
+ BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
+ outb(0x000a, 0x06);
+
+ outb(0x000c, 0x00); // clear flip-flop
+ outb(0x0004, base_address);
+ outb(0x0004, base_address>>8);
+ outb(0x000c, 0x00); // clear flip-flop
+ outb(0x0005, base_count);
+ outb(0x0005, base_count>>8);
+
+ // port 0b: DMA-1 Mode Register
+ mode_register = 0x4a; // single mode, increment, autoinit disable,
+ // transfer type=read, channel 2
+ outb(0x000b, mode_register);
+
+ // port 81: DMA-1 Page Register, channel 2
+ outb(0x0081, page);
+
+ BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
+ outb(0x000a, 0x02);
+
+ //--------------------------------------
+ // set up floppy controller for transfer
+ //--------------------------------------
+ floppy_prepare_controller(drive);
+
+ // send write-normal-data command (9 bytes) to controller
+ outb(0x03f5, 0xc5); // c5: write normal data
+ outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
+ outb(0x03f5, track);
+ outb(0x03f5, head);
+ outb(0x03f5, sector);
+ outb(0x03f5, 2); // 512 byte sector size
+ outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
+ outb(0x03f5, 0); // Gap length
+ outb(0x03f5, 0xff); // Gap length
+
+ // turn on interrupts
+ ASM_START
+ sti
+ ASM_END
+
+ // wait on 40:3e bit 7 to become 1
+ do {
+ val8 = read_byte(0x0040, 0x0040);
+ if (val8 == 0) {
+ floppy_reset_controller();
+ SET_AH(0x80); // drive not ready (timeout)
+ set_diskette_ret_status(0x80);
+ SET_AL(0); // no sectors written
+ SET_CF(); // error occurred
+ return;
+ }
+ val8 = (read_byte(0x0040, 0x003e) & 0x80);
+ } while ( val8 == 0 );
+
+ val8 = 0; // separate asm from while() loop
+ // turn off interrupts
+ ASM_START
+ cli
+ ASM_END
+
+ // set 40:3e bit 7 to 0
+ val8 = read_byte(0x0040, 0x003e);
+ val8 &= 0x7f;
+ write_byte(0x0040, 0x003e, val8);
+
+ // check port 3f4 for accessibility to status bytes
+ val8 = inb(0x3f4);
+ if ( (val8 & 0xc0) != 0xc0 )
+ BX_PANIC("int13_diskette: ctrl not ready\n");
+
+ // read 7 return status bytes from controller
+ // using loop index broken, have to unroll...
+ return_status[0] = inb(0x3f5);
+ return_status[1] = inb(0x3f5);
+ return_status[2] = inb(0x3f5);
+ return_status[3] = inb(0x3f5);
+ return_status[4] = inb(0x3f5);
+ return_status[5] = inb(0x3f5);
+ return_status[6] = inb(0x3f5);
+ // record in BIOS Data Area
+ write_byte(0x0040, 0x0042, return_status[0]);
+ write_byte(0x0040, 0x0043, return_status[1]);
+ write_byte(0x0040, 0x0044, return_status[2]);
+ write_byte(0x0040, 0x0045, return_status[3]);
+ write_byte(0x0040, 0x0046, return_status[4]);
+ write_byte(0x0040, 0x0047, return_status[5]);
+ write_byte(0x0040, 0x0048, return_status[6]);
+
+ if ( (return_status[0] & 0xc0) != 0 ) {
+ if ( (return_status[1] & 0x02) != 0 ) {
+ // diskette not writable.
+ // AH=status code=0x03 (tried to write on write-protected disk)
+ // AL=number of sectors written=0
+ AX = 0x0300;
+ SET_CF();
+ return;
+ } else {
+ BX_PANIC("int13_diskette_function: read error\n");
+ }
+ }
+
+ // ??? should track be new val from return_status[3] ?
+ set_diskette_current_cyl(drive, track);
+ // AL = number of sectors read (same value as passed)
+ SET_AH(0x00); // success
+ CLEAR_CF(); // success
+ return;
+ } else { // if (ah == 0x04)
+ // Verify Diskette Sectors
+
+ // ??? should track be new val from return_status[3] ?
+ set_diskette_current_cyl(drive, track);
+ // AL = number of sectors verified (same value as passed)
+ CLEAR_CF(); // success
+ SET_AH(0x00); // success
+ return;
+ }
+ break;
+
+ case 0x05: // format diskette track
+BX_DEBUG_INT13_FL("floppy f05\n");
+
+ num_sectors = GET_AL();
+ track = GET_CH();
+ head = GET_DH();
+ drive = GET_ELDL();
+
+ if ((drive > 1) || (head > 1) || (track > 79) ||
+ (num_sectors == 0) || (num_sectors > 18)) {
+ SET_AH(1);
+ set_diskette_ret_status(1);
+ SET_CF(); // error occurred
+ }
+
+ // see if drive exists
+ if (floppy_drive_exists(drive) == 0) {
+ SET_AH(0x80); // drive not responding
+ set_diskette_ret_status(0x80);
+ SET_CF(); // error occurred
+ return;
+ }
+
+ // see if media in drive, and type is known
+ if (floppy_media_known(drive) == 0) {
+ if (floppy_media_sense(drive) == 0) {
+ SET_AH(0x0C); // Media type not found
+ set_diskette_ret_status(0x0C);
+ SET_AL(0); // no sectors read
+ SET_CF(); // error occurred
+ return;
+ }
+ }
+
+ // set up DMA controller for transfer
+ page = (ES >> 12); // upper 4 bits
+ base_es = (ES << 4); // lower 16bits contributed by ES
+ base_address = base_es + BX; // lower 16 bits of address
+ // contributed by ES:BX
+ if ( base_address < base_es ) {
+ // in case of carry, adjust page by 1
+ page++;
+ }
+ base_count = (num_sectors * 4) - 1;
+
+ // check for 64K boundary overrun
+ last_addr = base_address + base_count;
+ if (last_addr < base_address) {
+ SET_AH(0x09);
+ set_diskette_ret_status(0x09);
+ SET_AL(0); // no sectors read
+ SET_CF(); // error occurred
+ return;
+ }
+
+ outb(0x000a, 0x06);
+ outb(0x000c, 0x00); // clear flip-flop
+ outb(0x0004, base_address);
+ outb(0x0004, base_address>>8);
+ outb(0x000c, 0x00); // clear flip-flop
+ outb(0x0005, base_count);
+ outb(0x0005, base_count>>8);
+ mode_register = 0x4a; // single mode, increment, autoinit disable,
+ // transfer type=read, channel 2
+ outb(0x000b, mode_register);
+ // port 81: DMA-1 Page Register, channel 2
+ outb(0x0081, page);
+ outb(0x000a, 0x02);
+
+ // set up floppy controller for transfer
+ floppy_prepare_controller(drive);
+
+ // send format-track command (6 bytes) to controller
+ outb(0x03f5, 0x4d); // 4d: format track
+ outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
+ outb(0x03f5, 2); // 512 byte sector size
+ outb(0x03f5, num_sectors); // number of sectors per track
+ outb(0x03f5, 0); // Gap length
+ outb(0x03f5, 0xf6); // Fill byte
+ // turn on interrupts
+ ASM_START
+ sti
+ ASM_END
+
+ // wait on 40:3e bit 7 to become 1
+ do {
+ val8 = read_byte(0x0040, 0x0040);
+ if (val8 == 0) {
+ floppy_reset_controller();
+ SET_AH(0x80); // drive not ready (timeout)
+ set_diskette_ret_status(0x80);
+ SET_CF(); // error occurred
+ return;
+ }
+ val8 = (read_byte(0x0040, 0x003e) & 0x80);
+ } while ( val8 == 0 );
+
+ val8 = 0; // separate asm from while() loop
+ // turn off interrupts
+ ASM_START
+ cli
+ ASM_END
+ // set 40:3e bit 7 to 0
+ val8 = read_byte(0x0040, 0x003e);
+ val8 &= 0x7f;
+ write_byte(0x0040, 0x003e, val8);
+ // check port 3f4 for accessibility to status bytes
+ val8 = inb(0x3f4);
+ if ( (val8 & 0xc0) != 0xc0 )
+ BX_PANIC("int13_diskette: ctrl not ready\n");
+
+ // read 7 return status bytes from controller
+ // using loop index broken, have to unroll...
+ return_status[0] = inb(0x3f5);
+ return_status[1] = inb(0x3f5);
+ return_status[2] = inb(0x3f5);
+ return_status[3] = inb(0x3f5);
+ return_status[4] = inb(0x3f5);
+ return_status[5] = inb(0x3f5);
+ return_status[6] = inb(0x3f5);
+ // record in BIOS Data Area
+ write_byte(0x0040, 0x0042, return_status[0]);
+ write_byte(0x0040, 0x0043, return_status[1]);
+ write_byte(0x0040, 0x0044, return_status[2]);
+ write_byte(0x0040, 0x0045, return_status[3]);
+ write_byte(0x0040, 0x0046, return_status[4]);
+ write_byte(0x0040, 0x0047, return_status[5]);
+ write_byte(0x0040, 0x0048, return_status[6]);
+
+ if ( (return_status[0] & 0xc0) != 0 ) {
+ if ( (return_status[1] & 0x02) != 0 ) {
+ // diskette not writable.
+ // AH=status code=0x03 (tried to write on write-protected disk)
+ // AL=number of sectors written=0
+ AX = 0x0300;
+ SET_CF();
+ return;
+ } else {
+ BX_PANIC("int13_diskette_function: write error\n");
+ }
+ }
+
+ SET_AH(0);
+ set_diskette_ret_status(0);
+ set_diskette_current_cyl(drive, 0);
+ CLEAR_CF(); // successful
+ return;
+
+
+ case 0x08: // read diskette drive parameters
+BX_DEBUG_INT13_FL("floppy f08\n");
+ drive = GET_ELDL();
+
+ if (drive > 1) {
+ AX = 0;
+ BX = 0;
+ CX = 0;
+ DX = 0;
+ ES = 0;
+ DI = 0;
+ SET_DL(num_floppies);
+ SET_CF();
+ return;
+ }
+
+ drive_type = inb_cmos(0x10);
+ num_floppies = 0;
+ if (drive_type & 0xf0)
+ num_floppies++;
+ if (drive_type & 0x0f)
+ num_floppies++;
+
+ if (drive == 0)
+ drive_type >>= 4;
+ else
+ drive_type &= 0x0f;
+
+ SET_BH(0);
+ SET_BL(drive_type);
+ SET_AH(0);
+ SET_AL(0);
+ SET_DL(num_floppies);
+
+ switch (drive_type) {
+ case 0: // none
+ CX = 0;
+ SET_DH(0); // max head #
+ break;
+
+ case 1: // 360KB, 5.25"
+ CX = 0x2709; // 40 tracks, 9 sectors
+ SET_DH(1); // max head #
+ break;
+
+ case 2: // 1.2MB, 5.25"
+ CX = 0x4f0f; // 80 tracks, 15 sectors
+ SET_DH(1); // max head #
+ break;
+
+ case 3: // 720KB, 3.5"
+ CX = 0x4f09; // 80 tracks, 9 sectors
+ SET_DH(1); // max head #
+ break;
+
+ case 4: // 1.44MB, 3.5"
+ CX = 0x4f12; // 80 tracks, 18 sectors
+ SET_DH(1); // max head #
+ break;
+
+ case 5: // 2.88MB, 3.5"
+ CX = 0x4f24; // 80 tracks, 36 sectors
+ SET_DH(1); // max head #
+ break;
+
+ case 6: // 160k, 5.25"
+ CX = 0x2708; // 40 tracks, 8 sectors
+ SET_DH(0); // max head #
+ break;
+
+ case 7: // 180k, 5.25"
+ CX = 0x2709; // 40 tracks, 9 sectors
+ SET_DH(0); // max head #
+ break;
+
+ case 8: // 320k, 5.25"
+ CX = 0x2708; // 40 tracks, 8 sectors
+ SET_DH(1); // max head #
+ break;
+
+ default: // ?
+ BX_PANIC("floppy: int13: bad floppy type\n");
+ }
+
+ /* set es & di to point to 11 byte diskette param table in ROM */
+ASM_START
+ push bp
+ mov bp, sp
+ mov ax, #diskette_param_table2
+ mov _int13_diskette_function.DI+2[bp], ax
+ mov _int13_diskette_function.ES+2[bp], cs
+ pop bp
+ASM_END
+ CLEAR_CF(); // success
+ /* disk status not changed upon success */
+ return;
+
+
+ case 0x15: // read diskette drive type
+BX_DEBUG_INT13_FL("floppy f15\n");
+ drive = GET_ELDL();
+ if (drive > 1) {
+ SET_AH(0); // only 2 drives supported
+ // set_diskette_ret_status here ???
+ SET_CF();
+ return;
+ }
+ drive_type = inb_cmos(0x10);
+
+ if (drive == 0)
+ drive_type >>= 4;
+ else
+ drive_type &= 0x0f;
+ CLEAR_CF(); // successful, not present
+ if (drive_type==0) {
+ SET_AH(0); // drive not present
+ }
+ else {
+ SET_AH(1); // drive present, does not support change line
+ }
+
+ return;
+
+ case 0x16: // get diskette change line status
+BX_DEBUG_INT13_FL("floppy f16\n");
+ drive = GET_ELDL();
+ if (drive > 1) {
+ SET_AH(0x01); // invalid drive
+ set_diskette_ret_status(0x01);
+ SET_CF();
+ return;
+ }
+
+ SET_AH(0x06); // change line not supported
+ set_diskette_ret_status(0x06);
+ SET_CF();
+ return;
+
+ case 0x17: // set diskette type for format(old)
+BX_DEBUG_INT13_FL("floppy f17\n");
+ /* not used for 1.44M floppies */
+ SET_AH(0x01); // not supported
+ set_diskette_ret_status(1); /* not supported */
+ SET_CF();
+ return;
+
+ case 0x18: // set diskette type for format(new)
+BX_DEBUG_INT13_FL("floppy f18\n");
+ SET_AH(0x01); // do later
+ set_diskette_ret_status(1);
+ SET_CF();
+ return;
+
+ default:
+ BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
+
+ // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
+ SET_AH(0x01); // ???
+ set_diskette_ret_status(1);
+ SET_CF();
+ return;
+ // }
+ }
+}
+#else // #if BX_SUPPORT_FLOPPY
+ void
+int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
+ Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
+{
+ Bit8u val8;
+
+ switch ( GET_AH() ) {
+
+ case 0x01: // Read Diskette Status
+ CLEAR_CF();
+ val8 = read_byte(0x0000, 0x0441);
+ SET_AH(val8);
+ if (val8) {
+ SET_CF();
+ }
+ return;
+
+ default:
+ SET_CF();
+ write_byte(0x0000, 0x0441, 0x01);
+ SET_AH(0x01);
+ }
+}
+#endif // #if BX_SUPPORT_FLOPPY
+
+ void
+set_diskette_ret_status(value)
+ Bit8u value;
+{
+ write_byte(0x0040, 0x0041, value);
+}
+
+ void
+set_diskette_current_cyl(drive, cyl)
+ Bit8u drive;
+ Bit8u cyl;
+{
+ if (drive > 1)
+ BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
+ write_byte(0x0040, 0x0094+drive, cyl);
+}
+
+ void
+determine_floppy_media(drive)
+ Bit16u drive;
+{
+#if 0
+ Bit8u val8, DOR, ctrl_info;
+
+ ctrl_info = read_byte(0x0040, 0x008F);
+ if (drive==1)
+ ctrl_info >>= 4;
+ else
+ ctrl_info &= 0x0f;
+
+#if 0
+ if (drive == 0) {
+ DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
+ }
+ else {
+ DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
+ }
+#endif
+
+ if ( (ctrl_info & 0x04) != 0x04 ) {
+ // Drive not determined means no drive exists, done.
+ return;
+ }
+
+#if 0
+ // check Main Status Register for readiness
+ val8 = inb(0x03f4) & 0x80; // Main Status Register
+ if (val8 != 0x80)
+ BX_PANIC("d_f_m: MRQ bit not set\n");
+
+ // change line
+
+ // existing BDA values
+
+ // turn on drive motor
+ outb(0x03f2, DOR); // Digital Output Register
+ //
+#endif
+ BX_PANIC("d_f_m: OK so far\n");
+#endif
+}
+
+ void
+int17_function(regs, ds, iret_addr)
+ pusha_regs_t regs; // regs pushed from PUSHA instruction
+ Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
+ iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
+{
+ Bit16u addr,timeout;
+ Bit8u val8;
+
+ ASM_START
+ sti
+ ASM_END
+
+ addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
+ if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
+ timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
+ if (regs.u.r8.ah == 0) {
+ outb(addr, regs.u.r8.al);
+ val8 = inb(addr+2);
+ outb(addr+2, val8 | 0x01); // send strobe
+ ASM_START
+ nop
+ ASM_END
+ outb(addr+2, val8 & ~0x01);
+ while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
+ timeout--;
+ }
+ }
+ if (regs.u.r8.ah == 1) {
+ val8 = inb(addr+2);
+ outb(addr+2, val8 & ~0x04); // send init
+ ASM_START
+ nop
+ ASM_END
+ outb(addr+2, val8 | 0x04);
+ }
+ val8 = inb(addr+1);
+ regs.u.r8.ah = (val8 ^ 0x48);
+ if (!timeout) regs.u.r8.ah |= 0x01;
+ ClearCF(iret_addr.flags);
+ } else {
+ SetCF(iret_addr.flags); // Unsupported
+ }
+}
+
+void
+int19_function(seq_nr)
+Bit16u seq_nr;
+{
+ Bit16u ebda_seg=read_word(0x0040,0x000E);
+ Bit16u bootdev;
+ Bit8u bootdrv;
+ Bit8u bootchk;
+ Bit16u bootseg;
+ Bit16u bootip;
+ Bit16u status;
+ Bit16u bootfirst;
+
+ ipl_entry_t e;
+
+ // if BX_ELTORITO_BOOT is not defined, old behavior
+ // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
+ // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
+ // 0: system boot sequence, first drive C: then A:
+ // 1: system boot sequence, first drive A: then C:
+ // else BX_ELTORITO_BOOT is defined
+ // CMOS regs 0x3D and 0x38 contain the boot sequence:
+ // CMOS reg 0x3D & 0x0f : 1st boot device
+ // CMOS reg 0x3D & 0xf0 : 2nd boot device
+ // CMOS reg 0x38 & 0xf0 : 3rd boot device
+ // boot device codes:
+ // 0x00 : not defined
+ // 0x01 : first floppy
+ // 0x02 : first harddrive
+ // 0x03 : first cdrom
+ // 0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
+ // else : boot failure
+
+ // Get the boot sequence
+#if BX_ELTORITO_BOOT
+ bootdev = inb_cmos(0x3d);
+ bootdev |= ((inb_cmos(0x38) & 0xf0) << 4);
+ bootdev >>= 4 * seq_nr;
+ bootdev &= 0xf;
+
+ /* Read user selected device */
+ bootfirst = read_word(IPL_SEG, IPL_BOOTFIRST_OFFSET);
+ if (bootfirst != 0xFFFF) {
+ bootdev = bootfirst;
+ /* User selected device not set */
+ write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
+ /* Reset boot sequence */
+ write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xFFFF);
+ } else if (bootdev == 0) BX_PANIC("No bootable device.\n");
+
+ /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
+ bootdev -= 1;
+#else
+ if (seq_nr ==2) BX_PANIC("No more boot devices.");
+ if (!!(inb_cmos(0x2d) & 0x20) ^ (seq_nr == 1))
+ /* Boot from floppy if the bit is set or it's the second boot */
+ bootdev = 0x00;
+ else
+ bootdev = 0x01;
+#endif
+
+ /* Read the boot device from the IPL table */
+ if (get_boot_vector(bootdev, &e) == 0) {
+ BX_INFO("Invalid boot device (0x%x)\n", bootdev);
+ return;
+ }
+
+ /* Do the loading, and set up vector as a far pointer to the boot
+ * address, and bootdrv as the boot drive */
+ print_boot_device(&e);
+
+ switch(e.type) {
+ case IPL_TYPE_FLOPPY: /* FDD */
+ case IPL_TYPE_HARDDISK: /* HDD */
+
+ bootdrv = (e.type == IPL_TYPE_HARDDISK) ? 0x80 : 0x00;
+ bootseg = 0x07c0;
+ status = 0;
+
+ASM_START
+ push bp
+ mov bp, sp
+ push ax
+ push bx
+ push cx
+ push dx
+
+ mov dl, _int19_function.bootdrv + 2[bp]
+ mov ax, _int19_function.bootseg + 2[bp]
+ mov es, ax ;; segment
+ xor bx, bx ;; offset
+ mov ah, #0x02 ;; function 2, read diskette sector
+ mov al, #0x01 ;; read 1 sector
+ mov ch, #0x00 ;; track 0
+ mov cl, #0x01 ;; sector 1
+ mov dh, #0x00 ;; head 0
+ int #0x13 ;; read sector
+ jnc int19_load_done
+ mov ax, #0x0001
+ mov _int19_function.status + 2[bp], ax
+
+int19_load_done:
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ pop bp
+ASM_END
+
+ if (status != 0) {
+ print_boot_failure(e.type, 1);
+ return;
+ }
+
+ /* Always check the signature on a HDD boot sector; on FDD, only do
+ * the check if the CMOS doesn't tell us to skip it */
+ if ((e.type != IPL_TYPE_FLOPPY) || !((inb_cmos(0x38) & 0x01))) {
+ if (read_word(bootseg,0x1fe) != 0xaa55) {
+ print_boot_failure(e.type, 0);
+ return;
+ }
+ }
+
+ /* Canonicalize bootseg:bootip */
+ bootip = (bootseg & 0x0fff) << 4;
+ bootseg &= 0xf000;
+ break;
+
+#if BX_ELTORITO_BOOT
+ case IPL_TYPE_CDROM: /* CD-ROM */
+ status = cdrom_boot();
+
+ // If failure
+ if ( (status & 0x00ff) !=0 ) {
+ print_cdromboot_failure(status);
+ print_boot_failure(e.type, 1);
+ return;
+ }
+
+ bootdrv = (Bit8u)(status>>8);
+ bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
+ bootip = 0;
+ break;
+#endif
+
+ case IPL_TYPE_BEV: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */
+ bootseg = e.vector >> 16;
+ bootip = e.vector & 0xffff;
+ break;
+
+ default: return;
+ }
+
+ /* Debugging info */
+ BX_INFO("Booting from %x:%x\n", bootseg, bootip);
+
+ /* Jump to the boot vector */
+ASM_START
+ mov bp, sp
+ push cs
+ push #int18_handler
+ ;; Build an iret stack frame that will take us to the boot vector.
+ ;; iret pops ip, then cs, then flags, so push them in the opposite order.
+ pushf
+ mov ax, _int19_function.bootseg + 0[bp]
+ push ax
+ mov ax, _int19_function.bootip + 0[bp]
+ push ax
+ ;; Set the magic number in ax and the boot drive in dl.
+ mov ax, #0xaa55
+ mov dl, _int19_function.bootdrv + 0[bp]
+ ;; Zero some of the other registers.
+ xor bx, bx
+ mov ds, bx
+ mov es, bx
+ mov bp, bx
+ ;; Go!
+ iret
+ASM_END
+}
+
+ void
+int1a_function(regs, ds, iret_addr)
+ pusha_regs_t regs; // regs pushed from PUSHA instruction
+ Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
+ iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
+{
+ Bit8u val8;
+
+ BX_DEBUG_INT1A("int1a: AX=%04x BX=%04x CX=%04x DX=%04x DS=%04x\n", regs.u.r16.ax, regs.u.r16.bx, regs.u.r16.cx, regs.u.r16.dx, ds);
+
+ ASM_START
+ sti
+ ASM_END
+
+ switch (regs.u.r8.ah) {
+ case 0: // get current clock count
+ ASM_START
+ cli
+ ASM_END
+ regs.u.r16.cx = BiosData->ticks_high;
+ regs.u.r16.dx = BiosData->ticks_low;
+ regs.u.r8.al = BiosData->midnight_flag;
+ BiosData->midnight_flag = 0; // reset flag
+ ASM_START
+ sti
+ ASM_END
+ // AH already 0
+ ClearCF(iret_addr.flags); // OK
+ break;
+
+ case 1: // Set Current Clock Count
+ ASM_START
+ cli
+ ASM_END
+ BiosData->ticks_high = regs.u.r16.cx;
+ BiosData->ticks_low = regs.u.r16.dx;
+ BiosData->midnight_flag = 0; // reset flag
+ ASM_START
+ sti
+ ASM_END
+ regs.u.r8.ah = 0;
+ ClearCF(iret_addr.flags); // OK
+ break;
+
+
+ case 2: // Read CMOS Time
+ if (rtc_updating()) {
+ SetCF(iret_addr.flags);
+ break;
+ }
+
+ regs.u.r8.dh = inb_cmos(0x00); // Seconds
+ regs.u.r8.cl = inb_cmos(0x02); // Minutes
+ regs.u.r8.ch = inb_cmos(0x04); // Hours
+ regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
+ regs.u.r8.ah = 0;
+ regs.u.r8.al = regs.u.r8.ch;
+ ClearCF(iret_addr.flags); // OK
+ break;
+
+ case 3: // Set CMOS Time
+ // 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(0x00, regs.u.r8.dh); // Seconds
+ outb_cmos(0x02, regs.u.r8.cl); // Minutes
+ outb_cmos(0x04, regs.u.r8.ch); // Hours
+ // Set Daylight Savings time enabled bit to requested value
+ val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
+ // (reg B already selected)
+ outb_cmos(0x0b, val8);
+ regs.u.r8.ah = 0;
+ regs.u.r8.al = val8; // val last written to Reg B
+ ClearCF(iret_addr.flags); // OK
+ break;
+
+ case 4: // Read CMOS Date
+ regs.u.r8.ah = 0;
+ if (rtc_updating()) {
+ SetCF(iret_addr.flags);
+ break;
+ }
+ regs.u.r8.cl = inb_cmos(0x09); // Year
+ regs.u.r8.dh = inb_cmos(0x08); // Month
+ regs.u.r8.dl = inb_cmos(0x07); // Day of Month
+ regs.u.r8.ch = inb_cmos(0x32); // Century
+ regs.u.r8.al = regs.u.r8.ch;
+ ClearCF(iret_addr.flags); // OK
+ break;
+
+ case 5: // Set CMOS Date
+ // 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();
+ SetCF(iret_addr.flags);
+ break;
+ }
+ outb_cmos(0x09, regs.u.r8.cl); // Year
+ outb_cmos(0x08, regs.u.r8.dh); // Month
+ outb_cmos(0x07, regs.u.r8.dl); // Day of Month
+ outb_cmos(0x32, regs.u.r8.ch); // Century
+ val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
+ outb_cmos(0x0b, val8);
+ regs.u.r8.ah = 0;
+ regs.u.r8.al = val8; // AL = val last written to Reg B
+ ClearCF(iret_addr.flags); // OK
+ break;
+
+ case 6: // Set Alarm Time in CMOS
+ // 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)
+ val8 = inb_cmos(0x0b); // Get Status Reg B
+ regs.u.r16.ax = 0;
+ if (val8 & 0x20) {
+ // Alarm interrupt enabled already
+ SetCF(iret_addr.flags); // Error: alarm in use
+ break;
+ }
+ if (rtc_updating()) {
+ init_rtc();
+ // fall through as if an update were not in progress
+ }
+ outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
+ outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
+ outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
+ outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
+ // enable Status Reg B alarm bit, clear halt clock bit
+ outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
+ ClearCF(iret_addr.flags); // OK
+ break;
+
+ case 7: // Turn off Alarm
+ // 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)
+ val8 = inb_cmos(0x0b); // Get Status Reg B
+ // clear clock-halt bit, disable alarm bit
+ outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
+ regs.u.r8.ah = 0;
+ regs.u.r8.al = val8; // val last written to Reg B
+ ClearCF(iret_addr.flags); // OK
+ break;
+#if BX_PCIBIOS
+ case 0xb1:
+ // real mode PCI BIOS functions now handled in assembler code
+ // this C code handles the error code for information only
+ if (regs.u.r8.bl == 0xff) {
+ BX_INFO("PCI BIOS: PCI not present\n");
+ } else if (regs.u.r8.bl == 0x81) {
+ BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
+ } else if (regs.u.r8.bl == 0x83) {
+ BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
+ } else if (regs.u.r8.bl == 0x86) {
+ if (regs.u.r8.al == 0x02) {
+ BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
+ } else {
+ BX_INFO("no PCI device with class code 0x%02x%04x found at index %d\n", regs.u.r8.cl, regs.u.r16.dx, regs.u.r16.si);
+ }
+ }
+ regs.u.r8.ah = regs.u.r8.bl;
+ SetCF(iret_addr.flags);
+ break;
+#endif
+
+ default:
+ SetCF(iret_addr.flags); // Unsupported
+ }
+}
+
+ void
+int70_function(regs, ds, iret_addr)
+ pusha_regs_t regs; // regs pushed from PUSHA instruction
+ Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
+ iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
+{
+ // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
+ Bit8u registerB = 0, registerC = 0;
+
+ // Check which modes are enabled and have occurred.
+ registerB = inb_cmos( 0xB );
+ registerC = inb_cmos( 0xC );
+
+ if( ( registerB & 0x60 ) != 0 ) {
+ if( ( registerC & 0x20 ) != 0 ) {
+ // Handle Alarm Interrupt.
+ASM_START
+ sti
+ int #0x4a
+ cli
+ASM_END
+ }
+ if( ( registerC & 0x40 ) != 0 ) {
+ // Handle Periodic Interrupt.
+
+ if( read_byte( 0x40, 0xA0 ) != 0 ) {
+ // Wait Interval (Int 15, AH=83) active.
+ Bit32u time, toggle;
+
+ time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
+ if( time < 0x3D1 ) {
+ // Done waiting.
+ Bit16u segment, offset;
+
+ segment = read_word( 0x40, 0x98 );
+ offset = read_word( 0x40, 0x9A );
+ write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
+ outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
+ write_byte(segment, offset, read_byte(segment, offset) | 0x80 ); // Write to specified flag byte.
+ } else {
+ // Continue waiting.
+ time -= 0x3D1;
+ write_dword( 0x40, 0x9C, time );
+ }
+ }
+ }
+ }
+
+ASM_START
+ call eoi_both_pics
+ASM_END
+}
+
+
+ASM_START
+;------------------------------------------
+;- INT74h : PS/2 mouse hardware interrupt -
+;------------------------------------------
+int74_handler:
+ sti
+ pusha
+ push ds ;; save DS
+ push #0x00 ;; placeholder for status
+ push #0x00 ;; placeholder for X
+ push #0x00 ;; placeholder for Y
+ push #0x00 ;; placeholder for Z
+ push #0x00 ;; placeholder for make_far_call boolean
+ call _int74_function
+ pop cx ;; remove make_far_call from stack
+ jcxz int74_done
+
+ ;; make far call to EBDA:0022
+ push #0x00
+ pop ds
+ push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
+ pop ds
+ //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
+ call far ptr[0x22]
+int74_done:
+ cli
+ call eoi_both_pics
+ add sp, #8 ;; pop status, x, y, z
+
+ pop ds ;; restore DS
+ popa
+ iret
+
+
+;; This will perform an IRET, but will retain value of current CF
+;; by altering flags on stack. Better than RETF #02.
+iret_modify_cf:
+ jc carry_set
+ push bp
+ mov bp, sp
+ and BYTE [bp + 0x06], #0xfe
+ pop bp
+ iret
+carry_set:
+ push bp
+ mov bp, sp
+ or BYTE [bp + 0x06], #0x01
+ pop bp
+ iret
+
+
+;----------------------
+;- INT13h (relocated) -
+;----------------------
+;
+; int13_relocated is a little bit messed up since I played with it
+; I have to rewrite it:
+; - call a function that detect which function to call
+; - make all called C function get the same parameters list
+;
+int13_relocated:
+
+#if BX_ELTORITO_BOOT
+ ;; check for an eltorito function
+ cmp ah,#0x4a
+ jb int13_not_eltorito
+ cmp ah,#0x4d
+ ja int13_not_eltorito
+
+ pusha
+ push es
+ push ds
+ push ss
+ pop ds
+
+ push #int13_out
+ jmp _int13_eltorito ;; ELDX not used
+
+int13_not_eltorito:
+ push ax
+ push bx
+ push cx
+ push dx
+
+ ;; check if emulation active
+ call _cdemu_isactive
+ cmp al,#0x00
+ je int13_cdemu_inactive
+
+ ;; check if access to the emulated drive
+ call _cdemu_emulated_drive
+ pop dx
+ push dx
+ cmp al,dl ;; int13 on emulated drive
+ jne int13_nocdemu
+
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+
+ pusha
+ push es
+ push ds
+ push ss
+ pop ds
+
+ push #int13_out
+ jmp _int13_cdemu ;; ELDX not used
+
+int13_nocdemu:
+ and dl,#0xE0 ;; mask to get device class, including cdroms
+ cmp al,dl ;; al is 0x00 or 0x80
+ jne int13_cdemu_inactive ;; inactive for device class
+
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+
+ push ax
+ push cx
+ push dx
+ push bx
+
+ dec dl ;; real drive is dl - 1
+ jmp int13_legacy
+
+int13_cdemu_inactive:
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+
+#endif // BX_ELTORITO_BOOT
+
+int13_noeltorito:
+
+ push ax
+ push cx
+ push dx
+ push bx
+
+int13_legacy:
+
+ push dx ;; push eltorito value of dx instead of sp
+
+ push bp
+ push si
+ push di
+
+ push es
+ push ds
+ push ss
+ pop ds
+
+ ;; now the 16-bit registers can be restored with:
+ ;; pop ds; pop es; popa; iret
+ ;; arguments passed to functions should be
+ ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
+
+ test dl, #0x80
+ jnz int13_notfloppy
+
+ push #int13_out
+ jmp _int13_diskette_function
+
+int13_notfloppy:
+
+#if BX_USE_ATADRV
+
+ cmp dl, #0xE0
+ jb int13_notcdrom
+
+ // ebx is modified: BSD 5.2.1 boot loader problem
+ // someone should figure out which 32 bit register that actually are used
+
+ shr ebx, #16
+ push bx
+
+ call _int13_cdrom
+
+ pop bx
+ shl ebx, #16
+
+ jmp int13_out
+
+int13_notcdrom:
+
+#endif
+
+int13_disk:
+ ;; int13_harddisk modifies high word of EAX
+ shr eax, #16
+ push ax
+ call _int13_harddisk
+ pop ax
+ shl eax, #16
+
+int13_out:
+ pop ds
+ pop es
+ popa
+ iret
+
+;----------
+;- INT18h -
+;----------
+int18_handler: ;; Boot Failure recovery: try the next device.
+
+ ;; Reset SP and SS
+ mov ax, #0xfffe
+ mov sp, ax
+ xor ax, ax
+ mov ss, ax
+
+ ;; Get the boot sequence number out of the IPL memory
+ mov bx, #IPL_SEG
+ mov ds, bx ;; Set segment
+ mov bx, IPL_SEQUENCE_OFFSET ;; BX is now the sequence number
+ inc bx ;; ++
+ mov IPL_SEQUENCE_OFFSET, bx ;; Write it back
+ mov ds, ax ;; and reset the segment to zero.
+
+ ;; Carry on in the INT 19h handler, using the new sequence number
+ push bx
+
+ jmp int19_next_boot
+
+;----------
+;- INT19h -
+;----------
+int19_relocated: ;; Boot function, relocated
+
+ ;; int19 was beginning to be really complex, so now it
+ ;; just calls a C function that does the work
+
+ push bp
+ mov bp, sp
+
+ ;; Reset SS and SP
+ mov ax, #0xfffe
+ mov sp, ax
+ xor ax, ax
+ mov ss, ax
+
+ ;; Start from the first boot device (0, in AX)
+ mov bx, #IPL_SEG
+ mov ds, bx ;; Set segment to write to the IPL memory
+ mov IPL_SEQUENCE_OFFSET, ax ;; Save the sequence number
+ mov ds, ax ;; and reset the segment.
+
+ push ax
+
+int19_next_boot:
+
+ ;; Call the C code for the next boot device
+ call _int19_function
+
+ ;; Boot failed: invoke the boot recovery function
+ int #0x18
+
+;----------
+;- INT1Ch -
+;----------
+int1c_handler: ;; User Timer Tick
+ iret
+
+
+;----------------------
+;- POST: Floppy Drive -
+;----------------------
+floppy_drive_post:
+ xor ax, ax
+ mov ds, ax
+
+ mov al, #0x00
+ mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
+
+ mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
+
+ mov 0x0440, al ;; diskette motor timeout counter: not active
+ mov 0x0441, al ;; diskette controller status return code
+
+ mov 0x0442, al ;; disk & diskette controller status register 0
+ mov 0x0443, al ;; diskette controller status register 1
+ mov 0x0444, al ;; diskette controller status register 2
+ mov 0x0445, al ;; diskette controller cylinder number
+ mov 0x0446, al ;; diskette controller head number
+ mov 0x0447, al ;; diskette controller sector number
+ mov 0x0448, al ;; diskette controller bytes written
+
+ mov 0x048b, al ;; diskette configuration data
+
+ ;; -----------------------------------------------------------------
+ ;; (048F) diskette controller information
+ ;;
+ mov al, #0x10 ;; get CMOS diskette drive type
+ out 0x70, AL
+ in AL, 0x71
+ mov ah, al ;; save byte to AH
+
+look_drive0:
+ shr al, #4 ;; look at top 4 bits for drive 0
+ jz f0_missing ;; jump if no drive0
+ mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
+ jmp look_drive1
+f0_missing:
+ mov bl, #0x00 ;; no drive0
+
+look_drive1:
+ mov al, ah ;; restore from AH
+ and al, #0x0f ;; look at bottom 4 bits for drive 1
+ jz f1_missing ;; jump if no drive1
+ or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
+f1_missing:
+ ;; leave high bits in BL zerod
+ mov 0x048f, bl ;; put new val in BDA (diskette controller information)
+ ;; -----------------------------------------------------------------
+
+ mov al, #0x00
+ mov 0x0490, al ;; diskette 0 media state
+ mov 0x0491, al ;; diskette 1 media state
+
+ ;; diskette 0,1 operational starting state
+ ;; drive type has not been determined,
+ ;; has no changed detection line
+ mov 0x0492, al
+ mov 0x0493, al
+
+ mov 0x0494, al ;; diskette 0 current cylinder
+ mov 0x0495, al ;; diskette 1 current cylinder
+
+ mov al, #0x02
+ out #0x0a, al ;; clear DMA-1 channel 2 mask bit
+
+ SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
+ SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
+ SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
+
+ ret
+
+
+;--------------------
+;- POST: HARD DRIVE -
+;--------------------
+; relocated here because the primary POST area isnt big enough.
+hard_drive_post:
+ // IRQ 14 = INT 76h
+ // INT 76h calls INT 15h function ax=9100
+
+ mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
+ mov dx, #0x03f6
+ out dx, al
+
+ xor ax, ax
+ mov ds, ax
+ mov 0x0474, al /* hard disk status of last operation */
+ mov 0x0477, al /* hard disk port offset (XT only ???) */
+ mov 0x048c, al /* hard disk status register */
+ mov 0x048d, al /* hard disk error register */
+ mov 0x048e, al /* hard disk task complete flag */
+ mov al, #0x01
+ mov 0x0475, al /* hard disk number attached */
+ mov al, #0xc0
+ mov 0x0476, al /* hard disk control byte */
+ SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
+ SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
+ ;; INT 41h: hard disk 0 configuration pointer
+ ;; INT 46h: hard disk 1 configuration pointer
+ SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
+ SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
+
+ ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
+ mov al, #0x12
+ out #0x70, al
+ in al, #0x71
+ and al, #0xf0
+ cmp al, #0xf0
+ je post_d0_extended
+ jmp check_for_hd1
+post_d0_extended:
+ mov al, #0x19
+ out #0x70, al
+ in al, #0x71
+ cmp al, #47 ;; decimal 47 - user definable
+ je post_d0_type47
+ HALT(__LINE__)
+post_d0_type47:
+ ;; CMOS purpose param table offset
+ ;; 1b cylinders low 0
+ ;; 1c cylinders high 1
+ ;; 1d heads 2
+ ;; 1e write pre-comp low 5
+ ;; 1f write pre-comp high 6
+ ;; 20 retries/bad map/heads>8 8
+ ;; 21 landing zone low C
+ ;; 22 landing zone high D
+ ;; 23 sectors/track E
+
+ mov ax, #EBDA_SEG
+ mov ds, ax
+
+ ;;; Filling EBDA table for hard disk 0.
+ mov al, #0x1f
+ out #0x70, al
+ in al, #0x71
+ mov ah, al
+ mov al, #0x1e
+ out #0x70, al
+ in al, #0x71
+ mov (0x003d + 0x05), ax ;; write precomp word
+
+ mov al, #0x20
+ out #0x70, al
+ in al, #0x71
+ mov (0x003d + 0x08), al ;; drive control byte
+
+ mov al, #0x22
+ out #0x70, al
+ in al, #0x71
+ mov ah, al
+ mov al, #0x21
+ out #0x70, al
+ in al, #0x71
+ mov (0x003d + 0x0C), ax ;; landing zone word
+
+ mov al, #0x1c ;; get cylinders word in AX
+ out #0x70, al
+ in al, #0x71 ;; high byte
+ mov ah, al
+ mov al, #0x1b
+ out #0x70, al
+ in al, #0x71 ;; low byte
+ mov bx, ax ;; BX = cylinders
+
+ mov al, #0x1d
+ out #0x70, al
+ in al, #0x71
+ mov cl, al ;; CL = heads
+
+ mov al, #0x23
+ out #0x70, al
+ in al, #0x71
+ mov dl, al ;; DL = sectors
+
+ cmp bx, #1024
+ jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
+
+hd0_post_physical_chs:
+ ;; no logical CHS mapping used, just physical CHS
+ ;; use Standard Fixed Disk Parameter Table (FDPT)
+ mov (0x003d + 0x00), bx ;; number of physical cylinders
+ mov (0x003d + 0x02), cl ;; number of physical heads
+ mov (0x003d + 0x0E), dl ;; number of physical sectors
+ jmp check_for_hd1
+
+hd0_post_logical_chs:
+ ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
+ mov (0x003d + 0x09), bx ;; number of physical cylinders
+ mov (0x003d + 0x0b), cl ;; number of physical heads
+ mov (0x003d + 0x04), dl ;; number of physical sectors
+ mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
+ mov al, #0xa0
+ mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
+
+ cmp bx, #2048
+ jnbe hd0_post_above_2048
+ ;; 1024 < c <= 2048 cylinders
+ shr bx, #0x01
+ shl cl, #0x01
+ jmp hd0_post_store_logical
+
+hd0_post_above_2048:
+ cmp bx, #4096
+ jnbe hd0_post_above_4096
+ ;; 2048 < c <= 4096 cylinders
+ shr bx, #0x02
+ shl cl, #0x02
+ jmp hd0_post_store_logical
+
+hd0_post_above_4096:
+ cmp bx, #8192
+ jnbe hd0_post_above_8192
+ ;; 4096 < c <= 8192 cylinders
+ shr bx, #0x03
+ shl cl, #0x03
+ jmp hd0_post_store_logical
+
+hd0_post_above_8192:
+ ;; 8192 < c <= 16384 cylinders
+ shr bx, #0x04
+ shl cl, #0x04
+
+hd0_post_store_logical:
+ mov (0x003d + 0x00), bx ;; number of physical cylinders
+ mov (0x003d + 0x02), cl ;; number of physical heads
+ ;; checksum
+ mov cl, #0x0f ;; repeat count
+ mov si, #0x003d ;; offset to disk0 FDPT
+ mov al, #0x00 ;; sum
+hd0_post_checksum_loop:
+ add al, [si]
+ inc si
+ dec cl
+ jnz hd0_post_checksum_loop
+ not al ;; now take 2s complement
+ inc al
+ mov [si], al
+;;; Done filling EBDA table for hard disk 0.
+
+
+check_for_hd1:
+ ;; is there really a second hard disk? if not, return now
+ mov al, #0x12
+ out #0x70, al
+ in al, #0x71
+ and al, #0x0f
+ jnz post_d1_exists
+ ret
+post_d1_exists:
+ ;; check that the hd type is really 0x0f.
+ cmp al, #0x0f
+ jz post_d1_extended
+ HALT(__LINE__)
+post_d1_extended:
+ ;; check that the extended type is 47 - user definable
+ mov al, #0x1a
+ out #0x70, al
+ in al, #0x71
+ cmp al, #47 ;; decimal 47 - user definable
+ je post_d1_type47
+ HALT(__LINE__)
+post_d1_type47:
+ ;; Table for disk1.
+ ;; CMOS purpose param table offset
+ ;; 0x24 cylinders low 0
+ ;; 0x25 cylinders high 1
+ ;; 0x26 heads 2
+ ;; 0x27 write pre-comp low 5
+ ;; 0x28 write pre-comp high 6
+ ;; 0x29 heads>8 8
+ ;; 0x2a landing zone low C
+ ;; 0x2b landing zone high D
+ ;; 0x2c sectors/track E
+;;; Fill EBDA table for hard disk 1.
+ mov ax, #EBDA_SEG
+ mov ds, ax
+ mov al, #0x28
+ out #0x70, al
+ in al, #0x71
+ mov ah, al
+ mov al, #0x27
+ out #0x70, al
+ in al, #0x71
+ mov (0x004d + 0x05), ax ;; write precomp word
+
+ mov al, #0x29
+ out #0x70, al
+ in al, #0x71
+ mov (0x004d + 0x08), al ;; drive control byte
+
+ mov al, #0x2b
+ out #0x70, al
+ in al, #0x71
+ mov ah, al
+ mov al, #0x2a
+ out #0x70, al
+ in al, #0x71
+ mov (0x004d + 0x0C), ax ;; landing zone word
+
+ mov al, #0x25 ;; get cylinders word in AX
+ out #0x70, al
+ in al, #0x71 ;; high byte
+ mov ah, al
+ mov al, #0x24
+ out #0x70, al
+ in al, #0x71 ;; low byte
+ mov bx, ax ;; BX = cylinders
+
+ mov al, #0x26
+ out #0x70, al
+ in al, #0x71
+ mov cl, al ;; CL = heads
+
+ mov al, #0x2c
+ out #0x70, al
+ in al, #0x71
+ mov dl, al ;; DL = sectors
+
+ cmp bx, #1024
+ jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
+
+hd1_post_physical_chs:
+ ;; no logical CHS mapping used, just physical CHS
+ ;; use Standard Fixed Disk Parameter Table (FDPT)
+ mov (0x004d + 0x00), bx ;; number of physical cylinders
+ mov (0x004d + 0x02), cl ;; number of physical heads
+ mov (0x004d + 0x0E), dl ;; number of physical sectors
+ ret
+
+hd1_post_logical_chs:
+ ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
+ mov (0x004d + 0x09), bx ;; number of physical cylinders
+ mov (0x004d + 0x0b), cl ;; number of physical heads
+ mov (0x004d + 0x04), dl ;; number of physical sectors
+ mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
+ mov al, #0xa0
+ mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
+
+ cmp bx, #2048
+ jnbe hd1_post_above_2048
+ ;; 1024 < c <= 2048 cylinders
+ shr bx, #0x01
+ shl cl, #0x01
+ jmp hd1_post_store_logical
+
+hd1_post_above_2048:
+ cmp bx, #4096
+ jnbe hd1_post_above_4096
+ ;; 2048 < c <= 4096 cylinders
+ shr bx, #0x02
+ shl cl, #0x02
+ jmp hd1_post_store_logical
+
+hd1_post_above_4096:
+ cmp bx, #8192
+ jnbe hd1_post_above_8192
+ ;; 4096 < c <= 8192 cylinders
+ shr bx, #0x03
+ shl cl, #0x03
+ jmp hd1_post_store_logical
+
+hd1_post_above_8192:
+ ;; 8192 < c <= 16384 cylinders
+ shr bx, #0x04
+ shl cl, #0x04
+
+hd1_post_store_logical:
+ mov (0x004d + 0x00), bx ;; number of physical cylinders
+ mov (0x004d + 0x02), cl ;; number of physical heads
+ ;; checksum
+ mov cl, #0x0f ;; repeat count
+ mov si, #0x004d ;; offset to disk0 FDPT
+ mov al, #0x00 ;; sum
+hd1_post_checksum_loop:
+ add al, [si]
+ inc si
+ dec cl
+ jnz hd1_post_checksum_loop
+ not al ;; now take 2s complement
+ inc al
+ mov [si], al
+;;; Done filling EBDA table for hard disk 1.
+
+ ret
+
+;--------------------
+;- POST: EBDA segment
+;--------------------
+; relocated here because the primary POST area isnt big enough.
+ebda_post:
+#if BX_USE_EBDA
+ mov ax, #EBDA_SEG
+ mov ds, ax
+ mov byte ptr [0x0], #EBDA_SIZE
+#endif
+ xor ax, ax ; mov EBDA seg into 40E
+ mov ds, ax
+ mov word ptr [0x40E], #EBDA_SEG
+ ret;;
+
+;--------------------
+;- POST: EOI + jmp via [0x40:67)
+;--------------------
+; relocated here because the primary POST area isnt big enough.
+eoi_jmp_post:
+ mov al, #0x20
+ out #0xA0, al ;; slave PIC EOI
+ mov al, #0x20
+ out #0x20, al ;; master PIC EOI
+
+jmp_post_0x467:
+ xor ax, ax
+ mov ds, ax
+
+ jmp far ptr [0x467]
+
+iret_post_0x467:
+ xor ax, ax
+ mov ds, ax
+
+ mov sp, [0x467]
+ mov ss, [0x469]
+ iret
+
+retf_post_0x467:
+ xor ax, ax
+ mov ds, ax
+
+ mov sp, [0x467]
+ mov ss, [0x469]
+ retf
+
+s3_post:
+ mov sp, #0xffe
+#if BX_ROMBIOS32
+ call rombios32_init
+#endif
+ call _s3_resume
+ mov bl, #0x00
+ and ax, ax
+ jz normal_post
+ call _s3_resume_panic
+
+;--------------------
+eoi_both_pics:
+ mov al, #0x20
+ out #0xA0, al ;; slave PIC EOI
+eoi_master_pic:
+ mov al, #0x20
+ out #0x20, al ;; master PIC EOI
+ ret
+
+;--------------------
+BcdToBin:
+ ;; in: AL in BCD format
+ ;; out: AL in binary format, AH will always be 0
+ ;; trashes BX
+ mov bl, al
+ and bl, #0x0f ;; bl has low digit
+ shr al, #4 ;; al has high digit
+ mov bh, #10
+ mul al, bh ;; multiply high digit by 10 (result in AX)
+ add al, bl ;; then add low digit
+ ret
+
+;--------------------
+timer_tick_post:
+ ;; Setup the Timer Ticks Count (0x46C:dword) and
+ ;; Timer Ticks Roller Flag (0x470:byte)
+ ;; The Timer Ticks Count needs to be set according to
+ ;; the current CMOS time, as if ticks have been occurring
+ ;; at 18.2hz since midnight up to this point. Calculating
+ ;; this is a little complicated. Here are the factors I gather
+ ;; regarding this. 14,318,180 hz was the original clock speed,
+ ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
+ ;; at the time, or 4 to drive the CGA video adapter. The div3
+ ;; source was divided again by 4 to feed a 1.193Mhz signal to
+ ;; the timer. With a maximum 16bit timer count, this is again
+ ;; divided down by 65536 to 18.2hz.
+ ;;
+ ;; 14,318,180 Hz clock
+ ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
+ ;; /4 = 1,193,181 Hz fed to timer
+ ;; /65536 (maximum timer count) = 18.20650736 ticks/second
+ ;; 1 second = 18.20650736 ticks
+ ;; 1 minute = 1092.390442 ticks
+ ;; 1 hour = 65543.42651 ticks
+ ;;
+ ;; Given the values in the CMOS clock, one could calculate
+ ;; the number of ticks by the following:
+ ;; ticks = (BcdToBin(seconds) * 18.206507) +
+ ;; (BcdToBin(minutes) * 1092.3904)
+ ;; (BcdToBin(hours) * 65543.427)
+ ;; To get a little more accuracy, since Im using integer
+ ;; arithmatic, I use:
+ ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
+ ;; (BcdToBin(minutes) * 10923904) / 10000 +
+ ;; (BcdToBin(hours) * 65543427) / 1000
+
+ ;; assuming DS=0000
+
+ ;; get CMOS seconds
+ xor eax, eax ;; clear EAX
+ mov al, #0x00
+ out #0x70, al
+ in al, #0x71 ;; AL has CMOS seconds in BCD
+ call BcdToBin ;; EAX now has seconds in binary
+ mov edx, #18206507
+ mul eax, edx
+ mov ebx, #1000000
+ xor edx, edx
+ div eax, ebx
+ mov ecx, eax ;; ECX will accumulate total ticks
+
+ ;; get CMOS minutes
+ xor eax, eax ;; clear EAX
+ mov al, #0x02
+ out #0x70, al
+ in al, #0x71 ;; AL has CMOS minutes in BCD
+ call BcdToBin ;; EAX now has minutes in binary
+ mov edx, #10923904
+ mul eax, edx
+ mov ebx, #10000
+ xor edx, edx
+ div eax, ebx
+ add ecx, eax ;; add to total ticks
+
+ ;; get CMOS hours
+ xor eax, eax ;; clear EAX
+ mov al, #0x04
+ out #0x70, al
+ in al, #0x71 ;; AL has CMOS hours in BCD
+ call BcdToBin ;; EAX now has hours in binary
+ mov edx, #65543427
+ mul eax, edx
+ mov ebx, #1000
+ xor edx, edx
+ div eax, ebx
+ add ecx, eax ;; add to total ticks
+
+ mov 0x46C, ecx ;; Timer Ticks Count
+ xor al, al
+ mov 0x470, al ;; Timer Ticks Rollover Flag
+ ret
+
+;--------------------
+int76_handler:
+ ;; record completion in BIOS task complete flag
+ push ax
+ push ds
+ mov ax, #0x0040
+ mov ds, ax
+ mov 0x008E, #0xff
+ call eoi_both_pics
+ pop ds
+ pop ax
+ iret
+
+
+;--------------------
+#if BX_APM
+
+use32 386
+#define APM_PROT32
+#include "apmbios.S"
+
+use16 386
+#define APM_PROT16
+#include "apmbios.S"
+
+#define APM_REAL
+#include "apmbios.S"
+
+#endif
+
+;--------------------
+#if BX_PCIBIOS
+use32 386
+.align 16
+bios32_structure:
+ db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
+ dw bios32_entry_point, 0xf ;; 32 bit physical address
+ db 0 ;; revision level
+ ;; length in paragraphs and checksum stored in a word to prevent errors
+ dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
+ & 0xff) << 8) + 0x01
+ db 0,0,0,0,0 ;; reserved
+
+.align 16
+bios32_entry_point:
+ pushfd
+ cmp eax, #0x49435024 ;; "$PCI"
+ jne unknown_service
+ mov eax, #0x80000000
+ mov dx, #0x0cf8
+ out dx, eax
+ mov dx, #0x0cfc
+ in eax, dx
+#ifdef PCI_FIXED_HOST_BRIDGE
+ cmp eax, #PCI_FIXED_HOST_BRIDGE
+ jne unknown_service
+#else
+ ;; say ok if a device is present
+ cmp eax, #0xffffffff
+ je unknown_service
+#endif
+ mov ebx, #0x000f0000
+ mov ecx, #0
+ mov edx, #pcibios_protected
+ xor al, al
+ jmp bios32_end
+unknown_service:
+ mov al, #0x80
+bios32_end:
+#ifdef BX_QEMU
+ and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
+#endif
+ popfd
+ retf
+
+.align 16
+pcibios_protected:
+ pushfd
+ cli
+ push esi
+ push edi
+ cmp al, #0x01 ;; installation check
+ jne pci_pro_f02
+ mov bx, #0x0210
+ mov cx, #0
+ mov edx, #0x20494350 ;; "PCI "
+ mov al, #0x01
+ jmp pci_pro_ok
+pci_pro_f02: ;; find pci device
+ cmp al, #0x02
+ jne pci_pro_f03
+ shl ecx, #16
+ mov cx, dx
+ xor bx, bx
+ mov di, #0x00
+pci_pro_devloop:
+ call pci_pro_select_reg
+ mov dx, #0x0cfc
+ in eax, dx
+ cmp eax, ecx
+ jne pci_pro_nextdev
+ cmp si, #0
+ je pci_pro_ok
+ dec si
+pci_pro_nextdev:
+ inc bx
+ cmp bx, #0x0100
+ jne pci_pro_devloop
+ mov ah, #0x86
+ jmp pci_pro_fail
+pci_pro_f03: ;; find class code
+ cmp al, #0x03
+ jne pci_pro_f08
+ xor bx, bx
+ mov di, #0x08
+pci_pro_devloop2:
+ call pci_pro_select_reg
+ mov dx, #0x0cfc
+ in eax, dx
+ shr eax, #8
+ cmp eax, ecx
+ jne pci_pro_nextdev2
+ cmp si, #0
+ je pci_pro_ok
+ dec si
+pci_pro_nextdev2:
+ inc bx
+ cmp bx, #0x0100
+ jne pci_pro_devloop2
+ mov ah, #0x86
+ jmp pci_pro_fail
+pci_pro_f08: ;; read configuration byte
+ cmp al, #0x08
+ jne pci_pro_f09
+ call pci_pro_select_reg
+ push edx
+ mov dx, di
+ and dx, #0x03
+ add dx, #0x0cfc
+ in al, dx
+ pop edx
+ mov cl, al
+ jmp pci_pro_ok
+pci_pro_f09: ;; read configuration word
+ cmp al, #0x09
+ jne pci_pro_f0a
+ call pci_pro_select_reg
+ push edx
+ mov dx, di
+ and dx, #0x02
+ add dx, #0x0cfc
+ in ax, dx
+ pop edx
+ mov cx, ax
+ jmp pci_pro_ok
+pci_pro_f0a: ;; read configuration dword
+ cmp al, #0x0a
+ jne pci_pro_f0b
+ call pci_pro_select_reg
+ push edx
+ mov dx, #0x0cfc
+ in eax, dx
+ pop edx
+ mov ecx, eax
+ jmp pci_pro_ok
+pci_pro_f0b: ;; write configuration byte
+ cmp al, #0x0b
+ jne pci_pro_f0c
+ call pci_pro_select_reg
+ push edx
+ mov dx, di
+ and dx, #0x03
+ add dx, #0x0cfc
+ mov al, cl
+ out dx, al
+ pop edx
+ jmp pci_pro_ok
+pci_pro_f0c: ;; write configuration word
+ cmp al, #0x0c
+ jne pci_pro_f0d
+ call pci_pro_select_reg
+ push edx
+ mov dx, di
+ and dx, #0x02
+ add dx, #0x0cfc
+ mov ax, cx
+ out dx, ax
+ pop edx
+ jmp pci_pro_ok
+pci_pro_f0d: ;; write configuration dword
+ cmp al, #0x0d
+ jne pci_pro_unknown
+ call pci_pro_select_reg
+ push edx
+ mov dx, #0x0cfc
+ mov eax, ecx
+ out dx, eax
+ pop edx
+ jmp pci_pro_ok
+pci_pro_unknown:
+ mov ah, #0x81
+pci_pro_fail:
+ pop edi
+ pop esi
+#ifdef BX_QEMU
+ and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
+#endif
+ popfd
+ stc
+ retf
+pci_pro_ok:
+ xor ah, ah
+ pop edi
+ pop esi
+#ifdef BX_QEMU
+ and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
+#endif
+ popfd
+ clc
+ retf
+
+pci_pro_select_reg:
+ push edx
+ mov eax, #0x800000
+ mov ax, bx
+ shl eax, #8
+ and di, #0xff
+ or ax, di
+ and al, #0xfc
+ mov dx, #0x0cf8
+ out dx, eax
+ pop edx
+ ret
+
+use16 386
+
+pcibios_real:
+ push eax
+ push dx
+ mov eax, #0x80000000
+ mov dx, #0x0cf8
+ out dx, eax
+ mov dx, #0x0cfc
+ in eax, dx
+#ifdef PCI_FIXED_HOST_BRIDGE
+ cmp eax, #PCI_FIXED_HOST_BRIDGE
+ je pci_present
+#else
+ ;; say ok if a device is present
+ cmp eax, #0xffffffff
+ jne pci_present
+#endif
+ pop dx
+ pop eax
+ mov ah, #0xff
+ stc
+ ret
+pci_present:
+ pop dx
+ pop eax
+ cmp al, #0x01 ;; installation check
+ jne pci_real_f02
+ mov ax, #0x0001
+ mov bx, #0x0210
+ mov cx, #0
+ mov edx, #0x20494350 ;; "PCI "
+ mov edi, #0xf0000
+ mov di, #pcibios_protected
+ clc
+ ret
+pci_real_f02: ;; find pci device
+ push esi
+ push edi
+ cmp al, #0x02
+ jne pci_real_f03
+ shl ecx, #16
+ mov cx, dx
+ xor bx, bx
+ mov di, #0x00
+pci_real_devloop:
+ call pci_real_select_reg
+ mov dx, #0x0cfc
+ in eax, dx
+ cmp eax, ecx
+ jne pci_real_nextdev
+ cmp si, #0
+ je pci_real_ok
+ dec si
+pci_real_nextdev:
+ inc bx
+ cmp bx, #0x0100
+ jne pci_real_devloop
+ mov dx, cx
+ shr ecx, #16
+ mov ax, #0x8602
+ jmp pci_real_fail
+pci_real_f03: ;; find class code
+ cmp al, #0x03
+ jne pci_real_f08
+ xor bx, bx
+ mov di, #0x08
+pci_real_devloop2:
+ call pci_real_select_reg
+ mov dx, #0x0cfc
+ in eax, dx
+ shr eax, #8
+ cmp eax, ecx
+ jne pci_real_nextdev2
+ cmp si, #0
+ je pci_real_ok
+ dec si
+pci_real_nextdev2:
+ inc bx
+ cmp bx, #0x0100
+ jne pci_real_devloop2
+ mov dx, cx
+ shr ecx, #16
+ mov ax, #0x8603
+ jmp pci_real_fail
+pci_real_f08: ;; read configuration byte
+ cmp al, #0x08
+ jne pci_real_f09
+ call pci_real_select_reg
+ push dx
+ mov dx, di
+ and dx, #0x03
+ add dx, #0x0cfc
+ in al, dx
+ pop dx
+ mov cl, al
+ jmp pci_real_ok
+pci_real_f09: ;; read configuration word
+ cmp al, #0x09
+ jne pci_real_f0a
+ call pci_real_select_reg
+ push dx
+ mov dx, di
+ and dx, #0x02
+ add dx, #0x0cfc
+ in ax, dx
+ pop dx
+ mov cx, ax
+ jmp pci_real_ok
+pci_real_f0a: ;; read configuration dword
+ cmp al, #0x0a
+ jne pci_real_f0b
+ call pci_real_select_reg
+ push dx
+ mov dx, #0x0cfc
+ in eax, dx
+ pop dx
+ mov ecx, eax
+ jmp pci_real_ok
+pci_real_f0b: ;; write configuration byte
+ cmp al, #0x0b
+ jne pci_real_f0c
+ call pci_real_select_reg
+ push dx
+ mov dx, di
+ and dx, #0x03
+ add dx, #0x0cfc
+ mov al, cl
+ out dx, al
+ pop dx
+ jmp pci_real_ok
+pci_real_f0c: ;; write configuration word
+ cmp al, #0x0c
+ jne pci_real_f0d
+ call pci_real_select_reg
+ push dx
+ mov dx, di
+ and dx, #0x02
+ add dx, #0x0cfc
+ mov ax, cx
+ out dx, ax
+ pop dx
+ jmp pci_real_ok
+pci_real_f0d: ;; write configuration dword
+ cmp al, #0x0d
+ jne pci_real_f0e
+ call pci_real_select_reg
+ push dx
+ mov dx, #0x0cfc
+ mov eax, ecx
+ out dx, eax
+ pop dx
+ jmp pci_real_ok
+pci_real_f0e: ;; get irq routing options
+ cmp al, #0x0e
+ jne pci_real_unknown
+ SEG ES
+ cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
+ jb pci_real_too_small
+ SEG ES
+ mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
+ pushf
+ push ds
+ push es
+ push cx
+ push si
+ push di
+ cld
+ mov si, #pci_routing_table_structure_start
+ push cs
+ pop ds
+ SEG ES
+ mov cx, [di+2]
+ SEG ES
+ mov es, [di+4]
+ mov di, cx
+ mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
+ rep
+ movsb
+ pop di
+ pop si
+ pop cx
+ pop es
+ pop ds
+ popf
+ mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
+ jmp pci_real_ok
+pci_real_too_small:
+ SEG ES
+ mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
+ mov ah, #0x89
+ jmp pci_real_fail
+
+pci_real_unknown:
+ mov ah, #0x81
+pci_real_fail:
+ pop edi
+ pop esi
+ stc
+ ret
+pci_real_ok:
+ xor ah, ah
+ pop edi
+ pop esi
+ clc
+ ret
+
+pci_real_select_reg:
+ push dx
+ mov eax, #0x800000
+ mov ax, bx
+ shl eax, #8
+ and di, #0xff
+ or ax, di
+ and al, #0xfc
+ mov dx, #0x0cf8
+ out dx, eax
+ pop dx
+ ret
+
+.align 16
+pci_routing_table_structure:
+ db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
+ db 0, 1 ;; version
+ dw 32 + (6 * 16) ;; table size
+ db 0 ;; PCI interrupt router bus
+ db 0x08 ;; PCI interrupt router DevFunc
+ dw 0x0000 ;; PCI exclusive IRQs
+ dw 0x8086 ;; compatible PCI interrupt router vendor ID
+ dw 0x122e ;; compatible PCI interrupt router device ID
+ dw 0,0 ;; Miniport data
+ db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
+ db 0x37 ;; checksum
+pci_routing_table_structure_start:
+ ;; first slot entry PCI-to-ISA (embedded)
+ db 0 ;; pci bus number
+ db 0x08 ;; pci device number (bit 7-3)
+ db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
+ dw 0xdef8 ;; IRQ bitmap INTA#
+ db 0x61 ;; link value INTB#
+ dw 0xdef8 ;; IRQ bitmap INTB#
+ db 0x62 ;; link value INTC#
+ dw 0xdef8 ;; IRQ bitmap INTC#
+ db 0x63 ;; link value INTD#
+ dw 0xdef8 ;; IRQ bitmap INTD#
+ db 0 ;; physical slot (0 = embedded)
+ db 0 ;; reserved
+ ;; second slot entry: 1st PCI slot
+ db 0 ;; pci bus number
+ db 0x10 ;; pci device number (bit 7-3)
+ db 0x61 ;; link value INTA#
+ dw 0xdef8 ;; IRQ bitmap INTA#
+ db 0x62 ;; link value INTB#
+ dw 0xdef8 ;; IRQ bitmap INTB#
+ db 0x63 ;; link value INTC#
+ dw 0xdef8 ;; IRQ bitmap INTC#
+ db 0x60 ;; link value INTD#
+ dw 0xdef8 ;; IRQ bitmap INTD#
+ db 1 ;; physical slot (0 = embedded)
+ db 0 ;; reserved
+ ;; third slot entry: 2nd PCI slot
+ db 0 ;; pci bus number
+ db 0x18 ;; pci device number (bit 7-3)
+ db 0x62 ;; link value INTA#
+ dw 0xdef8 ;; IRQ bitmap INTA#
+ db 0x63 ;; link value INTB#
+ dw 0xdef8 ;; IRQ bitmap INTB#
+ db 0x60 ;; link value INTC#
+ dw 0xdef8 ;; IRQ bitmap INTC#
+ db 0x61 ;; link value INTD#
+ dw 0xdef8 ;; IRQ bitmap INTD#
+ db 2 ;; physical slot (0 = embedded)
+ db 0 ;; reserved
+ ;; 4th slot entry: 3rd PCI slot
+ db 0 ;; pci bus number
+ db 0x20 ;; pci device number (bit 7-3)
+ db 0x63 ;; link value INTA#
+ dw 0xdef8 ;; IRQ bitmap INTA#
+ db 0x60 ;; link value INTB#
+ dw 0xdef8 ;; IRQ bitmap INTB#
+ db 0x61 ;; link value INTC#
+ dw 0xdef8 ;; IRQ bitmap INTC#
+ db 0x62 ;; link value INTD#
+ dw 0xdef8 ;; IRQ bitmap INTD#
+ db 3 ;; physical slot (0 = embedded)
+ db 0 ;; reserved
+ ;; 5th slot entry: 4rd PCI slot
+ db 0 ;; pci bus number
+ db 0x28 ;; pci device number (bit 7-3)
+ db 0x60 ;; link value INTA#
+ dw 0xdef8 ;; IRQ bitmap INTA#
+ db 0x61 ;; link value INTB#
+ dw 0xdef8 ;; IRQ bitmap INTB#
+ db 0x62 ;; link value INTC#
+ dw 0xdef8 ;; IRQ bitmap INTC#
+ db 0x63 ;; link value INTD#
+ dw 0xdef8 ;; IRQ bitmap INTD#
+ db 4 ;; physical slot (0 = embedded)
+ db 0 ;; reserved
+ ;; 6th slot entry: 5rd PCI slot
+ db 0 ;; pci bus number
+ db 0x30 ;; pci device number (bit 7-3)
+ db 0x61 ;; link value INTA#
+ dw 0xdef8 ;; IRQ bitmap INTA#
+ db 0x62 ;; link value INTB#
+ dw 0xdef8 ;; IRQ bitmap INTB#
+ db 0x63 ;; link value INTC#
+ dw 0xdef8 ;; IRQ bitmap INTC#
+ db 0x60 ;; link value INTD#
+ dw 0xdef8 ;; IRQ bitmap INTD#
+ db 5 ;; physical slot (0 = embedded)
+ db 0 ;; reserved
+pci_routing_table_structure_end:
+
+#if !BX_ROMBIOS32
+pci_irq_list:
+ db 11, 10, 9, 5;
+
+pcibios_init_sel_reg:
+ push eax
+ mov eax, #0x800000
+ mov ax, bx
+ shl eax, #8
+ and dl, #0xfc
+ or al, dl
+ mov dx, #0x0cf8
+ out dx, eax
+ pop eax
+ ret
+
+pcibios_init_iomem_bases:
+ push bp
+ mov bp, sp
+ mov eax, #0xe0000000 ;; base for memory init
+ push eax
+ mov ax, #0xc000 ;; base for i/o init
+ push ax
+ mov ax, #0x0010 ;; start at base address #0
+ push ax
+ mov bx, #0x0008
+pci_init_io_loop1:
+ mov dl, #0x00
+ call pcibios_init_sel_reg
+ mov dx, #0x0cfc
+ in ax, dx
+ cmp ax, #0xffff
+ jz next_pci_dev
+ mov dl, #0x04 ;; disable i/o and memory space access
+ call pcibios_init_sel_reg
+ mov dx, #0x0cfc
+ in al, dx
+ and al, #0xfc
+ out dx, al
+pci_init_io_loop2:
+ mov dl, [bp-8]
+ call pcibios_init_sel_reg
+ mov dx, #0x0cfc
+ in eax, dx
+ test al, #0x01
+ jnz init_io_base
+ mov ecx, eax
+ mov eax, #0xffffffff
+ out dx, eax
+ in eax, dx
+ cmp eax, ecx
+ je next_pci_base
+ xor eax, #0xffffffff
+ mov ecx, eax
+ mov eax, [bp-4]
+ out dx, eax
+ add eax, ecx ;; calculate next free mem base
+ add eax, #0x01000000
+ and eax, #0xff000000
+ mov [bp-4], eax
+ jmp next_pci_base
+init_io_base:
+ mov cx, ax
+ mov ax, #0xffff
+ out dx, ax
+ in ax, dx
+ cmp ax, cx
+ je next_pci_base
+ xor ax, #0xfffe
+ mov cx, ax
+ mov ax, [bp-6]
+ out dx, ax
+ add ax, cx ;; calculate next free i/o base
+ add ax, #0x0100
+ and ax, #0xff00
+ mov [bp-6], ax
+next_pci_base:
+ mov al, [bp-8]
+ add al, #0x04
+ cmp al, #0x28
+ je enable_iomem_space
+ mov byte ptr[bp-8], al
+ jmp pci_init_io_loop2
+enable_iomem_space:
+ mov dl, #0x04 ;; enable i/o and memory space access if available
+ call pcibios_init_sel_reg
+ mov dx, #0x0cfc
+ in al, dx
+ or al, #0x07
+ out dx, al
+next_pci_dev:
+ mov byte ptr[bp-8], #0x10
+ inc bx
+ cmp bx, #0x0100
+ jne pci_init_io_loop1
+ mov sp, bp
+ pop bp
+ ret
+
+pcibios_init_set_elcr:
+ push ax
+ push cx
+ mov dx, #0x04d0
+ test al, #0x08
+ jz is_master_pic
+ inc dx
+ and al, #0x07
+is_master_pic:
+ mov cl, al
+ mov bl, #0x01
+ shl bl, cl
+ in al, dx
+ or al, bl
+ out dx, al
+ pop cx
+ pop ax
+ ret
+
+pcibios_init_irqs:
+ push ds
+ push bp
+ mov ax, #0xf000
+ mov ds, ax
+ mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
+ mov al, #0x00
+ out dx, al
+ inc dx
+ out dx, al
+ mov si, #pci_routing_table_structure
+ mov bh, [si+8]
+ mov bl, [si+9]
+ mov dl, #0x00
+ call pcibios_init_sel_reg
+ mov dx, #0x0cfc
+ in ax, dx
+ cmp ax, [si+12] ;; check irq router
+ jne pci_init_end
+ mov dl, [si+34]
+ call pcibios_init_sel_reg
+ push bx ;; save irq router bus + devfunc
+ mov dx, #0x0cfc
+ mov ax, #0x8080
+ out dx, ax ;; reset PIRQ route control
+ add dx, #2
+ out dx, ax
+ mov ax, [si+6]
+ sub ax, #0x20
+ shr ax, #4
+ mov cx, ax
+ add si, #0x20 ;; set pointer to 1st entry
+ mov bp, sp
+ mov ax, #pci_irq_list
+ push ax
+ xor ax, ax
+ push ax
+pci_init_irq_loop1:
+ mov bh, [si]
+ mov bl, [si+1]
+pci_init_irq_loop2:
+ mov dl, #0x00
+ call pcibios_init_sel_reg
+ mov dx, #0x0cfc
+ in ax, dx
+ cmp ax, #0xffff
+ jnz pci_test_int_pin
+ test bl, #0x07
+ jz next_pir_entry
+ jmp next_pci_func
+pci_test_int_pin:
+ mov dl, #0x3c
+ call pcibios_init_sel_reg
+ mov dx, #0x0cfd
+ in al, dx
+ and al, #0x07
+ jz next_pci_func
+ dec al ;; determine pirq reg
+ mov dl, #0x03
+ mul al, dl
+ add al, #0x02
+ xor ah, ah
+ mov bx, ax
+ mov al, [si+bx]
+ mov dl, al
+ mov bx, [bp]
+ call pcibios_init_sel_reg
+ mov dx, #0x0cfc
+ and al, #0x03
+ add dl, al
+ in al, dx
+ cmp al, #0x80
+ jb pirq_found
+ mov bx, [bp-2] ;; pci irq list pointer
+ mov al, [bx]
+ out dx, al
+ inc bx
+ mov [bp-2], bx
+ call pcibios_init_set_elcr
+pirq_found:
+ mov bh, [si]
+ mov bl, [si+1]
+ add bl, [bp-3] ;; pci function number
+ mov dl, #0x3c
+ call pcibios_init_sel_reg
+ mov dx, #0x0cfc
+ out dx, al
+next_pci_func:
+ inc byte ptr[bp-3]
+ inc bl
+ test bl, #0x07
+ jnz pci_init_irq_loop2
+next_pir_entry:
+ add si, #0x10
+ mov byte ptr[bp-3], #0x00
+ loop pci_init_irq_loop1
+ mov sp, bp
+ pop bx
+pci_init_end:
+ pop bp
+ pop ds
+ ret
+#endif // !BX_ROMBIOS32
+#endif // BX_PCIBIOS
+
+#if BX_ROMBIOS32
+rombios32_init:
+ ;; save a20 and enable it
+ in al, 0x92
+ push ax
+ or al, #0x02
+ out 0x92, al
+
+ ;; save SS:SP to the BDA
+ xor ax, ax
+ mov ds, ax
+ mov 0x0469, ss
+ mov 0x0467, sp
+
+ SEG CS
+ lidt [pmode_IDT_info]
+ SEG CS
+ lgdt [rombios32_gdt_48]
+ ;; set PE bit in CR0
+ mov eax, cr0
+ or al, #0x01
+ mov cr0, eax
+ ;; start protected mode code: ljmpl 0x10:rombios32_init1
+ db 0x66, 0xea
+ dw rombios32_05
+ dw 0x000f ;; high 16 bit address
+ dw 0x0010
+
+use32 386
+rombios32_05:
+ ;; init data segments
+ mov eax, #0x18
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+ xor eax, eax
+ mov fs, ax
+ mov gs, ax
+ cld
+
+ ;; init the stack pointer to point below EBDA
+ mov ax, [0x040e]
+ shl eax, #4
+ mov esp, #-0x10
+ add esp, eax
+
+ ;; pass pointer to s3_resume_flag and s3_resume_vector to rombios32
+ push #0x04b0
+ push #0x04b2
+
+ ;; call rombios32 code
+ mov eax, #0x000e0000
+ call eax
+
+ ;; return to 16 bit protected mode first
+ db 0xea
+ dd rombios32_10
+ dw 0x20
+
+use16 386
+rombios32_10:
+ ;; restore data segment limits to 0xffff
+ mov ax, #0x28
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+ mov fs, ax
+ mov gs, ax
+
+ ;; reset PE bit in CR0
+ mov eax, cr0
+ and al, #0xFE
+ mov cr0, eax
+
+ ;; far jump to flush CPU queue after transition to real mode
+ JMP_AP(0xf000, rombios32_real_mode)
+
+rombios32_real_mode:
+ ;; restore IDT to normal real-mode defaults
+ SEG CS
+ lidt [rmode_IDT_info]
+
+ xor ax, ax
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+
+ ;; restore SS:SP from the BDA
+ mov ss, 0x0469
+ xor esp, esp
+ mov sp, 0x0467
+ ;; restore a20
+ pop ax
+ out 0x92, al
+ ret
+
+rombios32_gdt_48:
+ dw 0x30
+ dw rombios32_gdt
+ dw 0x000f
+
+rombios32_gdt:
+ dw 0, 0, 0, 0
+ dw 0, 0, 0, 0
+ dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
+ dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
+ dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
+ dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
+#endif // BX_ROMBIOS32
+
+
+; parallel port detection: base address in DX, index in BX, timeout in CL
+detect_parport:
+ push dx
+ add dx, #2
+ in al, dx
+ and al, #0xdf ; clear input mode
+ out dx, al
+ pop dx
+ mov al, #0xaa
+ out dx, al
+ in al, dx
+ cmp al, #0xaa
+ jne no_parport
+ push bx
+ shl bx, #1
+ mov [bx+0x408], dx ; Parallel I/O address
+ pop bx
+ mov [bx+0x478], cl ; Parallel printer timeout
+ inc bx
+no_parport:
+ ret
+
+; serial port detection: base address in DX, index in BX, timeout in CL
+detect_serial:
+ push dx
+ inc dx
+ mov al, #0x02
+ out dx, al
+ in al, dx
+ cmp al, #0x02
+ jne no_serial
+ inc dx
+ in al, dx
+ cmp al, #0x02
+ jne no_serial
+ dec dx
+ xor al, al
+ out dx, al
+ pop dx
+ push bx
+ shl bx, #1
+ mov [bx+0x400], dx ; Serial I/O address
+ pop bx
+ mov [bx+0x47c], cl ; Serial timeout
+ inc bx
+ ret
+no_serial:
+ pop dx
+ ret
+
+rom_checksum:
+ push ax
+ push bx
+ push cx
+ xor ax, ax
+ xor bx, bx
+ xor cx, cx
+ mov ch, [2]
+ shl cx, #1
+checksum_loop:
+ add al, [bx]
+ inc bx
+ loop checksum_loop
+ and al, #0xff
+ pop cx
+ pop bx
+ pop ax
+ ret
+
+
+;; We need a copy of this string, but we are not actually a PnP BIOS,
+;; so make sure it is *not* aligned, so OSes will not see it if they scan.
+.align 16
+ db 0
+pnp_string:
+ .ascii "$PnP"
+
+
+rom_scan:
+ ;; Scan for existence of valid expansion ROMS.
+ ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
+ ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
+ ;; System ROM: only 0xE0000
+ ;;
+ ;; Header:
+ ;; Offset Value
+ ;; 0 0x55
+ ;; 1 0xAA
+ ;; 2 ROM length in 512-byte blocks
+ ;; 3 ROM initialization entry point (FAR CALL)
+
+rom_scan_loop:
+ push ax ;; Save AX
+ mov ds, cx
+ mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
+ cmp [0], #0xAA55 ;; look for signature
+ jne rom_scan_increment
+ call rom_checksum
+ jnz rom_scan_increment
+ mov al, [2] ;; change increment to ROM length in 512-byte blocks
+
+ ;; We want our increment in 512-byte quantities, rounded to
+ ;; the nearest 2k quantity, since we only scan at 2k intervals.
+ test al, #0x03
+ jz block_count_rounded
+ and al, #0xfc ;; needs rounding up
+ add al, #0x04
+block_count_rounded:
+
+ xor bx, bx ;; Restore DS back to 0000:
+ mov ds, bx
+ push ax ;; Save AX
+ push di ;; Save DI
+ ;; Push addr of ROM entry point
+ push cx ;; Push seg
+ push #0x0003 ;; Push offset
+
+ ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS.
+ ;; That should stop it grabbing INT 19h; we will use its BEV instead.
+ mov ax, #0xf000
+ mov es, ax
+ lea di, pnp_string
+
+ mov bp, sp ;; Call ROM init routine using seg:off on stack
+ db 0xff ;; call_far ss:[bp+0]
+ db 0x5e
+ db 0
+ cli ;; In case expansion ROM BIOS turns IF on
+ add sp, #2 ;; Pop offset value
+ pop cx ;; Pop seg value (restore CX)
+
+ ;; Look at the ROM's PnP Expansion header. Properly, we're supposed
+ ;; to init all the ROMs and then go back and build an IPL table of
+ ;; all the bootable devices, but we can get away with one pass.
+ mov ds, cx ;; ROM base
+ mov bx, 0x001a ;; 0x1A is the offset into ROM header that contains...
+ mov ax, [bx] ;; the offset of PnP expansion header, where...
+ cmp ax, #0x5024 ;; we look for signature "$PnP"
+ jne no_bev
+ mov ax, 2[bx]
+ cmp ax, #0x506e
+ jne no_bev
+
+ mov ax, 0x16[bx] ;; 0x16 is the offset of Boot Connection Vector
+ cmp ax, #0x0000
+ je no_bcv
+
+ ;; Option ROM has BCV. Run it now.
+ push cx ;; Push seg
+ push ax ;; Push offset
+
+ ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS.
+ mov bx, #0xf000
+ mov es, bx
+ lea di, pnp_string
+ /* jump to BCV function entry pointer */
+ mov bp, sp ;; Call ROM BCV routine using seg:off on stack
+ db 0xff ;; call_far ss:[bp+0]
+ db 0x5e
+ db 0
+ cli ;; In case expansion ROM BIOS turns IF on
+ add sp, #2 ;; Pop offset value
+ pop cx ;; Pop seg value (restore CX)
+ jmp no_bev
+
+no_bcv:
+ mov ax, 0x1a[bx] ;; 0x1A is also the offset into the expansion header of...
+ cmp ax, #0x0000 ;; the Bootstrap Entry Vector, or zero if there is none.
+ je no_bev
+
+ ;; Found a device that thinks it can boot the system. Record its BEV and product name string.
+ mov di, 0x10[bx] ;; Pointer to the product name string or zero if none
+ mov bx, #IPL_SEG ;; Go to the segment where the IPL table lives
+ mov ds, bx
+ mov bx, IPL_COUNT_OFFSET ;; Read the number of entries so far
+ cmp bx, #IPL_TABLE_ENTRIES
+ je no_bev ;; Get out if the table is full
+ shl bx, #0x4 ;; Turn count into offset (entries are 16 bytes)
+ mov 0[bx], #IPL_TYPE_BEV ;; This entry is a BEV device
+ mov 6[bx], cx ;; Build a far pointer from the segment...
+ mov 4[bx], ax ;; and the offset
+ cmp di, #0x0000
+ je no_prod_str
+ mov 0xA[bx], cx ;; Build a far pointer from the segment...
+ mov 8[bx], di ;; and the offset
+no_prod_str:
+ shr bx, #0x4 ;; Turn the offset back into a count
+ inc bx ;; We have one more entry now
+ mov IPL_COUNT_OFFSET, bx ;; Remember that.
+
+no_bev:
+ pop di ;; Restore DI
+ pop ax ;; Restore AX
+rom_scan_increment:
+ shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
+ ;; because the segment selector is shifted left 4 bits.
+ add cx, ax
+ pop ax ;; Restore AX
+ cmp cx, ax
+ jbe rom_scan_loop
+
+ xor ax, ax ;; Restore DS back to 0000:
+ mov ds, ax
+ ret
+
+post_init_pic:
+ mov al, #0x11 ; send initialisation commands
+ out 0x20, al
+ out 0xa0, al
+ mov al, #0x08
+ out 0x21, al
+ mov al, #0x70
+ out 0xa1, al
+ mov al, #0x04
+ out 0x21, al
+ mov al, #0x02
+ out 0xa1, al
+ mov al, #0x01
+ out 0x21, al
+ out 0xa1, al
+ mov al, #0xb8
+ out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
+#if BX_USE_PS2_MOUSE
+ mov al, #0x8f
+#else
+ mov al, #0x9f
+#endif
+ out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
+ ret
+
+;; the following area can be used to write dynamically generated tables
+ .align 16
+bios_table_area_start:
+ dd 0xaafb4442
+ dd bios_table_area_end - bios_table_area_start - 8;
+
+;--------
+;- POST -
+;--------
+.org 0xe05b ; POST Entry Point
+post:
+
+ xor ax, ax
+
+ ;; first reset the DMA controllers
+ out 0x0d,al
+ out 0xda,al
+
+ ;; then initialize the DMA controllers
+ mov al, #0xC0
+ out 0xD6, al ; cascade mode of channel 4 enabled
+ mov al, #0x00
+ out 0xD4, al ; unmask channel 4
+
+ ;; Examine CMOS shutdown status.
+ mov AL, #0x0f
+ out 0x70, AL
+ in AL, 0x71
+
+ ;; backup status
+ mov bl, al
+
+ ;; Reset CMOS shutdown status.
+ mov AL, #0x0f
+ out 0x70, AL ; select CMOS register Fh
+ mov AL, #0x00
+ out 0x71, AL ; set shutdown action to normal
+
+ ;; Examine CMOS shutdown status.
+ mov al, bl
+
+ ;; 0x00, 0x09, 0x0D+ = normal startup
+ cmp AL, #0x00
+ jz normal_post
+ cmp AL, #0x0d
+ jae normal_post
+ cmp AL, #0x09
+ je normal_post
+
+ ;; 0x05 = eoi + jmp via [0x40:0x67] jump
+ cmp al, #0x05
+ je eoi_jmp_post
+
+ ;; 0x0A = jmp via [0x40:0x67] jump
+ cmp al, #0x0a
+ je jmp_post_0x467
+
+ ;; 0x0B = iret via [0x40:0x67]
+ cmp al, #0x0b
+ je iret_post_0x467
+
+ ;; 0x0C = retf via [0x40:0x67]
+ cmp al, #0x0c
+ je retf_post_0x467
+
+ ;; Examine CMOS shutdown status.
+ ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08 = Unimplemented shutdown status.
+ push bx
+ call _shutdown_status_panic
+
+#if 0
+ HALT(__LINE__)
+ ;
+ ;#if 0
+ ; 0xb0, 0x20, /* mov al, #0x20 */
+ ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
+ ;#endif
+ ;
+ pop es
+ pop ds
+ popa
+ iret
+#endif
+
+normal_post:
+ ; case 0: normal startup
+
+ cli
+ mov ax, #0xfffe
+ mov sp, ax
+ xor ax, ax
+ mov ds, ax
+ mov ss, ax
+
+ ;; Save shutdown status
+ mov 0x04b0, bl
+
+ cmp bl, #0xfe
+ jz s3_post
+
+ ;; zero out BIOS data area (40:00..40:ff)
+ mov es, ax
+ mov cx, #0x0080 ;; 128 words
+ mov di, #0x0400
+ cld
+ rep
+ stosw
+
+ call _log_bios_start
+
+ ;; set all interrupts to default handler
+ xor bx, bx ;; offset index
+ mov cx, #0x0100 ;; counter (256 interrupts)
+ mov ax, #dummy_iret_handler
+ mov dx, #0xF000
+
+post_default_ints:
+ mov [bx], ax
+ add bx, #2
+ mov [bx], dx
+ add bx, #2
+ loop post_default_ints
+
+ ;; set vector 0x79 to zero
+ ;; this is used by 'gardian angel' protection system
+ SET_INT_VECTOR(0x79, #0, #0)
+
+ ;; base memory in K 40:13 (word)
+ mov ax, #BASE_MEM_IN_K
+ mov 0x0413, ax
+
+
+ ;; Manufacturing Test 40:12
+ ;; zerod out above
+
+ ;; Warm Boot Flag 0040:0072
+ ;; value of 1234h = skip memory checks
+ ;; zerod out above
+
+
+ ;; Printer Services vector
+ SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
+
+ ;; Bootstrap failure vector
+ SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
+
+ ;; Bootstrap Loader vector
+ SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
+
+ ;; User Timer Tick vector
+ SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
+
+ ;; Memory Size Check vector
+ SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
+
+ ;; Equipment Configuration Check vector
+ SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
+
+ ;; System Services
+ SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
+
+ ;; EBDA setup
+ call ebda_post
+
+ ;; PIT setup
+ SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
+ ;; int 1C already points at dummy_iret_handler (above)
+ mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
+ out 0x43, al
+ mov al, #0x00 ; maximum count of 0000H = 18.2Hz
+ out 0x40, al
+ out 0x40, al
+
+ ;; Keyboard
+ SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
+ SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
+
+ xor ax, ax
+ mov ds, ax
+ mov 0x0417, al /* keyboard shift flags, set 1 */
+ mov 0x0418, al /* keyboard shift flags, set 2 */
+ mov 0x0419, al /* keyboard alt-numpad work area */
+ mov 0x0471, al /* keyboard ctrl-break flag */
+ mov 0x0497, al /* keyboard status flags 4 */
+ mov al, #0x10
+ mov 0x0496, al /* keyboard status flags 3 */
+
+
+ /* keyboard head of buffer pointer */
+ mov bx, #0x001E
+ mov 0x041A, bx
+
+ /* keyboard end of buffer pointer */
+ mov 0x041C, bx
+
+ /* keyboard pointer to start of buffer */
+ mov bx, #0x001E
+ mov 0x0480, bx
+
+ /* keyboard pointer to end of buffer */
+ mov bx, #0x003E
+ mov 0x0482, bx
+
+ /* init the keyboard */
+ call _keyboard_init
+
+ ;; mov CMOS Equipment Byte to BDA Equipment Word
+ mov ax, 0x0410
+ mov al, #0x14
+ out 0x70, al
+ in al, 0x71
+ mov 0x0410, ax
+
+
+ ;; Parallel setup
+ SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
+ xor ax, ax
+ mov ds, ax
+ xor bx, bx
+ mov cl, #0x14 ; timeout value
+ mov dx, #0x378 ; Parallel I/O address, port 1
+ call detect_parport
+ mov dx, #0x278 ; Parallel I/O address, port 2
+ call detect_parport
+ shl bx, #0x0e
+ mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
+ and ax, #0x3fff
+ or ax, bx ; set number of parallel ports
+ mov 0x410, ax
+
+ ;; Serial setup
+ SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
+ SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
+ xor bx, bx
+ mov cl, #0x0a ; timeout value
+ mov dx, #0x03f8 ; Serial I/O address, port 1
+ call detect_serial
+ mov dx, #0x02f8 ; Serial I/O address, port 2
+ call detect_serial
+ mov dx, #0x03e8 ; Serial I/O address, port 3
+ call detect_serial
+ mov dx, #0x02e8 ; Serial I/O address, port 4
+ call detect_serial
+ shl bx, #0x09
+ mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
+ and ax, #0xf1ff
+ or ax, bx ; set number of serial port
+ mov 0x410, ax
+
+ ;; CMOS RTC
+ SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
+ SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
+ SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
+ ;; BIOS DATA AREA 0x4CE ???
+ call timer_tick_post
+
+ ;; PS/2 mouse setup
+ SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
+
+ ;; IRQ13 (FPU exception) setup
+ SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
+
+ ;; Video setup
+ SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
+
+ ;; PIC
+ call post_init_pic
+
+ mov cx, #0xc000 ;; init vga bios
+ mov ax, #0xc780
+ call rom_scan
+
+ call _print_bios_banner
+
+#if BX_ROMBIOS32
+ call rombios32_init
+#else
+#if BX_PCIBIOS
+ call pcibios_init_iomem_bases
+ call pcibios_init_irqs
+#endif //BX_PCIBIOS
+#endif
+
+ ;;
+ ;; Floppy setup
+ ;;
+ call floppy_drive_post
+
+ ;;
+ ;; Hard Drive setup
+ ;;
+ call hard_drive_post
+
+#if BX_USE_ATADRV
+
+ ;;
+ ;; ATA/ATAPI driver setup
+ ;;
+ call _ata_init
+ call _ata_detect
+ ;;
+
+#endif // BX_USE_ATADRV
+
+#if BX_ELTORITO_BOOT
+ ;;
+ ;; eltorito floppy/harddisk emulation from cd
+ ;;
+ call _cdemu_init
+ ;;
+#endif // BX_ELTORITO_BOOT
+
+ call _init_boot_vectors
+
+ mov cx, #0xc800 ;; init option roms
+ mov ax, #0xe000
+ call rom_scan
+
+#if BX_ELTORITO_BOOT
+ call _interactive_bootkey
+#endif // BX_ELTORITO_BOOT
+
+ sti ;; enable interrupts
+ int #0x19
+
+.org 0xe2c3 ; NMI Handler Entry Point
+nmi:
+ ;; FIXME the NMI handler should not panic
+ ;; but iret when called from int75 (fpu exception)
+ call _nmi_handler_msg
+ iret
+
+int75_handler:
+ out 0xf0, al // clear irq13
+ call eoi_both_pics // clear interrupt
+ int 2 // legacy nmi call
+ iret
+
+;-------------------------------------------
+;- INT 13h Fixed Disk Services Entry Point -
+;-------------------------------------------
+.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
+int13_handler:
+ //JMPL(int13_relocated)
+ jmp int13_relocated
+
+.org 0xe401 ; Fixed Disk Parameter Table
+
+;----------
+;- INT19h -
+;----------
+.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
+int19_handler:
+
+ jmp int19_relocated
+;-------------------------------------------
+;- System BIOS Configuration Data Table
+;-------------------------------------------
+.org BIOS_CONFIG_TABLE
+db 0x08 ; Table size (bytes) -Lo
+db 0x00 ; Table size (bytes) -Hi
+db SYS_MODEL_ID
+db SYS_SUBMODEL_ID
+db BIOS_REVISION
+; Feature byte 1
+; b7: 1=DMA channel 3 used by hard disk
+; b6: 1=2 interrupt controllers present
+; b5: 1=RTC present
+; b4: 1=BIOS calls int 15h/4Fh every key
+; b3: 1=wait for extern event supported (Int 15h/41h)
+; b2: 1=extended BIOS data area used
+; b1: 0=AT or ESDI bus, 1=MicroChannel
+; b0: 1=Dual bus (MicroChannel + ISA)
+db (0 << 7) | \
+ (1 << 6) | \
+ (1 << 5) | \
+ (BX_CALL_INT15_4F << 4) | \
+ (0 << 3) | \
+ (BX_USE_EBDA << 2) | \
+ (0 << 1) | \
+ (0 << 0)
+; Feature byte 2
+; b7: 1=32-bit DMA supported
+; b6: 1=int16h, function 9 supported
+; b5: 1=int15h/C6h (get POS data) supported
+; b4: 1=int15h/C7h (get mem map info) supported
+; b3: 1=int15h/C8h (en/dis CPU) supported
+; b2: 1=non-8042 kb controller
+; b1: 1=data streaming supported
+; b0: reserved
+db (0 << 7) | \
+ (1 << 6) | \
+ (0 << 5) | \
+ (0 << 4) | \
+ (0 << 3) | \
+ (0 << 2) | \
+ (0 << 1) | \
+ (0 << 0)
+; Feature byte 3
+; b7: not used
+; b6: reserved
+; b5: reserved
+; b4: POST supports ROM-to-RAM enable/disable
+; b3: SCSI on system board
+; b2: info panel installed
+; b1: Initial Machine Load (IML) system - BIOS on disk
+; b0: SCSI supported in IML
+db 0x00
+; Feature byte 4
+; b7: IBM private
+; b6: EEPROM present
+; b5-3: ABIOS presence (011 = not supported)
+; b2: private
+; b1: memory split above 16Mb supported
+; b0: POSTEXT directly supported by POST
+db 0x00
+; Feature byte 5 (IBM)
+; b1: enhanced mouse
+; b0: flash EPROM
+db 0x00
+
+
+
+.org 0xe729 ; Baud Rate Generator Table
+
+;----------
+;- INT14h -
+;----------
+.org 0xe739 ; INT 14h Serial Communications Service Entry Point
+int14_handler:
+ push ds
+ pusha
+ xor ax, ax
+ mov ds, ax
+ call _int14_function
+ popa
+ pop ds
+ iret
+
+
+;----------------------------------------
+;- INT 16h Keyboard Service Entry Point -
+;----------------------------------------
+.org 0xe82e
+int16_handler:
+
+ sti
+ push ds
+ pushf
+ pusha
+
+ cmp ah, #0x00
+ je int16_F00
+ cmp ah, #0x10
+ je int16_F00
+
+ mov bx, #0xf000
+ mov ds, bx
+ call _int16_function
+ popa
+ popf
+ pop ds
+ jz int16_zero_set
+
+int16_zero_clear:
+ push bp
+ mov bp, sp
+ //SEG SS
+ and BYTE [bp + 0x06], #0xbf
+ pop bp
+ iret
+
+int16_zero_set:
+ push bp
+ mov bp, sp
+ //SEG SS
+ or BYTE [bp + 0x06], #0x40
+ pop bp
+ iret
+
+int16_F00:
+ mov bx, #0x0040
+ mov ds, bx
+
+int16_wait_for_key:
+ cli
+ mov bx, 0x001a
+ cmp bx, 0x001c
+ jne int16_key_found
+ sti
+ nop
+#if 0
+ /* no key yet, call int 15h, function AX=9002 */
+ 0x50, /* push AX */
+ 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
+ 0xcd, 0x15, /* int 15h */
+ 0x58, /* pop AX */
+ 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
+#endif
+ jmp int16_wait_for_key
+
+int16_key_found:
+ mov bx, #0xf000
+ mov ds, bx
+ call _int16_function
+ popa
+ popf
+ pop ds
+#if 0
+ /* notify int16 complete w/ int 15h, function AX=9102 */
+ 0x50, /* push AX */
+ 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
+ 0xcd, 0x15, /* int 15h */
+ 0x58, /* pop AX */
+#endif
+ iret
+
+
+
+;-------------------------------------------------
+;- INT09h : Keyboard Hardware Service Entry Point -
+;-------------------------------------------------
+.org 0xe987
+int09_handler:
+ cli
+ push ax
+
+ mov al, #0xAD ;;disable keyboard
+ out #0x64, al
+
+ mov al, #0x0B
+ out #0x20, al
+ in al, #0x20
+ and al, #0x02
+ jz int09_finish
+
+ in al, #0x60 ;;read key from keyboard controller
+ sti
+ push ds
+ pusha
+#ifdef BX_CALL_INT15_4F
+ mov ah, #0x4f ;; allow for keyboard intercept
+ stc
+ int #0x15
+ jnc int09_done
+#endif
+
+ ;; check for extended key
+ cmp al, #0xe0
+ jne int09_check_pause
+ xor ax, ax
+ mov ds, ax
+ mov al, BYTE [0x496] ;; mf2_state |= 0x02
+ or al, #0x02
+ mov BYTE [0x496], al
+ jmp int09_done
+
+int09_check_pause: ;; check for pause key
+ cmp al, #0xe1
+ jne int09_process_key
+ xor ax, ax
+ mov ds, ax
+ mov al, BYTE [0x496] ;; mf2_state |= 0x01
+ or al, #0x01
+ mov BYTE [0x496], al
+ jmp int09_done
+
+int09_process_key:
+ mov bx, #0xf000
+ mov ds, bx
+ call _int09_function
+
+int09_done:
+ popa
+ pop ds
+ cli
+ call eoi_master_pic
+
+int09_finish:
+ mov al, #0xAE ;;enable keyboard
+ out #0x64, al
+ pop ax
+ iret
+
+
+;----------------------------------------
+;- INT 13h Diskette Service Entry Point -
+;----------------------------------------
+.org 0xec59
+int13_diskette:
+ jmp int13_noeltorito
+
+;---------------------------------------------
+;- INT 0Eh Diskette Hardware ISR Entry Point -
+;---------------------------------------------
+.org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
+int0e_handler:
+ push ax
+ push dx
+ mov dx, #0x03f4
+ in al, dx
+ and al, #0xc0
+ cmp al, #0xc0
+ je int0e_normal
+ mov dx, #0x03f5
+ mov al, #0x08 ; sense interrupt status
+ out dx, al
+int0e_loop1:
+ mov dx, #0x03f4
+ in al, dx
+ and al, #0xc0
+ cmp al, #0xc0
+ jne int0e_loop1
+int0e_loop2:
+ mov dx, #0x03f5
+ in al, dx
+ mov dx, #0x03f4
+ in al, dx
+ and al, #0xc0
+ cmp al, #0xc0
+ je int0e_loop2
+int0e_normal:
+ push ds
+ xor ax, ax ;; segment 0000
+ mov ds, ax
+ call eoi_master_pic
+ mov al, 0x043e
+ or al, #0x80 ;; diskette interrupt has occurred
+ mov 0x043e, al
+ pop ds
+ pop dx
+ pop ax
+ iret
+
+
+.org 0xefc7 ; Diskette Controller Parameter Table
+diskette_param_table:
+;; Since no provisions are made for multiple drive types, most
+;; values in this table are ignored. I set parameters for 1.44M
+;; floppy here
+db 0xAF
+db 0x02 ;; head load time 0000001, DMA used
+db 0x25
+db 0x02
+db 18
+db 0x1B
+db 0xFF
+db 0x6C
+db 0xF6
+db 0x0F
+db 0x08
+
+
+;----------------------------------------
+;- INT17h : Printer Service Entry Point -
+;----------------------------------------
+.org 0xefd2
+int17_handler:
+ push ds
+ pusha
+ xor ax, ax
+ mov ds, ax
+ call _int17_function
+ popa
+ pop ds
+ iret
+
+diskette_param_table2:
+;; 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
+db 0xAF
+db 0x02 ;; head load time 0000001, DMA used
+db 0x25
+db 0x02
+db 18
+db 0x1B
+db 0xFF
+db 0x6C
+db 0xF6
+db 0x0F
+db 0x08
+db 79 ;; maximum track
+db 0 ;; data transfer rate
+db 4 ;; drive type in cmos
+
+.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
+ HALT(__LINE__)
+ iret
+
+;----------
+;- INT10h -
+;----------
+.org 0xf065 ; INT 10h Video Support Service Entry Point
+int10_handler:
+ ;; dont do anything, since the VGA BIOS handles int10h requests
+ iret
+
+.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
+
+;----------
+;- INT12h -
+;----------
+.org 0xf841 ; INT 12h Memory Size Service Entry Point
+; ??? different for Pentium (machine check)?
+int12_handler:
+ push ds
+ mov ax, #0x0040
+ mov ds, ax
+ mov ax, 0x0013
+ pop ds
+ iret
+
+;----------
+;- INT11h -
+;----------
+.org 0xf84d ; INT 11h Equipment List Service Entry Point
+int11_handler:
+ push ds
+ mov ax, #0x0040
+ mov ds, ax
+ mov ax, 0x0010
+ pop ds
+ iret
+
+;----------
+;- INT15h -
+;----------
+.org 0xf859 ; INT 15h System Services Entry Point
+int15_handler:
+ pushf
+#if BX_APM
+ cmp ah, #0x53
+ je apm_call
+#endif
+ push ds
+ push es
+ cmp ah, #0x86
+ je int15_handler32
+ cmp ah, #0xE8
+ je int15_handler32
+ pusha
+#if BX_USE_PS2_MOUSE
+ cmp ah, #0xC2
+ je int15_handler_mouse
+#endif
+ call _int15_function
+int15_handler_mouse_ret:
+ popa
+int15_handler32_ret:
+ pop es
+ pop ds
+ popf
+ jmp iret_modify_cf
+#if BX_APM
+apm_call:
+ jmp _apmreal_entry
+#endif
+
+#if BX_USE_PS2_MOUSE
+int15_handler_mouse:
+ call _int15_function_mouse
+ jmp int15_handler_mouse_ret
+#endif
+
+int15_handler32:
+ pushad
+ call _int15_function32
+ popad
+ jmp int15_handler32_ret
+
+;; Protected mode IDT descriptor
+;;
+;; I just make the limit 0, so the machine will shutdown
+;; if an exception occurs during protected mode memory
+;; transfers.
+;;
+;; Set base to f0000 to correspond to beginning of BIOS,
+;; in case I actually define an IDT later
+;; Set limit to 0
+
+pmode_IDT_info:
+dw 0x0000 ;; limit 15:00
+dw 0x0000 ;; base 15:00
+db 0x0f ;; base 23:16
+
+;; Real mode IDT descriptor
+;;
+;; Set to typical real-mode values.
+;; base = 000000
+;; limit = 03ff
+
+rmode_IDT_info:
+dw 0x03ff ;; limit 15:00
+dw 0x0000 ;; base 15:00
+db 0x00 ;; base 23:16
+
+
+;----------
+;- INT1Ah -
+;----------
+.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
+int1a_handler:
+#if BX_PCIBIOS
+ cmp ah, #0xb1
+ jne int1a_normal
+ call pcibios_real
+ jc pcibios_error
+ retf 2
+pcibios_error:
+ mov bl, ah
+ mov ah, #0xb1
+ push ds
+ pusha
+ mov ax, ss ; set readable descriptor to ds, for calling pcibios
+ mov ds, ax ; on 16bit protected mode.
+ jmp int1a_callfunction
+int1a_normal:
+#endif
+ push ds
+ pusha
+ xor ax, ax
+ mov ds, ax
+int1a_callfunction:
+ call _int1a_function
+ popa
+ pop ds
+ iret
+
+;;
+;; int70h: IRQ8 - CMOS RTC
+;;
+int70_handler:
+ push ds
+ pushad
+ xor ax, ax
+ mov ds, ax
+ call _int70_function
+ popad
+ pop ds
+ iret
+
+;---------
+;- INT08 -
+;---------
+.org 0xfea5 ; INT 08h System Timer ISR Entry Point
+int08_handler:
+ sti
+ push eax
+ push ds
+ xor ax, ax
+ mov ds, ax
+
+ ;; time to turn off drive(s)?
+ mov al,0x0440
+ or al,al
+ jz int08_floppy_off
+ dec al
+ mov 0x0440,al
+ jnz int08_floppy_off
+ ;; turn motor(s) off
+ push dx
+ mov dx,#0x03f2
+ in al,dx
+ and al,#0xcf
+ out dx,al
+ pop dx
+int08_floppy_off:
+
+ mov eax, 0x046c ;; get ticks dword
+ inc eax
+
+ ;; compare eax to one days worth of timer ticks at 18.2 hz
+ cmp eax, #0x001800B0
+ jb int08_store_ticks
+ ;; there has been a midnight rollover at this point
+ xor eax, eax ;; zero out counter
+ inc BYTE 0x0470 ;; increment rollover flag
+
+int08_store_ticks:
+ mov 0x046c, eax ;; store new ticks dword
+ ;; chain to user timer tick INT #0x1c
+ //pushf
+ //;; call_ep [ds:loc]
+ //CALL_EP( 0x1c << 2 )
+ int #0x1c
+ cli
+ call eoi_master_pic
+ pop ds
+ pop eax
+ iret
+
+.org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
+
+
+.org 0xff00
+.ascii BIOS_COPYRIGHT_STRING
+
+;------------------------------------------------
+;- IRET Instruction for Dummy Interrupt Handler -
+;------------------------------------------------
+.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
+dummy_iret_handler:
+ iret
+
+.org 0xff54 ; INT 05h Print Screen Service Entry Point
+ HALT(__LINE__)
+ iret
+
+.org 0xfff0 ; Power-up Entry Point
+ jmp 0xf000:post
+
+.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
+.ascii BIOS_BUILD_DATE
+
+.org 0xfffe ; System Model ID
+db SYS_MODEL_ID
+db 0x00 ; filler
+
+.org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
+ASM_END
+/*
+ * 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
+ */
+static Bit8u vgafont8[128*8]=
+{
+ 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,
+};
+
+ASM_START
+.org 0xcc00
+bios_table_area_end:
+// bcc-generated data will be placed here
+ASM_END
diff --git a/bochs/bios/rombios.h b/bochs/bios/rombios.h
new file mode 100644
index 0000000..6f9cbb1
--- /dev/null
+++ b/bochs/bios/rombios.h
@@ -0,0 +1,68 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id$
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2006 Volker Ruppert
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+/* define it to include QEMU specific code */
+#define BX_QEMU
+
+#ifndef LEGACY
+# define BX_ROMBIOS32 1
+#else
+# define BX_ROMBIOS32 0
+#endif
+#define DEBUG_ROMBIOS 0
+
+#define PANIC_PORT 0x400
+#define PANIC_PORT2 0x401
+#define INFO_PORT 0x402
+#define DEBUG_PORT 0x403
+
+#define BIOS_PRINTF_HALT 1
+#define BIOS_PRINTF_SCREEN 2
+#define BIOS_PRINTF_INFO 4
+#define BIOS_PRINTF_DEBUG 8
+#define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
+#define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
+
+#define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
+
+// Defines the output macros.
+// BX_DEBUG goes to INFO port until we can easily choose debug info on a
+// per-device basis. Debug info are sent only in debug mode
+#if DEBUG_ROMBIOS
+# define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
+#else
+# define BX_DEBUG(format, p...)
+#endif
+#define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
+#define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
+
+#define ACPI_DATA_SIZE 0x00010000L
+#define PM_IO_BASE 0xb000
+#define SMB_IO_BASE 0xb100
+#define SMP_MSR_ADDR 0x0510
+
+ // Define the application NAME
+#if defined(BX_QEMU)
+# define BX_APPNAME "QEMU"
+#elif defined(PLEX86)
+# define BX_APPNAME "Plex86"
+#else
+# define BX_APPNAME "Bochs"
+#endif
diff --git a/bochs/bios/rombios32.c b/bochs/bios/rombios32.c
new file mode 100644
index 0000000..f861f81
--- /dev/null
+++ b/bochs/bios/rombios32.c
@@ -0,0 +1,2739 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id$
+/////////////////////////////////////////////////////////////////////////
+//
+// 32 bit Bochs BIOS init code
+// 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 as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#include <stdarg.h>
+#include <stddef.h>
+
+#include "rombios.h"
+
+typedef signed char int8_t;
+typedef short int16_t;
+typedef int int32_t;
+typedef long long int64_t;
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+
+/* if true, put the MP float table and ACPI RSDT in EBDA and the MP
+ table in RAM. Unfortunately, Linux has bugs with that, so we prefer
+ to modify the BIOS in shadow RAM */
+//#define BX_USE_EBDA_TABLES
+
+/* define it if the (emulated) hardware supports SMM mode */
+#define BX_USE_SMM
+
+#define cpuid(index, eax, ebx, ecx, edx) \
+ asm volatile ("cpuid" \
+ : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \
+ : "0" (index))
+
+#define wbinvd() asm volatile("wbinvd")
+
+#define CPUID_MSR (1 << 5)
+#define CPUID_APIC (1 << 9)
+#define CPUID_MTRR (1 << 12)
+
+#define APIC_BASE ((uint8_t *)0xfee00000)
+#define APIC_ICR_LOW 0x300
+#define APIC_SVR 0x0F0
+#define APIC_ID 0x020
+#define APIC_LVT3 0x370
+
+#define APIC_ENABLED 0x0100
+
+#define AP_BOOT_ADDR 0x9f000
+
+#define MPTABLE_MAX_SIZE 0x00002000
+#define SMI_CMD_IO_ADDR 0xb2
+
+#define BIOS_TMP_STORAGE 0x00030000 /* 64 KB used to copy the BIOS to shadow RAM */
+
+#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)
+
+static inline void outl(int addr, int val)
+{
+ asm volatile ("outl %1, %w0" : : "d" (addr), "a" (val));
+}
+
+static inline void outw(int addr, int val)
+{
+ asm volatile ("outw %w1, %w0" : : "d" (addr), "a" (val));
+}
+
+static inline void outb(int addr, int val)
+{
+ asm volatile ("outb %b1, %w0" : : "d" (addr), "a" (val));
+}
+
+static inline uint32_t inl(int addr)
+{
+ uint32_t val;
+ asm volatile ("inl %w1, %0" : "=a" (val) : "d" (addr));
+ return val;
+}
+
+static inline uint16_t inw(int addr)
+{
+ uint16_t val;
+ asm volatile ("inw %w1, %w0" : "=a" (val) : "d" (addr));
+ return val;
+}
+
+static inline uint8_t inb(int addr)
+{
+ uint8_t val;
+ asm volatile ("inb %w1, %b0" : "=a" (val) : "d" (addr));
+ return val;
+}
+
+static inline void writel(void *addr, uint32_t val)
+{
+ *(volatile uint32_t *)addr = val;
+}
+
+static inline void writew(void *addr, uint16_t val)
+{
+ *(volatile uint16_t *)addr = val;
+}
+
+static inline void writeb(void *addr, uint8_t val)
+{
+ *(volatile uint8_t *)addr = val;
+}
+
+static inline uint32_t readl(const void *addr)
+{
+ return *(volatile const uint32_t *)addr;
+}
+
+static inline uint16_t readw(const void *addr)
+{
+ return *(volatile const uint16_t *)addr;
+}
+
+static inline uint8_t readb(const void *addr)
+{
+ return *(volatile const uint8_t *)addr;
+}
+
+static inline void putc(int c)
+{
+ outb(INFO_PORT, c);
+}
+
+static uint64_t rdmsr(unsigned index)
+{
+ unsigned long long ret;
+
+ asm ("rdmsr" : "=A"(ret) : "c"(index));
+ return ret;
+}
+
+static void wrmsr(unsigned index, uint64_t val)
+{
+ asm volatile ("wrmsr" : : "c"(index), "A"(val));
+}
+
+static inline int isdigit(int c)
+{
+ return c >= '0' && c <= '9';
+}
+
+void *memset(void *d1, int val, size_t len)
+{
+ uint8_t *d = d1;
+
+ while (len--) {
+ *d++ = val;
+ }
+ return d1;
+}
+
+void *memcpy(void *d1, const void *s1, size_t len)
+{
+ uint8_t *d = d1;
+ const uint8_t *s = s1;
+
+ while (len--) {
+ *d++ = *s++;
+ }
+ return d1;
+}
+
+void *memmove(void *d1, const void *s1, size_t len)
+{
+ uint8_t *d = d1;
+ const uint8_t *s = s1;
+
+ if (d <= s) {
+ while (len--) {
+ *d++ = *s++;
+ }
+ } else {
+ d += len;
+ s += len;
+ while (len--) {
+ *--d = *--s;
+ }
+ }
+ return d1;
+}
+
+int memcmp(const void *s1, const void *s2, size_t len)
+{
+ const int8_t *p1 = s1;
+ const int8_t *p2 = s2;
+
+ while (len--) {
+ int r = *p1++ - *p2++;
+ if(r)
+ return r;
+ }
+
+ return 0;
+}
+
+size_t strlen(const char *s)
+{
+ const char *s1;
+ for(s1 = s; *s1 != '\0'; s1++);
+ return s1 - s;
+}
+
+/* from BSD ppp sources */
+int vsnprintf(char *buf, int buflen, const char *fmt, va_list args)
+{
+ int c, i, n;
+ int width, prec, fillch;
+ int base, len, neg;
+ unsigned long val = 0;
+ const char *f;
+ char *str, *buf0;
+ char num[32];
+ static const char hexchars[] = "0123456789abcdef";
+
+ buf0 = buf;
+ --buflen;
+ while (buflen > 0) {
+ for (f = fmt; *f != '%' && *f != 0; ++f)
+ ;
+ if (f > fmt) {
+ len = f - fmt;
+ if (len > buflen)
+ len = buflen;
+ memcpy(buf, fmt, len);
+ buf += len;
+ buflen -= len;
+ fmt = f;
+ }
+ if (*fmt == 0)
+ break;
+ c = *++fmt;
+ width = prec = 0;
+ fillch = ' ';
+ if (c == '0') {
+ fillch = '0';
+ c = *++fmt;
+ }
+ if (c == '*') {
+ width = va_arg(args, int);
+ c = *++fmt;
+ } else {
+ while (isdigit(c)) {
+ width = width * 10 + c - '0';
+ c = *++fmt;
+ }
+ }
+ if (c == '.') {
+ c = *++fmt;
+ if (c == '*') {
+ prec = va_arg(args, int);
+ c = *++fmt;
+ } else {
+ while (isdigit(c)) {
+ prec = prec * 10 + c - '0';
+ c = *++fmt;
+ }
+ }
+ }
+ /* modifiers */
+ switch(c) {
+ case 'l':
+ c = *++fmt;
+ break;
+ default:
+ break;
+ }
+ str = 0;
+ base = 0;
+ neg = 0;
+ ++fmt;
+ switch (c) {
+ case 'd':
+ i = va_arg(args, int);
+ if (i < 0) {
+ neg = 1;
+ val = -i;
+ } else
+ val = i;
+ base = 10;
+ break;
+ case 'o':
+ val = va_arg(args, unsigned int);
+ base = 8;
+ break;
+ case 'x':
+ case 'X':
+ val = va_arg(args, unsigned int);
+ base = 16;
+ break;
+ case 'p':
+ val = (unsigned long) va_arg(args, void *);
+ base = 16;
+ neg = 2;
+ break;
+ case 's':
+ str = va_arg(args, char *);
+ break;
+ case 'c':
+ num[0] = va_arg(args, int);
+ num[1] = 0;
+ str = num;
+ break;
+ default:
+ *buf++ = '%';
+ if (c != '%')
+ --fmt; /* so %z outputs %z etc. */
+ --buflen;
+ continue;
+ }
+ if (base != 0) {
+ str = num + sizeof(num);
+ *--str = 0;
+ while (str > num + neg) {
+ *--str = hexchars[val % base];
+ val = val / base;
+ if (--prec <= 0 && val == 0)
+ break;
+ }
+ switch (neg) {
+ case 1:
+ *--str = '-';
+ break;
+ case 2:
+ *--str = 'x';
+ *--str = '0';
+ break;
+ }
+ len = num + sizeof(num) - 1 - str;
+ } else {
+ len = strlen(str);
+ if (prec > 0 && len > prec)
+ len = prec;
+ }
+ if (width > 0) {
+ if (width > buflen)
+ width = buflen;
+ if ((n = width - len) > 0) {
+ buflen -= n;
+ for (; n > 0; --n)
+ *buf++ = fillch;
+ }
+ }
+ if (len > buflen)
+ len = buflen;
+ memcpy(buf, str, len);
+ buf += len;
+ buflen -= len;
+ }
+ *buf = 0;
+ return buf - buf0;
+}
+
+int snprintf(char * buf, size_t size, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i=vsnprintf(buf,size,fmt,args);
+ va_end(args);
+ return i;
+}
+
+void bios_printf(int flags, const char *fmt, ...)
+{
+ va_list ap;
+ char buf[1024];
+ const char *s;
+
+ if ((flags & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT)
+ outb(PANIC_PORT2, 0x00);
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ s = buf;
+ while (*s)
+ putc(*s++);
+ va_end(ap);
+}
+
+void delay_ms(int n)
+{
+ int i, j;
+ for(i = 0; i < n; i++) {
+#ifdef BX_QEMU
+ /* approximative ! */
+ for(j = 0; j < 1000000; j++);
+#else
+ {
+ int r1, r2;
+ j = 66;
+ r1 = inb(0x61) & 0x10;
+ do {
+ r2 = inb(0x61) & 0x10;
+ if (r1 != r2) {
+ j--;
+ r1 = r2;
+ }
+ } while (j > 0);
+ }
+#endif
+ }
+}
+
+uint16_t smp_cpus;
+uint32_t cpuid_signature;
+uint32_t cpuid_features;
+uint32_t cpuid_ext_features;
+unsigned long ram_size;
+uint64_t ram_end;
+#ifdef BX_USE_EBDA_TABLES
+unsigned long ebda_cur_addr;
+#endif
+int acpi_enabled;
+uint32_t pm_io_base, smb_io_base;
+int pm_sci_int;
+unsigned long bios_table_cur_addr;
+unsigned long bios_table_end_addr;
+
+static inline uint64_t le64_to_cpu(uint64_t x)
+{
+ return x;
+}
+
+void wrmsr_smp(uint32_t index, uint64_t val)
+{
+ static struct { uint32_t ecx, eax, edx; } *p = (void *)SMP_MSR_ADDR;
+
+ wrmsr(index, val);
+ p->ecx = index;
+ p->eax = val;
+ p->edx = val >> 32;
+ ++p;
+ p->ecx = 0;
+}
+
+#ifdef BX_QEMU
+#define QEMU_CFG_CTL_PORT 0x510
+#define QEMU_CFG_DATA_PORT 0x511
+#define QEMU_CFG_SIGNATURE 0x00
+#define QEMU_CFG_ID 0x01
+#define QEMU_CFG_UUID 0x02
+#define QEMU_CFG_NUMA 0x0D
+#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)
+
+int qemu_cfg_port;
+
+void qemu_cfg_select(int f)
+{
+ outw(QEMU_CFG_CTL_PORT, f);
+}
+
+int qemu_cfg_port_probe()
+{
+ char *sig = "QEMU";
+ int i;
+
+ qemu_cfg_select(QEMU_CFG_SIGNATURE);
+
+ for (i = 0; i < 4; i++)
+ if (inb(QEMU_CFG_DATA_PORT) != sig[i])
+ return 0;
+
+ return 1;
+}
+
+void qemu_cfg_read(uint8_t *buf, int len)
+{
+ while (len--)
+ *(buf++) = inb(QEMU_CFG_DATA_PORT);
+}
+
+static uint16_t acpi_additional_tables(void)
+{
+ uint16_t cnt;
+
+ qemu_cfg_select(QEMU_CFG_ACPI_TABLES);
+ qemu_cfg_read((uint8_t*)&cnt, sizeof(cnt));
+
+ return cnt;
+}
+
+static int acpi_load_table(int i, uint32_t addr, uint16_t *len)
+{
+ qemu_cfg_read((uint8_t*)len, sizeof(*len));
+
+ if (!*len)
+ return -1;
+
+ qemu_cfg_read((uint8_t*)addr, *len);
+ return 0;
+}
+
+static uint16_t smbios_entries(void)
+{
+ uint16_t cnt;
+
+ qemu_cfg_select(QEMU_CFG_SMBIOS_ENTRIES);
+ qemu_cfg_read((uint8_t*)&cnt, sizeof(cnt));
+
+ return cnt;
+}
+
+uint64_t qemu_cfg_get64 (void)
+{
+ uint64_t ret;
+
+ qemu_cfg_read((uint8_t*)&ret, 8);
+ return le64_to_cpu(ret);
+}
+#endif
+
+void cpu_probe(void)
+{
+ uint32_t eax, ebx, ecx, edx;
+ cpuid(1, eax, ebx, ecx, edx);
+ cpuid_signature = eax;
+ cpuid_features = edx;
+ cpuid_ext_features = ecx;
+}
+
+static int cmos_readb(int addr)
+{
+ outb(0x70, addr);
+ return inb(0x71);
+}
+
+void setup_mtrr(void)
+{
+ int i, vcnt, fix, wc;
+ uint32_t mtrr_cap;
+ union {
+ uint8_t valb[8];
+ uint64_t val;
+ } u;
+
+ *(uint32_t *)SMP_MSR_ADDR = 0;
+
+ if (!(cpuid_features & CPUID_MTRR))
+ return;
+
+ if (!(cpuid_features & CPUID_MSR))
+ return;
+
+ mtrr_cap = rdmsr(MSR_MTRRcap);
+ vcnt = mtrr_cap & 0xff;
+ fix = mtrr_cap & 0x100;
+ wc = mtrr_cap & 0x400;
+ if (!vcnt || !fix)
+ return;
+
+ u.val = 0;
+ for (i = 0; i < 8; ++i)
+ if (ram_size >= 65536 * (i + 1))
+ u.valb[i] = 6;
+ wrmsr_smp(MSR_MTRRfix64K_00000, u.val);
+ u.val = 0;
+ for (i = 0; i < 8; ++i)
+ if (ram_size >= 65536 * 8 + 16384 * (i + 1))
+ u.valb[i] = 6;
+ wrmsr_smp(MSR_MTRRfix16K_80000, u.val);
+ wrmsr_smp(MSR_MTRRfix16K_A0000, 0);
+ wrmsr_smp(MSR_MTRRfix4K_C0000, 0);
+ wrmsr_smp(MSR_MTRRfix4K_C8000, 0);
+ wrmsr_smp(MSR_MTRRfix4K_D0000, 0);
+ wrmsr_smp(MSR_MTRRfix4K_D8000, 0);
+ wrmsr_smp(MSR_MTRRfix4K_E0000, 0);
+ wrmsr_smp(MSR_MTRRfix4K_E8000, 0);
+ wrmsr_smp(MSR_MTRRfix4K_F0000, 0);
+ wrmsr_smp(MSR_MTRRfix4K_F8000, 0);
+ /* Mark 3.5-4GB as UC, anything not specified defaults to WB */
+ wrmsr_smp(MTRRphysBase_MSR(0), 0xe0000000ull | 0);
+ wrmsr_smp(MTRRphysMask_MSR(0), ~(0x20000000ull - 1) | 0x800);
+ wrmsr_smp(MSR_MTRRdefType, 0xc06);
+}
+
+void ram_probe(void)
+{
+ if (cmos_readb(0x34) | cmos_readb(0x35))
+ ram_size = (cmos_readb(0x34) | (cmos_readb(0x35) << 8)) * 65536 +
+ 16 * 1024 * 1024;
+ else
+ ram_size = (cmos_readb(0x30) | (cmos_readb(0x31) << 8)) * 1024 +
+ 1 * 1024 * 1024;
+ BX_INFO("ram_size=0x%08lx\n", ram_size);
+ if (cmos_readb(0x5b) | cmos_readb(0x5c) | cmos_readb(0x5d))
+ ram_end = (((uint64_t)cmos_readb(0x5b) << 16) |
+ ((uint64_t)cmos_readb(0x5c) << 24) |
+ ((uint64_t)cmos_readb(0x5d) << 32)) + (1ull << 32);
+ else
+ ram_end = ram_size;
+ BX_INFO("end of ram=%ldMB\n", ram_end >> 20);
+#ifdef BX_USE_EBDA_TABLES
+ ebda_cur_addr = ((*(uint16_t *)(0x40e)) << 4) + 0x380;
+ BX_INFO("ebda_cur_addr: 0x%08lx\n", ebda_cur_addr);
+#endif
+}
+
+/****************************************************/
+/* SMP probe */
+
+extern uint8_t smp_ap_boot_code_start;
+extern uint8_t smp_ap_boot_code_end;
+
+/* find the number of CPUs by launching a SIPI to them */
+void smp_probe(void)
+{
+ uint32_t val, sipi_vector;
+
+ writew(&smp_cpus, 1);
+ if (cpuid_features & CPUID_APIC) {
+
+ /* enable local APIC */
+ val = readl(APIC_BASE + APIC_SVR);
+ val |= APIC_ENABLED;
+ writel(APIC_BASE + APIC_SVR, val);
+
+ /* copy AP boot code */
+ memcpy((void *)AP_BOOT_ADDR, &smp_ap_boot_code_start,
+ &smp_ap_boot_code_end - &smp_ap_boot_code_start);
+
+ /* broadcast SIPI */
+ writel(APIC_BASE + APIC_ICR_LOW, 0x000C4500);
+ sipi_vector = AP_BOOT_ADDR >> 12;
+ writel(APIC_BASE + APIC_ICR_LOW, 0x000C4600 | sipi_vector);
+
+#ifndef BX_QEMU
+ delay_ms(10);
+#else
+ while (cmos_readb(0x5f) + 1 != readw(&smp_cpus))
+ ;
+#endif
+ }
+ BX_INFO("Found %d cpu(s)\n", readw(&smp_cpus));
+}
+
+/****************************************************/
+/* PCI init */
+
+#define PCI_ADDRESS_SPACE_MEM 0x00
+#define PCI_ADDRESS_SPACE_IO 0x01
+#define PCI_ADDRESS_SPACE_MEM_PREFETCH 0x08
+
+#define PCI_ROM_SLOT 6
+#define PCI_NUM_REGIONS 7
+
+#define PCI_DEVICES_MAX 64
+
+#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_CLASS_DEVICE 0x0a /* Device class */
+#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 */
+
+#define PCI_VENDOR_ID_INTEL 0x8086
+#define PCI_DEVICE_ID_INTEL_82441 0x1237
+#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000
+#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010
+#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110
+#define PCI_DEVICE_ID_INTEL_82371AB 0x7111
+#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113
+
+#define PCI_VENDOR_ID_IBM 0x1014
+#define PCI_VENDOR_ID_APPLE 0x106b
+
+typedef struct PCIDevice {
+ int bus;
+ int devfn;
+} PCIDevice;
+
+static uint32_t pci_bios_io_addr;
+static uint32_t pci_bios_mem_addr;
+static uint32_t pci_bios_bigmem_addr;
+/* host irqs corresponding to PCI irqs A-D */
+static uint8_t pci_irqs[4] = { 11, 9, 11, 9 };
+static PCIDevice i440_pcidev;
+
+static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val)
+{
+ outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc));
+ outl(0xcfc, val);
+}
+
+static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val)
+{
+ outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc));
+ outw(0xcfc + (addr & 2), val);
+}
+
+static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val)
+{
+ outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc));
+ outb(0xcfc + (addr & 3), val);
+}
+
+static uint32_t pci_config_readl(PCIDevice *d, uint32_t addr)
+{
+ outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc));
+ return inl(0xcfc);
+}
+
+static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr)
+{
+ outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc));
+ return inw(0xcfc + (addr & 2));
+}
+
+static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr)
+{
+ outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc));
+ return inb(0xcfc + (addr & 3));
+}
+
+static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr)
+{
+ uint16_t cmd;
+ uint32_t ofs, old_addr;
+
+ if ( region_num == PCI_ROM_SLOT ) {
+ ofs = 0x30;
+ }else{
+ ofs = 0x10 + region_num * 4;
+ }
+
+ old_addr = pci_config_readl(d, ofs);
+
+ pci_config_writel(d, ofs, addr);
+ BX_INFO("region %d: 0x%08x\n", region_num, addr);
+
+ /* enable memory mappings */
+ cmd = pci_config_readw(d, PCI_COMMAND);
+ if ( region_num == PCI_ROM_SLOT )
+ cmd |= 2;
+ else if (old_addr & PCI_ADDRESS_SPACE_IO)
+ cmd |= 1;
+ else
+ cmd |= 2;
+ pci_config_writew(d, PCI_COMMAND, cmd);
+}
+
+/* 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(PCIDevice *pci_dev, int irq_num)
+{
+ int slot_addend;
+ slot_addend = (pci_dev->devfn >> 3) - 1;
+ return (irq_num + slot_addend) & 3;
+}
+
+static void find_bios_table_area(void)
+{
+ unsigned long addr;
+ for(addr = 0xf0000; addr < 0x100000; addr += 16) {
+ if (*(uint32_t *)addr == 0xaafb4442) {
+ bios_table_cur_addr = addr + 8;
+ bios_table_end_addr = bios_table_cur_addr + *(uint32_t *)(addr + 4);
+ BX_INFO("bios_table_addr: 0x%08lx end=0x%08lx\n",
+ bios_table_cur_addr, bios_table_end_addr);
+ return;
+ }
+ }
+ return;
+}
+
+static void bios_shadow_init(PCIDevice *d)
+{
+ int v;
+
+ if (bios_table_cur_addr == 0)
+ return;
+
+ /* remap the BIOS to shadow RAM an keep it read/write while we
+ are writing tables */
+ v = pci_config_readb(d, 0x59);
+ v &= 0xcf;
+ pci_config_writeb(d, 0x59, v);
+ memcpy((void *)BIOS_TMP_STORAGE, (void *)0x000f0000, 0x10000);
+ v |= 0x30;
+ pci_config_writeb(d, 0x59, v);
+ memcpy((void *)0x000f0000, (void *)BIOS_TMP_STORAGE, 0x10000);
+
+ i440_pcidev = *d;
+}
+
+static void bios_lock_shadow_ram(void)
+{
+ PCIDevice *d = &i440_pcidev;
+ int v;
+
+ wbinvd();
+ v = pci_config_readb(d, 0x59);
+ v = (v & 0x0f) | (0x10);
+ pci_config_writeb(d, 0x59, v);
+}
+
+static void pci_bios_init_bridges(PCIDevice *d)
+{
+ uint16_t vendor_id, device_id;
+
+ vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
+ device_id = pci_config_readw(d, PCI_DEVICE_ID);
+
+ if (vendor_id == PCI_VENDOR_ID_INTEL &&
+ (device_id == PCI_DEVICE_ID_INTEL_82371SB_0 ||
+ device_id == PCI_DEVICE_ID_INTEL_82371AB_0)) {
+ int i, irq;
+ uint8_t elcr[2];
+
+ /* PIIX3/PIIX4 PCI to ISA bridge */
+
+ 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(d, 0x60 + i, irq);
+ }
+ outb(0x4d0, elcr[0]);
+ outb(0x4d1, elcr[1]);
+ BX_INFO("PIIX3/PIIX4 init: elcr=%02x %02x\n",
+ elcr[0], elcr[1]);
+ } else if (vendor_id == PCI_VENDOR_ID_INTEL && device_id == PCI_DEVICE_ID_INTEL_82441) {
+ /* i440 PCI bridge */
+ bios_shadow_init(d);
+ }
+}
+
+extern uint8_t smm_relocation_start, smm_relocation_end;
+extern uint8_t smm_code_start, smm_code_end;
+
+#ifdef BX_USE_SMM
+static void smm_init(PCIDevice *d)
+{
+ uint32_t value;
+
+ /* check if SMM init is already done */
+ value = pci_config_readl(d, 0x58);
+ if ((value & (1 << 25)) == 0) {
+
+ /* enable the SMM memory window */
+ pci_config_writeb(&i440_pcidev, 0x72, 0x02 | 0x48);
+
+ /* save original memory content */
+ memcpy((void *)0xa8000, (void *)0x38000, 0x8000);
+
+ /* copy the SMM relocation code */
+ memcpy((void *)0x38000, &smm_relocation_start,
+ &smm_relocation_end - &smm_relocation_start);
+
+ /* enable SMI generation when writing to the APMC register */
+ pci_config_writel(d, 0x58, value | (1 << 25));
+
+ /* init APM status port */
+ outb(0xb3, 0x01);
+
+ /* raise an SMI interrupt */
+ outb(0xb2, 0x00);
+
+ /* wait until SMM code executed */
+ while (inb(0xb3) != 0x00);
+
+ /* restore original memory content */
+ memcpy((void *)0x38000, (void *)0xa8000, 0x8000);
+
+ /* copy the SMM code */
+ memcpy((void *)0xa8000, &smm_code_start,
+ &smm_code_end - &smm_code_start);
+ wbinvd();
+
+ /* close the SMM memory window and enable normal SMM */
+ pci_config_writeb(&i440_pcidev, 0x72, 0x02 | 0x08);
+ }
+}
+#endif
+
+static void piix4_pm_enable(PCIDevice *d)
+{
+ /* PIIX4 Power Management device (for ACPI) */
+ pci_config_writel(d, 0x40, PM_IO_BASE | 1);
+ pci_config_writeb(d, 0x80, 0x01); /* enable PM io space */
+ pci_config_writel(d, 0x90, SMB_IO_BASE | 1);
+ pci_config_writeb(d, 0xd2, 0x09); /* enable SMBus io space */
+#ifdef BX_USE_SMM
+ smm_init(d);
+#endif
+}
+
+static void pci_bios_init_device(PCIDevice *d)
+{
+ int class;
+ uint32_t *paddr;
+ int i, pin, pic_irq, vendor_id, device_id;
+
+ class = pci_config_readw(d, PCI_CLASS_DEVICE);
+ vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
+ device_id = pci_config_readw(d, PCI_DEVICE_ID);
+ BX_INFO("PCI: bus=%d devfn=0x%02x: vendor_id=0x%04x device_id=0x%04x class=0x%04x\n",
+ d->bus, d->devfn, vendor_id, device_id, class);
+ switch(class) {
+ case 0x0101: /* Mass storage controller - IDE interface */
+ if (vendor_id == PCI_VENDOR_ID_INTEL &&
+ (device_id == PCI_DEVICE_ID_INTEL_82371SB_1 ||
+ device_id == PCI_DEVICE_ID_INTEL_82371AB)) {
+ /* PIIX3/PIIX4 IDE */
+ pci_config_writew(d, 0x40, 0x8000); // enable IDE0
+ pci_config_writew(d, 0x42, 0x8000); // enable IDE1
+ goto default_map;
+ } else {
+ /* IDE: we map it as in ISA mode */
+ pci_set_io_region_addr(d, 0, 0x1f0);
+ pci_set_io_region_addr(d, 1, 0x3f4);
+ pci_set_io_region_addr(d, 2, 0x170);
+ pci_set_io_region_addr(d, 3, 0x374);
+ }
+ break;
+ case 0x0300: /* Display controller - VGA compatible controller */
+ if (vendor_id != 0x1234)
+ goto default_map;
+ /* VGA: map frame buffer to default Bochs VBE address */
+ pci_set_io_region_addr(d, 0, 0xE0000000);
+ break;
+ case 0x0800: /* Generic system peripheral - PIC */
+ if (vendor_id == PCI_VENDOR_ID_IBM) {
+ /* IBM */
+ if (device_id == 0x0046 || device_id == 0xFFFF) {
+ /* MPIC & MPIC2 */
+ pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000);
+ }
+ }
+ break;
+ case 0xff00:
+ if (vendor_id == PCI_VENDOR_ID_APPLE &&
+ (device_id == 0x0017 || device_id == 0x0022)) {
+ /* macio bridge */
+ pci_set_io_region_addr(d, 0, 0x80800000);
+ }
+ break;
+ default:
+ default_map:
+ /* default memory mappings */
+ for(i = 0; i < PCI_NUM_REGIONS; i++) {
+ int ofs;
+ uint32_t val, size ;
+
+ if (i == PCI_ROM_SLOT) {
+ ofs = 0x30;
+ pci_config_writel(d, ofs, 0xfffffffe);
+ } else {
+ ofs = 0x10 + i * 4;
+ pci_config_writel(d, ofs, 0xffffffff);
+ }
+ val = pci_config_readl(d, ofs);
+ if (val != 0) {
+ size = (~(val & ~0xf)) + 1;
+ if (val & PCI_ADDRESS_SPACE_IO)
+ paddr = &pci_bios_io_addr;
+ else if (size >= 0x04000000)
+ paddr = &pci_bios_bigmem_addr;
+ else
+ paddr = &pci_bios_mem_addr;
+ *paddr = (*paddr + size - 1) & ~(size - 1);
+ pci_set_io_region_addr(d, i, *paddr);
+ *paddr += size;
+ }
+ }
+ break;
+ }
+
+ /* map the interrupt */
+ pin = pci_config_readb(d, PCI_INTERRUPT_PIN);
+ if (pin != 0) {
+ pin = pci_slot_get_pirq(d, pin - 1);
+ pic_irq = pci_irqs[pin];
+ pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq);
+ }
+
+ if (vendor_id == PCI_VENDOR_ID_INTEL && device_id == PCI_DEVICE_ID_INTEL_82371AB_3) {
+ /* PIIX4 Power Management device (for ACPI) */
+ pm_io_base = PM_IO_BASE;
+ smb_io_base = SMB_IO_BASE;
+ // acpi sci is hardwired to 9
+ pci_config_writeb(d, PCI_INTERRUPT_LINE, 9);
+ pm_sci_int = pci_config_readb(d, PCI_INTERRUPT_LINE);
+ piix4_pm_enable(d);
+ acpi_enabled = 1;
+ }
+}
+
+void pci_for_each_device(void (*init_func)(PCIDevice *d))
+{
+ PCIDevice d1, *d = &d1;
+ int bus, devfn;
+ uint16_t vendor_id, device_id;
+
+ for(bus = 0; bus < 1; bus++) {
+ for(devfn = 0; devfn < 256; devfn++) {
+ d->bus = bus;
+ d->devfn = devfn;
+ vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
+ device_id = pci_config_readw(d, PCI_DEVICE_ID);
+ if (vendor_id != 0xffff || device_id != 0xffff) {
+ init_func(d);
+ }
+ }
+ }
+}
+
+void pci_bios_init(void)
+{
+ pci_bios_io_addr = 0xc000;
+ pci_bios_mem_addr = 0xf0000000;
+ pci_bios_bigmem_addr = ram_size;
+ if (pci_bios_bigmem_addr < 0x90000000)
+ pci_bios_bigmem_addr = 0x90000000;
+
+ pci_for_each_device(pci_bios_init_bridges);
+
+ pci_for_each_device(pci_bios_init_device);
+}
+
+/****************************************************/
+/* Multi Processor table init */
+
+static void putb(uint8_t **pp, int val)
+{
+ uint8_t *q;
+ q = *pp;
+ *q++ = val;
+ *pp = q;
+}
+
+static void putstr(uint8_t **pp, const char *str)
+{
+ uint8_t *q;
+ q = *pp;
+ while (*str)
+ *q++ = *str++;
+ *pp = q;
+}
+
+static void putle16(uint8_t **pp, int val)
+{
+ uint8_t *q;
+ q = *pp;
+ *q++ = val;
+ *q++ = val >> 8;
+ *pp = q;
+}
+
+static void putle32(uint8_t **pp, int val)
+{
+ uint8_t *q;
+ q = *pp;
+ *q++ = val;
+ *q++ = val >> 8;
+ *q++ = val >> 16;
+ *q++ = val >> 24;
+ *pp = q;
+}
+
+static int mpf_checksum(const uint8_t *data, int len)
+{
+ int sum, i;
+ sum = 0;
+ for(i = 0; i < len; i++)
+ sum += data[i];
+ return sum & 0xff;
+}
+
+static unsigned long align(unsigned long addr, unsigned long v)
+{
+ return (addr + v - 1) & ~(v - 1);
+}
+
+static void mptable_init(void)
+{
+ uint8_t *mp_config_table, *q, *float_pointer_struct;
+ int ioapic_id, i, len;
+ int mp_config_table_size;
+
+#ifdef BX_USE_EBDA_TABLES
+ mp_config_table = (uint8_t *)(ram_size - ACPI_DATA_SIZE - MPTABLE_MAX_SIZE);
+#else
+ bios_table_cur_addr = align(bios_table_cur_addr, 16);
+ mp_config_table = (uint8_t *)bios_table_cur_addr;
+#endif
+ q = mp_config_table;
+ putstr(&q, "PCMP"); /* "PCMP signature */
+ putle16(&q, 0); /* table length (patched later) */
+ putb(&q, 4); /* spec rev */
+ putb(&q, 0); /* checksum (patched later) */
+#ifdef BX_QEMU
+ putstr(&q, "QEMUCPU "); /* OEM id */
+#else
+ putstr(&q, "BOCHSCPU");
+#endif
+ putstr(&q, "0.1 "); /* vendor id */
+ putle32(&q, 0); /* OEM table ptr */
+ putle16(&q, 0); /* OEM table size */
+ putle16(&q, smp_cpus + 18); /* entry count */
+ putle32(&q, 0xfee00000); /* local APIC addr */
+ putle16(&q, 0); /* ext table length */
+ putb(&q, 0); /* ext table checksum */
+ putb(&q, 0); /* reserved */
+
+ for(i = 0; i < smp_cpus; i++) {
+ putb(&q, 0); /* entry type = processor */
+ putb(&q, i); /* APIC id */
+ putb(&q, 0x11); /* local APIC version number */
+ if (i == 0)
+ putb(&q, 3); /* cpu flags: enabled, bootstrap cpu */
+ else
+ putb(&q, 1); /* cpu flags: enabled */
+ putb(&q, 0); /* cpu signature */
+ putb(&q, 6);
+ putb(&q, 0);
+ putb(&q, 0);
+ putle16(&q, 0x201); /* feature flags */
+ putle16(&q, 0);
+
+ putle16(&q, 0); /* reserved */
+ putle16(&q, 0);
+ putle16(&q, 0);
+ putle16(&q, 0);
+ }
+
+ /* isa bus */
+ putb(&q, 1); /* entry type = bus */
+ putb(&q, 0); /* bus ID */
+ putstr(&q, "ISA ");
+
+ /* ioapic */
+ ioapic_id = smp_cpus;
+ putb(&q, 2); /* entry type = I/O APIC */
+ putb(&q, ioapic_id); /* apic ID */
+ putb(&q, 0x11); /* I/O APIC version number */
+ putb(&q, 1); /* enable */
+ putle32(&q, 0xfec00000); /* I/O APIC addr */
+
+ /* irqs */
+ for(i = 0; i < 16; i++) {
+#ifdef BX_QEMU
+ /* One entry per ioapic input. Input 2 is covered by
+ irq0->inti2 override (i == 0). irq 2 is unused */
+ if (i == 2)
+ continue;
+#endif
+ putb(&q, 3); /* entry type = I/O interrupt */
+ putb(&q, 0); /* interrupt type = vectored interrupt */
+ putb(&q, 0); /* flags: po=0, el=0 */
+ putb(&q, 0);
+ putb(&q, 0); /* source bus ID = ISA */
+ putb(&q, i); /* source bus IRQ */
+ putb(&q, ioapic_id); /* dest I/O APIC ID */
+#ifdef BX_QEMU
+ putb(&q, i == 0 ? 2 : i); /* dest I/O APIC interrupt in */
+#else
+ putb(&q, i); /* dest I/O APIC interrupt in */
+#endif
+ }
+ /* patch length */
+ len = q - mp_config_table;
+ mp_config_table[4] = len;
+ mp_config_table[5] = len >> 8;
+
+ mp_config_table[7] = -mpf_checksum(mp_config_table, q - mp_config_table);
+
+ mp_config_table_size = q - mp_config_table;
+
+#ifndef BX_USE_EBDA_TABLES
+ bios_table_cur_addr += mp_config_table_size;
+#endif
+
+ /* floating pointer structure */
+#ifdef BX_USE_EBDA_TABLES
+ ebda_cur_addr = align(ebda_cur_addr, 16);
+ float_pointer_struct = (uint8_t *)ebda_cur_addr;
+#else
+ bios_table_cur_addr = align(bios_table_cur_addr, 16);
+ float_pointer_struct = (uint8_t *)bios_table_cur_addr;
+#endif
+ q = float_pointer_struct;
+ putstr(&q, "_MP_");
+ /* pointer to MP config table */
+ putle32(&q, (unsigned long)mp_config_table);
+
+ putb(&q, 1); /* length in 16 byte units */
+ putb(&q, 4); /* MP spec revision */
+ putb(&q, 0); /* checksum (patched later) */
+ putb(&q, 0); /* MP feature byte 1 */
+
+ putb(&q, 0);
+ putb(&q, 0);
+ putb(&q, 0);
+ putb(&q, 0);
+ float_pointer_struct[10] =
+ -mpf_checksum(float_pointer_struct, q - float_pointer_struct);
+#ifdef BX_USE_EBDA_TABLES
+ ebda_cur_addr += (q - float_pointer_struct);