Added plex86 directory to bochs. This directory contains the
new experimental stripped-down version of plex86, which is now a user-code-only VM. I ripped out all the fancy stuff in plex86, such that under that right conditions, user-code (protection level 3) can run at near native speeds inside the plex86 VM. The general idea is that bochs emulates all the initial real-mode code, and guest kernel code (protection level 0). When it senses the right conditions (like the context switches to user-code), a shim is called to execute the guest inside the plex86 VM. All guest-generated faults/exceptions are then forwarded back to bochs to be handled in the emulator. Actually, I'm not yet adding the mods to the bochs code (other than the shim code which is in a separate file), until I hear that we're back in a more development mode with bochs after the 2.0 release. The plex86 subdirectory is really a separate project. It's just more convenient to co-develop it with bochs for now. Both projects are currently LGPL, but each should be taken to be a separate project, and have their own license file. Plex86 (it's only a kernel driver now) could ultimately be used with other projects, as it's modular. I talked with Bryce, and we both agreed it's OK to keep plex86 as a subdir in bochs for now.
This commit is contained in:
parent
1cfe6c248a
commit
0768d01522
504
bochs/plex86/COPYING
Normal file
504
bochs/plex86/COPYING
Normal file
@ -0,0 +1,504 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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!
|
||||
|
||||
|
46
bochs/plex86/Makefile.in
Normal file
46
bochs/plex86/Makefile.in
Normal file
@ -0,0 +1,46 @@
|
||||
# plex86: run multiple x86 operating systems concurrently
|
||||
# Copyright (C) 1999-2000 Kevin P. Lawton
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
.PHONY: all clean dist-clean
|
||||
|
||||
|
||||
# Get variables from shell, or override if specified to make
|
||||
CC = @CC@
|
||||
CFLAGS = @CFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
MDEFINES = CC="$(CC)" CFLAGS="$(CFLAGS)" \
|
||||
LDFLAGS="$(LDFLAGS)"
|
||||
|
||||
all:
|
||||
$(MAKE) -C kernel $(MDEFINES)
|
||||
|
||||
|
||||
clean:
|
||||
$(MAKE) -C kernel clean
|
||||
|
||||
dist-clean:
|
||||
$(MAKE) -C kernel dist-clean
|
||||
/bin/rm -f config.status config.cache config.log
|
||||
/bin/rm -f Makefile config.h
|
||||
|
||||
Makefile: Makefile.in config.status
|
||||
CONFIG_FILES=Makefile CONFIG_HEADERS= $(SHELL) config.status
|
||||
|
17
bochs/plex86/PERFORMANCE
Normal file
17
bochs/plex86/PERFORMANCE
Normal file
@ -0,0 +1,17 @@
|
||||
PERFORMANCE
|
||||
===========
|
||||
|
||||
Optimize functions in util-nexus.c: mon_memzero, mon_memcpy, mon_memset
|
||||
They could be done a lot more efficiently.
|
||||
Perhaps make mon_memzero function specifically for pages.
|
||||
|
||||
Pseudo devices and special guest-OS specific device drivers for
|
||||
disk/network/video/etc and an associated architecture. This would
|
||||
let us pass data more quickly and prevent a lot of emulation overhead.
|
||||
The real device emulation could plug into the same architecture as
|
||||
the pseudo devices.
|
||||
|
||||
|
||||
Fix extra CR3 reload in nexus.S
|
||||
|
||||
Alignment of routines in mon-fault.c
|
93
bochs/plex86/TODO
Normal file
93
bochs/plex86/TODO
Normal file
@ -0,0 +1,93 @@
|
||||
Synchronize page writes with iCache in bochs.
|
||||
|
||||
Deal with cycle counts of guest execution in VM, and in
|
||||
bochs/plex86 shim.
|
||||
|
||||
Complete the CPUID info passing between bochs/plex86.
|
||||
|
||||
Make a host-null.c file to demonstrate/test the OS-specific
|
||||
files that are needed for a host port.
|
||||
|
||||
Deal with page_usage. How do we update this between timeslices?
|
||||
Do we always clear it? Maybe we should keep a log of things to
|
||||
clear (page_usage, GDT entries, PDE entries, ...) and clear those
|
||||
before returning to user space.
|
||||
|
||||
monpanic breaks up into 2 monprints which hit user space twice.
|
||||
|
||||
Task segment must be a 32-bit'er.
|
||||
|
||||
Save/restore floating point state of host/VM.
|
||||
|
||||
pack guest_cpu_t structure.
|
||||
|
||||
deduct off some cycles for the IRET/int sequence.
|
||||
|
||||
Delete use of vm->addr, and split print-nexus into parts so we can
|
||||
use direct host or guest fields. I don't like having implicit
|
||||
pointer usage.
|
||||
|
||||
Not compiled for debug
|
||||
Compiled for BX_SMP_PROCESSORS == 1
|
||||
cpuid match
|
||||
x86 host
|
||||
|
||||
monitor uses slots 1,2,3 so guest ring3 should not
|
||||
use these slots.
|
||||
|
||||
FIX a20 in system fields.
|
||||
FIX use of CPL in paging-mon.c. We can eliminate any
|
||||
code other than CPL==3.
|
||||
|
||||
|
||||
==================== From previous plex86 TODO file ====================
|
||||
|
||||
This is a list of the major tasks/achievements/milestones yet to-do.
|
||||
We should keep this list prioritized, creating sort of a road map.
|
||||
Hopefully, this will reduce duplicate suggestions on the developers
|
||||
channels, and let people know where we are in the development process.
|
||||
Entries listed first have highest priority.
|
||||
|
||||
<NEAR-TERM>
|
||||
- Fix plex86 on Linux 2.4.x/SMP or with 1P and LAPIC enabled.
|
||||
|
||||
- Save FPU state on host <--> monitor context switch.
|
||||
|
||||
- Special guest-specific drivers and special emulated pseudo-devices
|
||||
for faster graphics/network/disk access.
|
||||
|
||||
- Allow some of the inactive guest pages be host swappable.
|
||||
Currently, all pages are locked down.
|
||||
|
||||
- Many performance enhancements (see PERFORMANCE)
|
||||
|
||||
- Test and get more guests running; list in 'GUESTS'.
|
||||
|
||||
- Allow memory to be mapped anywhere in the physical address
|
||||
space.
|
||||
|
||||
- Allow certain guest pages to be swap eligible by the host.
|
||||
This means they will have to be unavailable by the guest
|
||||
during that time. Need a dynamic algorith for this.
|
||||
|
||||
- Test on 2.4 with SMP/APIC enabled on single processor machine.
|
||||
|
||||
- Deal with guest use of TF.
|
||||
|
||||
- Deal with LDT
|
||||
|
||||
|
||||
Use monitor unmapped IO port handler rather than user space.
|
||||
|
||||
Get rid of VM message count instrumentation spew to kernel log
|
||||
|
||||
unallocVmPages/unreserve_guest_pages called twice,
|
||||
release & teardown.
|
||||
|
||||
move mapMonitor to -host.c
|
||||
|
||||
Zero out GDT when remapped.
|
||||
|
||||
When is mapMonitor called?
|
||||
|
||||
Fix extra PDBR reload in nexus.S
|
63
bochs/plex86/config.h.in
Normal file
63
bochs/plex86/config.h.in
Normal file
@ -0,0 +1,63 @@
|
||||
/* our plex86 compile time configuration options will go here */
|
||||
|
||||
#ifndef _CONFIG_H_
|
||||
#define _CONFIG_H_
|
||||
|
||||
#define VERSION "Plex86 2002/07/11"
|
||||
#define BUGSMAIL "plex86-devel@mail.freesoftware.fsf.org"
|
||||
|
||||
/* Might need these for some host OS. */
|
||||
#define SIZEOF_UNSIGNED_CHAR 0
|
||||
#define SIZEOF_UNSIGNED_SHORT 0
|
||||
#define SIZEOF_UNSIGNED_INT 0
|
||||
#define SIZEOF_UNSIGNED_LONG 0
|
||||
#define SIZEOF_UNSIGNED_LONG_LONG 0
|
||||
|
||||
#if SIZEOF_UNSIGNED_CHAR != 1
|
||||
# error "sizeof (unsigned char) != 1"
|
||||
#else
|
||||
typedef unsigned char Bit8u;
|
||||
typedef signed char Bit8s;
|
||||
#endif
|
||||
|
||||
#if SIZEOF_UNSIGNED_SHORT != 2
|
||||
# error "sizeof (unsigned short) != 2"
|
||||
#else
|
||||
typedef unsigned short Bit16u;
|
||||
typedef signed short Bit16s;
|
||||
#endif
|
||||
|
||||
#if SIZEOF_UNSIGNED_INT == 4
|
||||
typedef unsigned int Bit32u;
|
||||
typedef signed int Bit32s;
|
||||
#elif SIZEOF_UNSIGNED_LONG == 4
|
||||
typedef unsigned long Bit32u;
|
||||
typedef signed long Bit32s;
|
||||
#else
|
||||
# error "can't find sizeof(type) of 4 bytes!"
|
||||
#endif
|
||||
|
||||
#if SIZEOF_UNSIGNED_LONG == 8
|
||||
typedef unsigned long Bit64u;
|
||||
typedef signed long Bit64s;
|
||||
#elif SIZEOF_UNSIGNED_LONG_LONG == 8
|
||||
typedef unsigned long long Bit64u;
|
||||
typedef signed long long Bit64s;
|
||||
#else
|
||||
# error "can't find data type of 8 bytes"
|
||||
#endif
|
||||
|
||||
typedef unsigned int Boolean;
|
||||
|
||||
/*
|
||||
* NetBSD just has off_t, which is 64 bits, not loff_t.
|
||||
*/
|
||||
#ifdef __NetBSD__
|
||||
typedef unsigned long long loff_t;
|
||||
#endif
|
||||
|
||||
|
||||
/* Some plex86 customization options. */
|
||||
#define ANAL_CHECKS 1
|
||||
|
||||
#endif /* _CONFIG_H_ */
|
2535
bochs/plex86/configure
vendored
Executable file
2535
bochs/plex86/configure
vendored
Executable file
File diff suppressed because it is too large
Load Diff
169
bochs/plex86/configure.in
Normal file
169
bochs/plex86/configure.in
Normal file
@ -0,0 +1,169 @@
|
||||
dnl // Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.4)
|
||||
AC_INIT(COPYING)
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
|
||||
changequote(<<, >>)
|
||||
changequote([, ])
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_RANLIB
|
||||
|
||||
AC_PATH_XTRA
|
||||
|
||||
AC_C_INLINE
|
||||
AC_CHECK_SIZEOF(unsigned char, 0)
|
||||
AC_CHECK_SIZEOF(unsigned short, 0)
|
||||
AC_CHECK_SIZEOF(unsigned int, 0)
|
||||
AC_CHECK_SIZEOF(unsigned long, 0)
|
||||
AC_CHECK_SIZEOF(unsigned long long, 0)
|
||||
|
||||
dnl When compiling with gcc, use appropriate warning level
|
||||
if test "$GCC" = "yes"; then
|
||||
CFLAGS="$CFLAGS -Wall -Wstrict-prototypes"
|
||||
fi
|
||||
if test "$GXX" = "yes"; then
|
||||
CXXFLAGS="$CXXFLAGS -Wall -Wstrict-prototypes"
|
||||
fi
|
||||
|
||||
AC_ARG_WITH(WinNT,
|
||||
[ --with-WinNT WinNT host],
|
||||
)
|
||||
|
||||
AC_ARG_WITH(BeOS,
|
||||
[ --with-BeOS BeOS host],
|
||||
)
|
||||
|
||||
AC_ARG_WITH(Linux,
|
||||
[ --with-Linux Linux host],
|
||||
)
|
||||
|
||||
AC_ARG_WITH(NetBSD,
|
||||
[ --with-NetBSD NetBSD host],
|
||||
)
|
||||
|
||||
AC_ARG_WITH(FreeBSD,
|
||||
[ --with-FreeBSD FreeBSD host],
|
||||
)
|
||||
|
||||
AC_ARG_WITH(null,
|
||||
[ --with-null No real host],
|
||||
)
|
||||
|
||||
AC_ARG_WITH(linux-source,
|
||||
[ --with-linux-source=dir Linux kernel source dir],
|
||||
[ LINUX_SRC="$withval" ],
|
||||
[ LINUX_SRC="/lib/modules/`uname -r`/build" ]
|
||||
)
|
||||
AC_SUBST(LINUX_SRC)
|
||||
|
||||
AC_ARG_WITH(netbsd-source,
|
||||
[ --with-netbsd-source=dir NetBSD kernel source dir],
|
||||
[ NETBSD_SRC="$withval" ],
|
||||
[ NETBSD_SRC="/sys" ]
|
||||
)
|
||||
AC_SUBST(NETBSD_SRC)
|
||||
|
||||
AC_ARG_WITH(freebsd-source,
|
||||
[ --with-freebsd-source=dir FreeBSD kernel source dir],
|
||||
[ FREEBSD_SRC="$withval" ],
|
||||
[ FREEBSD_SRC="/sys" ]
|
||||
)
|
||||
AC_SUBST(FREEBSD_SRC)
|
||||
|
||||
dnl // make sure Linux is default host if no other chosen
|
||||
if test "$with_Linux" != yes && \
|
||||
test "$with_BeOS" != yes && \
|
||||
test "$with_NetBSD" != yes && \
|
||||
test "$with_FreeBSD" != yes && \
|
||||
test "$with_null" != yes && \
|
||||
test "$with_WinNT" != yes; then
|
||||
with_Linux=yes
|
||||
fi
|
||||
|
||||
if test "$with_Linux" = yes; then
|
||||
HOST_O=host-linux.o
|
||||
KERNEL_TARGET=plex86.o
|
||||
HOST_TARGET=linux-target
|
||||
HOST_CLEAN=linux-clean
|
||||
HOSTOS=LINUX
|
||||
FULL_LINK=
|
||||
elif test "$with_BeOS" = yes; then
|
||||
HOST_O=host-beos.o
|
||||
KERNEL_TARGET=plex86
|
||||
HOST_TARGET=
|
||||
HOST_CLEAN=
|
||||
HOSTOS=BEOS
|
||||
FULL_LINK=
|
||||
elif test "$with_NetBSD" = yes; then
|
||||
HOST_O=host-netbsd.o
|
||||
KERNEL_TARGET=plex86.o
|
||||
HOST_TARGET=netbsd-target
|
||||
HOST_CLEAN=netbsd-clean
|
||||
HOSTOS=NETBSD
|
||||
FULL_LINK=
|
||||
elif test "$with_FreeBSD" = yes; then
|
||||
HOST_O=host-freebsd.o
|
||||
KERNEL_TARGET=plex86.o
|
||||
HOST_TARGET=freebsd-target
|
||||
HOST_CLEAN=freebsd-clean
|
||||
HOSTOS=FREEBSD
|
||||
FULL_LINK=
|
||||
elif test "$with_null" = yes; then
|
||||
HOST_O=host-null.o
|
||||
KERNEL_TARGET=plex86.o
|
||||
HOST_TARGET=null-target
|
||||
HOST_CLEAN=null-clean
|
||||
HOSTOS=NULL
|
||||
FULL_LINK='$(CC) -o a.out plex86.o'
|
||||
else
|
||||
echo " "
|
||||
echo "ERROR: Your system is not supported yet"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
dnl // code to test if CFLAGS is set. If not, use defaults
|
||||
AC_SUBST(HOST_O)
|
||||
AC_SUBST(KERNEL_TARGET)
|
||||
AC_SUBST(HOST_TARGET)
|
||||
AC_SUBST(HOST_CLEAN)
|
||||
AC_SUBST(HOSTOS)
|
||||
AC_SUBST(FULL_LINK)
|
||||
|
||||
SUFFIX_LINE='.SUFFIXES: .cc'
|
||||
CPP_SUFFIX='cc'
|
||||
DASH="-"
|
||||
SLASH="/"
|
||||
CXXFP=""
|
||||
CFP=""
|
||||
OFP="-o "
|
||||
MAKELIB="ar rv \$@"
|
||||
RMCOMMAND="rm -f "
|
||||
EXE=""
|
||||
COMMAND_SEPARATOR="&& \\"
|
||||
CD_UP_ONE="echo done"
|
||||
CD_UP_TWO="echo done"
|
||||
INSTRUMENT_DIR='instrument/'
|
||||
VIDEO_OBJS='$(VIDEO_OBJS_VGA)'
|
||||
|
||||
AC_SUBST(SUFFIX_LINE)
|
||||
AC_SUBST(CPP_SUFFIX)
|
||||
AC_SUBST(DASH)
|
||||
AC_SUBST(SLASH)
|
||||
AC_SUBST(CXXFP)
|
||||
AC_SUBST(CFP)
|
||||
AC_SUBST(OFP)
|
||||
AC_SUBST(MAKELIB)
|
||||
AC_SUBST(RMCOMMAND)
|
||||
AC_SUBST(EXE)
|
||||
AC_SUBST(COMMAND_SEPARATOR)
|
||||
AC_SUBST(CD_UP_ONE)
|
||||
AC_SUBST(CD_UP_TWO)
|
||||
|
||||
AC_OUTPUT([
|
||||
Makefile
|
||||
kernel/Makefile
|
||||
])
|
128
bochs/plex86/descriptor.h
Normal file
128
bochs/plex86/descriptor.h
Normal file
@ -0,0 +1,128 @@
|
||||
/************************************************************************
|
||||
* $Id: descriptor.h,v 1.1 2003-01-01 17:32:04 kevinlawton Exp $
|
||||
************************************************************************
|
||||
*
|
||||
* plex86: run multiple x86 operating systems concurrently
|
||||
* Copyright (C) 1999-2003 Kevin P. Lawton
|
||||
*
|
||||
* descriptor.h: defines for descriptors and selectors
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __DESCRIPTOR_H__
|
||||
#define __DESCRIPTOR_H__
|
||||
|
||||
#define SET_DESCRIPTOR(d, B, L, G, DB, AVL, P, DPL, T) {\
|
||||
d.base_high = (B) >> 24;\
|
||||
d.base_med = ((B) >> 16) & 0xff;\
|
||||
d.base_low = (B) & 0xffff;\
|
||||
d.limit_high = ((L) & 0xf0000) >> 16;\
|
||||
d.limit_low = ((L) & 0x0ffff);\
|
||||
d.g = (G);\
|
||||
d.d_b = (DB);\
|
||||
d.reserved = 0;\
|
||||
d.avl = (AVL);\
|
||||
d.p = (P);\
|
||||
d.dpl = (DPL);\
|
||||
d.type = (T);\
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
Bit16u limit_low; /* limit 0..15 */
|
||||
Bit16u base_low; /* base 0..15 */
|
||||
Bit8u base_med; /* base 16..23 */
|
||||
unsigned type:5; /* S/type field */
|
||||
unsigned dpl:2; /* DPL */
|
||||
unsigned p:1; /* present */
|
||||
unsigned limit_high:4; /* limit 16..19 */
|
||||
unsigned avl:1; /* Available for use by system software */
|
||||
unsigned reserved:1; /* 0 */
|
||||
unsigned d_b:1; /* D/B */
|
||||
unsigned g:1; /* granularity */
|
||||
Bit8u base_high; /* base 24..31 */
|
||||
} __attribute__ ((packed)) descriptor_t;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
Bit16u rpl:2;
|
||||
Bit16u ti:1;
|
||||
Bit16u index:13;
|
||||
} __attribute__ ((packed)) fields;
|
||||
Bit16u raw;
|
||||
} __attribute__ ((packed)) selector_t;
|
||||
|
||||
#define D_DPL0 0
|
||||
#define D_DPL1 1
|
||||
#define D_DPL2 2
|
||||
#define D_DPL3 3
|
||||
|
||||
#define D_BG 0
|
||||
#define D_PG 1
|
||||
|
||||
#define D_D16 0
|
||||
#define D_D32 1
|
||||
|
||||
#define D_NOTPRESENT 0
|
||||
#define D_PRESENT 1
|
||||
|
||||
#define D_S 0x10
|
||||
#define D_DATA 0x10
|
||||
#define D_CODE 0x18
|
||||
#define D_EXECUTE 0x08
|
||||
#define D_EXDOWN 0x04
|
||||
#define D_CONFORM 0x04
|
||||
#define D_WRITE 0x02 /* writable (data segment) */
|
||||
#define D_READ 0x02 /* readable (code segment) */
|
||||
#define D_ACCESSED 0x01
|
||||
|
||||
#define D_LDT 0x02 /* LDT segment */
|
||||
#define D_TASK 0x05 /* Task gate */
|
||||
#define D_TSS 0x09 /* TSS */
|
||||
#define D_CALL 0x0C /* 386 call gate */
|
||||
#define D_INT 0x0E /* 386 interrupt gate */
|
||||
#define D_TRAP 0x0F /* 386 trap gate */
|
||||
|
||||
#define D_AVL0 0
|
||||
#define D_AVL1 1
|
||||
|
||||
#define LimitOfDataDescriptor(d) \
|
||||
( d.g ? \
|
||||
( ((d.type & 0xc) == 0x4) ? \
|
||||
((d.limit_high << 16) | d.limit_low)<<12 : \
|
||||
((d.limit_high << 16) | d.limit_low)<<12 | 0xfff) : \
|
||||
((d.limit_high << 16) | d.limit_low) )
|
||||
|
||||
#define BaseOfDescriptor(d) \
|
||||
( (d.base_low) | (d.base_med << 16) | (d.base_high << 24) )
|
||||
|
||||
/*
|
||||
* selector stuff
|
||||
*/
|
||||
|
||||
#define Selector(sel, ti, rpl) (((sel)<<3) | ((ti)<<2) | (rpl))
|
||||
#define RPL0 0
|
||||
#define RPL1 1
|
||||
#define RPL2 2
|
||||
#define RPL3 3
|
||||
|
||||
typedef struct {
|
||||
Bit16u limit;
|
||||
Bit32u base;
|
||||
} __attribute__ ((packed)) gdt_info_t;
|
||||
|
||||
|
||||
#endif /* __DESCRIPTOR_H__ */
|
127
bochs/plex86/kernel/Makefile.in
Normal file
127
bochs/plex86/kernel/Makefile.in
Normal file
@ -0,0 +1,127 @@
|
||||
# plex86: run multiple x86 operating systems concurrently
|
||||
# Copyright (C) 1999-2001 Kevin P. Lawton
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
CC = @CC@
|
||||
CFLAGS = @CFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
KERNEL_TARGET = @KERNEL_TARGET@
|
||||
HOST_TARGET = @HOST_TARGET@
|
||||
HOST_CLEAN = @HOST_CLEAN@
|
||||
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
LD = ld
|
||||
|
||||
HOST_O = @HOST_O@
|
||||
|
||||
# extra kernel CFLAGS and LDFLAGS for each host OS
|
||||
KCFLAGS_LINUX = -fno-strength-reduce -fomit-frame-pointer \
|
||||
-malign-loops=2 -malign-jumps=2 -malign-functions=2 \
|
||||
-D__KERNEL__ -I@LINUX_SRC@/include -DCPU=586 -DMODULE
|
||||
KLDFLAGS_LINUX = -r
|
||||
|
||||
|
||||
KCFLAGS_NULL = -fno-strength-reduce -fomit-frame-pointer \
|
||||
-malign-loops=2 -malign-jumps=2 -malign-functions=2 \
|
||||
-D__KERNEL__ -DCPU=586
|
||||
KLDFLAGS_NULL = -r
|
||||
|
||||
|
||||
KCFLAGS_NETBSD = -fno-strength-reduce -nostdinc -fomit-frame-pointer \
|
||||
-malign-loops=2 -malign-jumps=2 -malign-functions=2 \
|
||||
-D_KERNEL -I@NETBSD_SRC@ -I@NETBSD_SRC@/arch -I. -D_LKM
|
||||
KLDFLAGS_NETBSD = -r
|
||||
|
||||
|
||||
KCFLAGS_FREEBSD = -fno-strength-reduce -nostdinc -fomit-frame-pointer \
|
||||
-malign-loops=2 -malign-jumps=2 -malign-functions=2 \
|
||||
-D_KERNEL -I@FREEBSD_SRC@ -I@FREEBSD_SRC@/sys -I. -D_LKM \
|
||||
-DFREEBSD_PLEX86_DEBUG
|
||||
KLDFLAGS_FREEBSD = -r
|
||||
|
||||
KCFLAGS_BEOS =
|
||||
KLDFLAGS_BEOS = -nostdlib /boot/develop/lib/x86/_KERNEL_
|
||||
|
||||
KLDFLAGS = $(KLDFLAGS_@HOSTOS@)
|
||||
|
||||
ALL_CFLAGS = $(CFLAGS) $(KCFLAGS_@HOSTOS@) -I$(srcdir)/include -I$(srcdir)/..
|
||||
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(ALL_CFLAGS) $<
|
||||
.S.o:
|
||||
$(CC) -c $(ALL_CFLAGS) -D__ASSEMBLY__ $<
|
||||
|
||||
main_target: $(HOST_TARGET) $(KERNEL_TARGET)
|
||||
@FULL_LINK@
|
||||
|
||||
$(KERNEL_TARGET): $(HOST_O) monitor-host.o \
|
||||
nexus.o print-nexus.o \
|
||||
util-nexus.o \
|
||||
fault-mon.o panic-mon.o \
|
||||
paging-mon.o monitor-mon.o
|
||||
$(LD) $(KLDFLAGS) $^ -o $@
|
||||
|
||||
clean: $(HOST_CLEAN) main_clean
|
||||
|
||||
main_clean:
|
||||
/bin/rm -f *.o *.s $(KERNEL_TARGET) a.out
|
||||
|
||||
dist-clean: clean
|
||||
/bin/rm -f Makefile
|
||||
|
||||
# Linux specific targets
|
||||
linux-target:
|
||||
|
||||
linux-clean:
|
||||
|
||||
# Null specific targets
|
||||
null-target:
|
||||
|
||||
null-clean:
|
||||
|
||||
|
||||
# NetBSD specific targets
|
||||
netbsd-target: netbsd-machine
|
||||
|
||||
netbsd-machine:
|
||||
ln -sf @NETBSD_SRC@/arch/i386/include machine
|
||||
|
||||
netbsd-clean:
|
||||
/bin/rm -f machine
|
||||
|
||||
# FreeBSD specific targets
|
||||
freebsd-target: freebsd-machine
|
||||
[ -r opt_posix.h ] || touch opt_posix.h
|
||||
|
||||
freebsd-machine:
|
||||
ln -sf @FREEBSD_SRC@/i386/include machine
|
||||
|
||||
freebsd-clean:
|
||||
/bin/rm -f opt_posix.h
|
||||
/bin/rm -f machine
|
||||
|
||||
# BeOS specific targets
|
||||
beos-install: $(KERNEL_TARGET)
|
||||
cp -f $(KERNEL_TARGET) /boot/home/config/add-ons/kernel/drivers/bin
|
||||
mkdir -p /boot/home/config/add-ons/kernel/drivers/dev/misc
|
||||
ln -sf ../../bin/$(KERNEL_TARGET) /boot/home/config/add-ons/kernel/drivers/dev/misc/$(KERNEL_TARGET)
|
||||
|
||||
Makefile: Makefile.in ../config.status
|
||||
cd ..; CONFIG_FILES=kernel/Makefile CONFIG_HEADERS= $(SHELL) config.status
|
306
bochs/plex86/kernel/fault-mon.c
Normal file
306
bochs/plex86/kernel/fault-mon.c
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* plex86: run multiple x86 operating systems concurrently
|
||||
* Copyright (C) 1999-2003 Kevin P. Lawton
|
||||
*
|
||||
* fault-mon.c: fault/int handlers for VM monitor - monitor space.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "plex86.h"
|
||||
#define IN_MONITOR_SPACE
|
||||
#include "monitor.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* The monitor stack frame. When an exception or interrupt occurrs
|
||||
* during the execution of either guest or monitor code, the following
|
||||
* values are pushed.
|
||||
*
|
||||
* ss
|
||||
* esp
|
||||
* eflags Values pushed by the CPU and interrupt stub. To simplify
|
||||
* cs things, the stub pushes an error of zero for those
|
||||
* eip events which don't naturally cause an error push, and
|
||||
* error also pushes the vector of the exception/interrupt.
|
||||
* vector
|
||||
*
|
||||
* eax
|
||||
* ecx
|
||||
* edx General registers, pushed with a PUSHA instruction,
|
||||
* ebx by code below.
|
||||
* <esp>
|
||||
* ebp
|
||||
* esi
|
||||
* edi
|
||||
*
|
||||
* es
|
||||
* ds Segment selectors, pushed by code below.
|
||||
* fs
|
||||
* gs
|
||||
*/
|
||||
|
||||
void handleMonFault(guest_context_t *monContext);
|
||||
|
||||
static inline
|
||||
Bit32u readCR2(void)
|
||||
{
|
||||
Bit32u cr2;
|
||||
asm volatile ("movl %%cr2, %0" : "=r" (cr2));
|
||||
return( cr2 );
|
||||
}
|
||||
|
||||
|
||||
asm (
|
||||
".text \n\t"
|
||||
|
||||
/* __handle_fault: This is called by all of the monitor's fault handler
|
||||
* stubs. A fault could have originated from execution of the guest
|
||||
* (due to virtualization conditions or natural fault generation) or
|
||||
* from the monitor (currently only due to bugs in the monitor).
|
||||
*/
|
||||
".globl __handle_fault \n\t"
|
||||
"__handle_fault: \n\t"
|
||||
" pushal \n\t" /* Save general registers */
|
||||
" pushl %es \n\t" /* Save segment registers */
|
||||
" pushl %ds \n\t"
|
||||
" pushl %fs \n\t"
|
||||
" pushl %gs \n\t"
|
||||
" movl 60(%esp), %eax \n\t" /* CS pushed by CPU from fault */
|
||||
" andl $3, %eax \n\t" /* Check CS.RPL bits */
|
||||
" jz __fault_from_mon \n\t" /* RPL0 means from monitor */
|
||||
|
||||
/* We have determined that the fault was from guest code. Prepare
|
||||
* to call the monitor C code to do most of the fault handling.
|
||||
*/
|
||||
"__fault_from_guest: \n\t"
|
||||
" movl %ss, %eax \n\t" /* Copy SS into DS/ES */
|
||||
" movl %eax, %ds \n\t"
|
||||
" movl %eax, %es \n\t"
|
||||
" cld \n\t" /* gcc-compiled code needs this */
|
||||
" pushl %esp \n\t" /* Push pointer to saved guest context for C call.*/
|
||||
" call handleGuestFault\n\t" /* Call the C monitor fault handler. */
|
||||
" addl $4, %esp \n\t" /* Remove arg from stack. */
|
||||
".globl __ret_to_guest \n\t" /* Fault handled, work back to guest. */
|
||||
"__ret_to_guest: \n\t"
|
||||
/* Return to the guest. Restore registers from the monitor stack. */
|
||||
" popl %gs \n\t" /* Restore guest segments */
|
||||
" popl %fs \n\t"
|
||||
" popl %ds \n\t"
|
||||
" popl %es \n\t"
|
||||
" popal \n\t" /* Restore guest general registers */
|
||||
" addl $8, %esp \n\t" /* Ignore vector and error dwords */
|
||||
" iret \n\t" /* Resume execution of guest */
|
||||
|
||||
|
||||
"__fault_from_mon: \n\t"
|
||||
" cld \n\t" /* gcc-compiled code needs this */
|
||||
" pushl %esp \n\t" /* Push pointer to context. */
|
||||
" call handleMonFault \n\t" /* Call C code for real work */
|
||||
" addl $4, %esp \n\t"
|
||||
/* Return to monitor. Restore state from the monitor stack. */
|
||||
"__ret_to_monitor: \n\t"
|
||||
" popl %gs \n\t" /* Restore monitor segments */
|
||||
" popl %fs \n\t"
|
||||
" popl %ds \n\t"
|
||||
" popl %es \n\t"
|
||||
" popal \n\t" /* Restore monitor general registers */
|
||||
" addl $8, %esp \n\t" /* ignore vector and error dwords */
|
||||
" iret \n\t" /* Resume execution of monitor */
|
||||
|
||||
|
||||
/*
|
||||
* Hardware interrupt handler stub
|
||||
*/
|
||||
".globl __handle_int \n\t" /* Return to monitor code */
|
||||
"__handle_int: \n\t"
|
||||
" pushal \n\t" /* Save guest general registers */
|
||||
" pushl %es \n\t" /* Save guest segment registers */
|
||||
" pushl %ds \n\t"
|
||||
" pushl %fs \n\t"
|
||||
" pushl %gs \n\t"
|
||||
|
||||
" movl %ss, %eax \n\t" /* Copy SS into DS/ES */
|
||||
" movl %eax, %ds \n\t"
|
||||
" movl %eax, %es \n\t"
|
||||
" cld \n\t" /* gcc-compiled code needs this */
|
||||
" pushl %esp \n\t"
|
||||
" call handleInt \n\t" /* monitor interrupt handler */
|
||||
" addl $4, %esp \n\t"
|
||||
" cmpl $0x1, %eax \n\t" /* Was interrupt generated from monitor code? */
|
||||
" je __ret_to_monitor\n\t" /* Yes, so return to monitor code */
|
||||
" jmp __ret_to_guest \n\t" /* No, so return to guest code */
|
||||
);
|
||||
|
||||
|
||||
|
||||
unsigned
|
||||
handleInt(guest_context_t *context)
|
||||
/*
|
||||
* handleInt(): Redirect a hardware interrupt back to the host
|
||||
*/
|
||||
{
|
||||
nexus_t *nexus = (nexus_t *) (((Bit32u) context) & 0xfffff000);
|
||||
vm_t *vm = (vm_t *) nexus->vm;
|
||||
unsigned from_monitor;
|
||||
Bit64u t1;
|
||||
|
||||
t1 = vm_rdtsc();
|
||||
|
||||
if ( (context->cs & 0x0003) == 0x0003 ) {
|
||||
/* End of elapsed guest execution duration. Add elapsed */
|
||||
/* cycles to time framework. */
|
||||
vm->system.cyclesElapsed += (t1 - vm->system.t0);
|
||||
|
||||
from_monitor = 0; /* Event from guest code */
|
||||
}
|
||||
else {
|
||||
from_monitor = 1; /* Event from monitor code */
|
||||
}
|
||||
|
||||
/* Interrupts are off naturally here. */
|
||||
vm->mon_request = MonReqRedirect;
|
||||
vm->redirect_vector = context->vector;
|
||||
vm->guest.__mon2host();
|
||||
return(from_monitor);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
handleGuestFault(guest_context_t *context)
|
||||
/* Handle a fault from the guest. Called from the assembly stub
|
||||
* __handle_fault.
|
||||
*/
|
||||
{
|
||||
nexus_t *nexus = (nexus_t *) (((Bit32u) context) & 0xfffff000);
|
||||
vm_t *vm = (vm_t *) nexus->vm;
|
||||
Bit32u cr2 = readCR2();
|
||||
Bit64u t1;
|
||||
|
||||
/* End of elapsed guest execution duration */
|
||||
t1 = vm_rdtsc();
|
||||
vm->system.cyclesElapsed += (t1 - vm->system.t0);
|
||||
|
||||
#warning "Delete these checks"
|
||||
#if ANAL_CHECKS
|
||||
if ( !context->eflags.fields.if_ )
|
||||
monpanic(vm, "handleGuestFault: guest IF=0.\n");
|
||||
if ( context->eflags.fields.vm )
|
||||
monpanic(vm, "handleGuestFault: eflags.VM=1.\n");
|
||||
#endif
|
||||
|
||||
STI();
|
||||
|
||||
switch ( context->vector ) {
|
||||
case ExceptionDB: /* 1 */
|
||||
monpanic(vm, "handleGuestFault: #DB, method=%u not coded\n",
|
||||
vm->executeMethod);
|
||||
#if 0
|
||||
if (vm->executeMethod == RunGuestNMethodBreakpoint) {
|
||||
/* Breakpoint generated because we requested it via TF=1 */
|
||||
}
|
||||
else {
|
||||
monpanic(vm, "handleGuestFault: #DB, method=%u not coded\n",
|
||||
vm->executeMethod);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case ExceptionBR: /* 5 */
|
||||
monpanic(vm, "handleGuestFault: BR unfinished.\n");
|
||||
/* BOUND instruction fault; array index not in bounds */
|
||||
monpanic(vm, "handleGuestFault: emulate_exception was here.\n");
|
||||
/*emulate_exception(vm, context->vector, 0);*/
|
||||
break;
|
||||
|
||||
case ExceptionDE: /* 0 */
|
||||
case ExceptionBP: /* 3 */
|
||||
case ExceptionOF: /* 4 */
|
||||
case ExceptionNM: /* 7 */
|
||||
case ExceptionMF: /* 16 */
|
||||
toHostGuestFault(vm, context->vector);
|
||||
/*monpanic(vm, "handleGuestFault: DE/BP/OF/NM/MF unfinished.\n");*/
|
||||
/*monpanic(vm, "handleGuestFault: %u\n", context->vector);*/
|
||||
/* emulate_interrupt(vm, context->vector); */
|
||||
break;
|
||||
|
||||
case ExceptionNP: /* 11 */
|
||||
case ExceptionSS: /* 12 */
|
||||
case ExceptionAC: /* 17 */
|
||||
monpanic(vm, "handleGuestFault: NP/SS/AC unfinished.\n");
|
||||
/* use emulate_xyz() */
|
||||
/*interrupt(vm, context->vector, 0, 1, context->error); */
|
||||
monpanic(vm, "handleGuestFault: %u\n", context->vector);
|
||||
break;
|
||||
|
||||
case ExceptionUD: /* 6 */
|
||||
case ExceptionGP: /* 13 */
|
||||
toHostGuestFault(vm, context->vector);
|
||||
break;
|
||||
|
||||
case ExceptionPF: /* 14 */
|
||||
guestPageFault(vm, context, cr2);
|
||||
break;
|
||||
|
||||
default:
|
||||
monpanic(vm, "handleGuestFault: Unhandled Fault: %u\n", context->vector);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
handleMonFault(guest_context_t *monContext)
|
||||
{
|
||||
nexus_t *nexus = (nexus_t *) (((Bit32u) monContext) & 0xfffff000);
|
||||
vm_t *vm = (vm_t *) nexus->vm;
|
||||
|
||||
if (vm->inMonFault)
|
||||
monpanic(vm, "handleMonFault called recursively.\n");
|
||||
vm->inMonFault = 1;
|
||||
monpanic(vm, "handleMonFault: vector=%u\n", monContext->vector);
|
||||
|
||||
/* Fault occurred inside monitor code. */
|
||||
|
||||
switch ( monContext->vector ) {
|
||||
case ExceptionPF:
|
||||
case ExceptionGP:
|
||||
{
|
||||
Bit32u cr2;
|
||||
/*unsigned us, rw;*/
|
||||
|
||||
cr2 = readCR2();
|
||||
STI();
|
||||
|
||||
if (monContext->error & 0x8) /* If RSVD bits used in PDir */
|
||||
monpanic(vm, "handleMF: RSVD\n");
|
||||
/*us = G_GetCPL(vm)==3;*/
|
||||
/*rw = (monContext->error >> 1) & 1;*/
|
||||
monpanic(vm, "handleMF: \n");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
monpanic(vm, "hMF: vector=%u\n", monContext->vector);
|
||||
break;
|
||||
}
|
||||
|
||||
/*vm->abort_code = 1;*/
|
||||
/*monpanic_nomess(vm);*/
|
||||
CLI();
|
||||
vm->inMonFault = 0;
|
||||
}
|
6
bochs/plex86/kernel/freebsd/Makefile
Normal file
6
bochs/plex86/kernel/freebsd/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
# FreeBSD Kernel module makefile
|
||||
|
||||
SRCS= ../plex86.o
|
||||
KMOD= plex86
|
||||
|
||||
.include <bsd.kmod.mk>
|
219
bochs/plex86/kernel/host-beos.c
Normal file
219
bochs/plex86/kernel/host-beos.c
Normal file
@ -0,0 +1,219 @@
|
||||
#include <Drivers.h>
|
||||
#include <KernelExport.h>
|
||||
#include <OS.h>
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "plex86.h"
|
||||
#include "monitor.h"
|
||||
|
||||
|
||||
#define read_flags() ({ \
|
||||
unsigned int __dummy; \
|
||||
__asm__( \
|
||||
"pushfl\n\t" \
|
||||
"popl %0\n\t" \
|
||||
:"=r" (__dummy)); \
|
||||
__dummy; \
|
||||
})
|
||||
#define write_flags(x) \
|
||||
__asm__("push %0\n\tpopfl\n\t": :"r" (x))
|
||||
|
||||
|
||||
|
||||
struct cookie {
|
||||
sem_id sem;
|
||||
|
||||
int mon_ok;
|
||||
|
||||
uint32 irq_cnt[17];
|
||||
};
|
||||
|
||||
static status_t
|
||||
driver_open(const char *name, ulong flags, void **_cookie)
|
||||
{
|
||||
struct cookie *cookie;
|
||||
status_t err;
|
||||
|
||||
cookie = calloc(sizeof(*cookie), 1);
|
||||
if (!cookie)
|
||||
return ENOMEM;
|
||||
cookie->sem = create_sem(1, "plex86 mutex");
|
||||
if (cookie->sem < 0) {
|
||||
err = cookie->sem;
|
||||
goto err1;
|
||||
}
|
||||
*_cookie = cookie;
|
||||
return B_OK;
|
||||
|
||||
err1:
|
||||
free(cookie);
|
||||
return err;
|
||||
}
|
||||
|
||||
static status_t
|
||||
driver_close(void *cookie)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
static status_t
|
||||
driver_free(void *_cookie)
|
||||
{
|
||||
struct cookie *cookie = (struct cookie *)_cookie;
|
||||
delete_sem(cookie->sem);
|
||||
free(cookie);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
static status_t
|
||||
driver_read(void *cookie, off_t pos, void *buf, size_t *count)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
driver_write(void *cookie, off_t pos, const void *buf, size_t *count)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
static status_t
|
||||
driver_ioctl(void *_cookie, ulong cmd, void *buf, size_t len)
|
||||
{
|
||||
struct cookie *cookie = (struct cookie *)_cookie;
|
||||
uint32 cr0, arg, eflags_orig;
|
||||
uchar soft_int_vector;
|
||||
status_t err;
|
||||
|
||||
arg = *(uint32 *)buf;
|
||||
|
||||
switch (cmd) {
|
||||
/* Allocate unpaged memory for the VM. */
|
||||
/* arg is the number of megabytes to allocate */
|
||||
/* Memory returned must not be pageable by the */
|
||||
/* host OS, since the VM monitor will run in this */
|
||||
/* memory as well. Perhaps later, we can let */
|
||||
/* the guest OS run in paged memory and reflect */
|
||||
/* the page faults back to the host OS. */
|
||||
case 0x6b02:
|
||||
acquire_sem(cookie->sem);
|
||||
init_monitor(MASTER_PIC_BASE_VECTOR, SLAVE_PIC_BASE_VECTOR, IRQ16_BASE_VECTOR);
|
||||
cookie->mon_ok = 1;
|
||||
release_sem(cookie->sem);
|
||||
return B_OK;
|
||||
|
||||
case 0x6b03:
|
||||
/* linux-specific hack, unnecessary under BeOS */
|
||||
return B_OK;
|
||||
|
||||
/* run guest context for a time slice */
|
||||
case 0x6b04:
|
||||
{
|
||||
cpu_status ps;
|
||||
|
||||
acquire_sem(cookie->sem);
|
||||
|
||||
if (!cookie->mon_ok) {
|
||||
release_sem(cookie->sem);
|
||||
return EPERM;
|
||||
}
|
||||
|
||||
ps = disable_interrupts();
|
||||
|
||||
/* clear NT/IF/TF */
|
||||
eflags_orig = read_flags();
|
||||
write_flags(eflags_orig & ~0x00004300);
|
||||
|
||||
__host2guest();
|
||||
|
||||
write_flags(eflags_orig & ~0x00000200);
|
||||
|
||||
restore_interrupts(ps);
|
||||
|
||||
switch ( monitor_info.ret_because ) {
|
||||
case RET_BECAUSE_IRQ:
|
||||
/* reported vector is actually the IRQ# */
|
||||
|
||||
soft_int_vector = MASTER_PIC_BASE_VECTOR + monitor_info.vector;
|
||||
soft_int(soft_int_vector);
|
||||
cookie->irq_cnt[monitor_info.vector]++;
|
||||
dprintf("plex86: irq %u\n", monitor_info.vector);
|
||||
err = B_OK;
|
||||
break;
|
||||
|
||||
case RET_BECAUSE_INT:
|
||||
dprintf("plex86: int %u\n", monitor_info.vector);
|
||||
err = EFAULT;
|
||||
break;
|
||||
|
||||
case RET_BECAUSE_EXC:
|
||||
dprintf("plex86: exc %u\n", monitor_info.vector);
|
||||
err = EFAULT;
|
||||
break;
|
||||
|
||||
case RET_BECAUSE_TEST:
|
||||
dprintf("plex86: test\n");
|
||||
err = B_OK;
|
||||
break;
|
||||
|
||||
default:
|
||||
dprintf("plex86: unknown ret_because\n");
|
||||
err = B_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
release_sem(cookie->sem);
|
||||
return err;
|
||||
}
|
||||
|
||||
case 0x6b05: /* tear down VM environment */
|
||||
acquire_sem(cookie->sem);
|
||||
cookie->mon_ok = 0;
|
||||
release_sem(cookie->sem);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
return ENOSYS;
|
||||
}
|
||||
|
||||
device_hooks driver_device = {
|
||||
driver_open,
|
||||
driver_close,
|
||||
driver_free,
|
||||
driver_ioctl,
|
||||
driver_read,
|
||||
driver_write
|
||||
};
|
||||
|
||||
status_t
|
||||
init_driver (void)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void
|
||||
uninit_driver(void)
|
||||
{
|
||||
}
|
||||
|
||||
const char **
|
||||
publish_devices(void)
|
||||
{
|
||||
static const char *driver_names[] = {
|
||||
"misc/plex86",
|
||||
NULL
|
||||
};
|
||||
return (const char **)driver_names;
|
||||
}
|
||||
|
||||
device_hooks *
|
||||
find_device(const char *name)
|
||||
{
|
||||
return &driver_device;
|
||||
}
|
||||
|
569
bochs/plex86/kernel/host-freebsd.c
Normal file
569
bochs/plex86/kernel/host-freebsd.c
Normal file
@ -0,0 +1,569 @@
|
||||
/*
|
||||
* plex86: run multiple x86 operating systems concurrently
|
||||
*
|
||||
* Copyright (C) 2000 Frank van der Linden (fvdl@wasabisystems.com)
|
||||
* Copyright (C) 2000 Alexander Langer <alex@big.endian.de>
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define DIAGNOSTIC 1
|
||||
#define CDEV_MAJOR 20
|
||||
#define timer_t __bsd_timer_t
|
||||
#define write_eflags __freebsd_write_eflags
|
||||
#define read_eflags __freebsd_read_eflags
|
||||
|
||||
/* XXX recheck, which includes are needed */
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <sys/proc.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/exec.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/linker.h>
|
||||
#include <sys/sysproto.h>
|
||||
|
||||
#include <sys/module.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
|
||||
#include <machine/cpu.h>
|
||||
|
||||
#undef timer_t
|
||||
#undef write_eflags
|
||||
#undef read_eflags
|
||||
|
||||
#include "plex86.h"
|
||||
#define IN_HOST_SPACE
|
||||
#include "monitor.h"
|
||||
|
||||
static MALLOC_DEFINE(M_PLEX86, "plex86", "Plex86 mem");
|
||||
|
||||
static d_open_t plex86_open;
|
||||
static d_close_t plex86_close;
|
||||
static d_mmap_t plex86_mmap;
|
||||
static d_ioctl_t plex86_ioctl;
|
||||
|
||||
static unsigned retrieve_phy_pages(Bit32u *, int, void *, unsigned, int);
|
||||
static vm_t *find_vm(struct proc * p);
|
||||
static void register_vm(vm_t * vm, struct proc * p);
|
||||
static void unregister_all(struct proc * p);
|
||||
|
||||
static struct cdevsw plex86_cdevsw = {
|
||||
/* open */ plex86_open,
|
||||
/* close */ plex86_close,
|
||||
/* read */ noread,
|
||||
/* write */ nowrite,
|
||||
/* ioctl */ plex86_ioctl,
|
||||
/* poll */ nopoll,
|
||||
/* mmap */ plex86_mmap,
|
||||
/* strat */ nostrategy,
|
||||
/* name */ "plex86",
|
||||
/* major */ CDEV_MAJOR,
|
||||
/* dump */ nodump,
|
||||
/* psize */ nopsize,
|
||||
/* flags */ 0,
|
||||
/* bmaj */ -1
|
||||
};
|
||||
|
||||
/* For use with make_dev/destroy_dev */
|
||||
static dev_t plex86_dev;
|
||||
|
||||
static struct plex86_softc {
|
||||
int sc_open;
|
||||
} plex86sc;
|
||||
|
||||
monitor_pages_t monitor_pages;
|
||||
|
||||
/*
|
||||
* Hash table stuff to maintain proc <-> vm mapping. 23 entries should be
|
||||
* plenty.. unless someone plans to run more than 23 guest OSs..
|
||||
*
|
||||
* Note that a process can only open the device once with this scheme.
|
||||
*/
|
||||
|
||||
LIST_HEAD(plex86_hashhead, plex86_vmentry);
|
||||
|
||||
struct plex86_vmentry {
|
||||
pid_t vm_pid;
|
||||
vm_t *vm_vm;
|
||||
LIST_ENTRY(plex86_vmentry) vm_entry;
|
||||
};
|
||||
|
||||
struct plex86_hashhead *plex86_hashtbl;
|
||||
u_long plex86_hashmask;
|
||||
|
||||
#define PLEX86_VMHASHSIZE 23
|
||||
#define PLEX86_VMHASH(p) ((u_long)((p)->p_pid) & plex86_hashmask)
|
||||
|
||||
static int
|
||||
plex86_open(dev_t dev, int flags, int fmt, struct proc * p)
|
||||
{
|
||||
vm_t *vm;
|
||||
|
||||
if (suser_xxx(p->p_ucred, p, p->p_acflag) != 0)
|
||||
return (EPERM);
|
||||
|
||||
vm = find_vm(p);
|
||||
if (vm == NULL) {
|
||||
vm = malloc(sizeof(vm_t), M_PLEX86, M_WAITOK);
|
||||
if (vm == NULL)
|
||||
return EIO;
|
||||
memset(vm, 0, sizeof(vm_t));
|
||||
register_vm(vm, p);
|
||||
plex86sc.sc_open++;
|
||||
} else
|
||||
return (EBUSY);
|
||||
|
||||
/* Kernel independent device open code. */
|
||||
hostDeviceOpenInit(vm);
|
||||
|
||||
#ifdef FREEBSD_PLEX86_DEBUG
|
||||
printf("plex86: pid %u opened device, vm %p\n", p->p_pid, vm);
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
plex86_close(dev_t dev, int flags, int fmt, struct proc * p)
|
||||
{
|
||||
unregister_all(p);
|
||||
plex86sc.sc_open = 0;
|
||||
#ifdef FREEBSD_PLEX86_DEBUG
|
||||
printf("plex86: pid %u closed device\n", p->p_pid);
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
plex86_mmap(dev_t dev, vm_offset_t offset, int nprot)
|
||||
{
|
||||
struct proc *p = curproc;
|
||||
int page;
|
||||
vm_offset_t endguestoff;
|
||||
vm_t *vm;
|
||||
|
||||
vm = find_vm(p);
|
||||
if (vm == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
#warning "kludge to mmap message buffer"
|
||||
endguestoff = (vm_offset_t) (vm->pages.guest_n_megs * 1024 * 1024);
|
||||
if (offset >= endguestoff && nprot == PROT_READ) {
|
||||
page = (offset - endguestoff) / PAGE_SIZE;
|
||||
return (vm->pages.log_buffer[page]);
|
||||
}
|
||||
page = offset / PAGE_SIZE;
|
||||
if (page < 0 || page > vm->pages.guest_n_pages) {
|
||||
log(LOG_WARNING, "plex86: mmap: offset %lx out of range\n",
|
||||
(unsigned long) offset);
|
||||
return -1;
|
||||
}
|
||||
return vm->pages.guest[page];
|
||||
}
|
||||
|
||||
int
|
||||
plex86_ioctl(dev_t dev, u_long cmd, caddr_t data, int flags,
|
||||
struct proc * p)
|
||||
{
|
||||
int error;
|
||||
vm_t *vm;
|
||||
|
||||
vm = find_vm(p);
|
||||
if (vm == NULL)
|
||||
return EINVAL;
|
||||
|
||||
switch (cmd) {
|
||||
case PLEX86_ALLOCVPHYS:
|
||||
{
|
||||
unsigned arg = *((unsigned *) data);
|
||||
guest_cpu_t guest_cpu;
|
||||
|
||||
if (vm->mon_state != MON_STATE_UNINITIALIZED ||
|
||||
vm->pages.guest_n_megs != 0)
|
||||
return EBUSY;
|
||||
if (arg > PLEX86_MAX_PHY_MEGS || arg < 4 || (arg & ~0x3) != arg)
|
||||
return EINVAL;
|
||||
|
||||
/* Allocate memory */
|
||||
error = allocVmPages(vm, arg);
|
||||
if (error != 0) {
|
||||
log(LOG_WARNING, "plex86: allocVmPages failed (%d)\n",
|
||||
error);
|
||||
return ENOMEM;
|
||||
}
|
||||
if (init_guest_phy_mem(vm) != 0) {
|
||||
log(LOG_ERR, "plex86: init_guest_phy_mem failed\n");
|
||||
unallocVmPages(vm);
|
||||
return EFAULT;
|
||||
}
|
||||
getCpuResetValues(&guest_cpu);
|
||||
log(LOG_WARNING, "plex86: cpu.cr0 = 0x%x\n", guest_cpu.cr0);
|
||||
if (!init_monitor(vm, 0, 0, &guest_cpu) ||
|
||||
!setGuestCPU(vm, 0, &guest_cpu) ||
|
||||
!mapMonitor(vm, guest_cpu.eflags, 0)) {
|
||||
log(LOG_ERR, "plex86: init_monitor failed\n");
|
||||
unallocVmPages(vm);
|
||||
return EFAULT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PLEX86_TEARDOWN:
|
||||
unallocVmPages(vm);
|
||||
break;
|
||||
|
||||
case PLEX86_ALLOCINT:
|
||||
return EINVAL;
|
||||
case PLEX86_RELEASEINT:
|
||||
return EINVAL;
|
||||
case PLEX86_PRESCANDEPTH:
|
||||
{
|
||||
unsigned long arg = *(unsigned long *) data;
|
||||
|
||||
if ((arg < PrescanDepthMin) || (arg > PrescanDepthMax)) {
|
||||
log(LOG_WARNING, "plex86: Requested prescan depth %lu"
|
||||
" out of range [%u..%u]\n", arg, PrescanDepthMin,
|
||||
PrescanDepthMax);
|
||||
return EINVAL;
|
||||
}
|
||||
vm->prescanDepth = (unsigned) arg;
|
||||
break;
|
||||
}
|
||||
case PLEX86_SETINTR:
|
||||
ioctlSetIntr(vm, *(unsigned long *) data);
|
||||
break;
|
||||
case PLEX86_SET_A20:
|
||||
{
|
||||
unsigned long arg = *(unsigned long *) data;
|
||||
if (!ioctlSetA20E(vm, arg))
|
||||
return EINVAL;
|
||||
break;
|
||||
}
|
||||
case PLEX86_MESSAGEQ:
|
||||
{
|
||||
vm_messages_t msg;
|
||||
|
||||
if (vm->mon_state != MON_STATE_RUNNABLE)
|
||||
return EINVAL;
|
||||
|
||||
error = copyin(*(void **) data, &msg.header, sizeof msg.header);
|
||||
if (error != 0)
|
||||
return error;
|
||||
|
||||
if ((msg.header.msg_len + sizeof(msg.header)) > sizeof(msg))
|
||||
return EINVAL;
|
||||
|
||||
if (msg.header.msg_len != 0) {
|
||||
error = copyin(&((vm_messages_t *) * (void **) data)->msg,
|
||||
&msg.msg, msg.header.msg_len);
|
||||
if (error != 0)
|
||||
return error;
|
||||
}
|
||||
if (ioctlMessageQ(vm, &msg)) {
|
||||
log(LOG_WARNING, "plex86: ioctlMessageQ failed\n");
|
||||
return EINVAL;
|
||||
}
|
||||
error = copyout(&msg, *(void **) data,
|
||||
sizeof(msg.header) + msg.header.msg_len);
|
||||
return error;
|
||||
}
|
||||
case PLEX86_RESET:
|
||||
break;
|
||||
|
||||
case PLEX86_PHYMEM_MOD:
|
||||
break;
|
||||
case PLEX86_FORCE_INT:
|
||||
if (vm->mon_state != MON_STATE_RUNNABLE)
|
||||
return -EINVAL;
|
||||
vm->dbg_force_int = 0x100 | (unsigned) data;
|
||||
break;
|
||||
case PLEX86_PRESCANRING3:
|
||||
{
|
||||
unsigned long arg = *(unsigned long *) data;
|
||||
if (arg > PrescanRing3On) {
|
||||
log(LOG_WARNING,
|
||||
"plex86: Requested PrescanRing3 val(%lu) OOB\n",
|
||||
arg);
|
||||
return EINVAL;
|
||||
}
|
||||
vm->prescanRing3 = arg;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
log(LOG_WARNING, "plex86: unknown ioctl %lx\n", cmd);
|
||||
return EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
register_vm(vm_t * vm, struct proc * p)
|
||||
{
|
||||
struct plex86_hashhead *php;
|
||||
struct plex86_vmentry *vhp;
|
||||
|
||||
php = &plex86_hashtbl[PLEX86_VMHASH(p)];
|
||||
#if DIAGNOSTIC
|
||||
for (vhp = php->lh_first; vhp != NULL; vhp = vhp->vm_entry.le_next) {
|
||||
if (vhp->vm_pid == p->p_pid)
|
||||
panic("plex86: vm already registered, pid %u\n",
|
||||
p->p_pid);
|
||||
}
|
||||
#endif
|
||||
vhp = malloc(sizeof(struct plex86_vmentry), M_PLEX86, M_WAITOK);
|
||||
vhp->vm_pid = p->p_pid;
|
||||
vhp->vm_vm = vm;
|
||||
LIST_INSERT_HEAD(php, vhp, vm_entry);
|
||||
}
|
||||
|
||||
static void
|
||||
unregister_vm(vm_t * vm, struct proc * p)
|
||||
{
|
||||
struct plex86_hashhead *php;
|
||||
struct plex86_vmentry *vhp;
|
||||
|
||||
php = &plex86_hashtbl[PLEX86_VMHASH(p)];
|
||||
for (vhp = php->lh_first; vhp != NULL; vhp = vhp->vm_entry.le_next) {
|
||||
if (vhp->vm_pid == p->p_pid) {
|
||||
LIST_REMOVE(vhp, vm_entry);
|
||||
free(vhp->vm_vm, M_PLEX86);
|
||||
free(vhp, M_PLEX86);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
unregister_all(struct proc * p)
|
||||
{
|
||||
int i;
|
||||
struct plex86_hashhead *php;
|
||||
struct plex86_vmentry *vhp;
|
||||
|
||||
php = &plex86_hashtbl[PLEX86_VMHASH(p)];
|
||||
if (php == NULL)
|
||||
return;
|
||||
for (vhp = php->lh_first; vhp != NULL;
|
||||
vhp = vhp->vm_entry.le_next) {
|
||||
#ifdef FREEBSD_PLEX86_DEBUG
|
||||
printf("plex86: unregister vm %p, pid %u\n",
|
||||
vhp->vm_vm, vhp->vm_pid);
|
||||
#endif
|
||||
LIST_REMOVE(vhp, vm_entry);
|
||||
if (vhp->vm_vm != NULL)
|
||||
free(vhp->vm_vm, M_PLEX86);
|
||||
if (vhp != NULL)
|
||||
free(vhp, M_PLEX86);
|
||||
}
|
||||
}
|
||||
|
||||
static vm_t *
|
||||
find_vm(struct proc * p)
|
||||
{
|
||||
struct plex86_hashhead *php;
|
||||
struct plex86_vmentry *vhp;
|
||||
|
||||
php = &plex86_hashtbl[PLEX86_VMHASH(p)];
|
||||
for (vhp = php->lh_first; vhp != NULL; vhp = vhp->vm_entry.le_next) {
|
||||
if (vhp->vm_pid == p->p_pid)
|
||||
return vhp->vm_vm;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
retrieve_phy_pages(Bit32u * page, int max_pages, void *addr_v, unsigned size,
|
||||
int aligned)
|
||||
{
|
||||
Bit32u start_addr;
|
||||
unsigned n_pages, i;
|
||||
|
||||
if (!aligned)
|
||||
start_addr = (Bit32u) addr_v & ~(PAGE_SIZE - 1);
|
||||
else {
|
||||
start_addr = (Bit32u) addr_v;
|
||||
if (start_addr & (PAGE_SIZE - 1)) {
|
||||
log(LOG_WARNING, "plex86: retrieve_phy_pages: address "
|
||||
"%p not aligned\n", addr_v);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
n_pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||
if (n_pages > max_pages) {
|
||||
log(LOG_WARNING, "plex86: retrieve_phy_pages: page list "
|
||||
"too small\n");
|
||||
return (0);
|
||||
}
|
||||
for (i = 0; i < n_pages; i++) {
|
||||
page[i] = kvtop((vm_offset_t) start_addr) / PAGE_SIZE;
|
||||
start_addr += PAGE_SIZE;
|
||||
}
|
||||
|
||||
return n_pages;
|
||||
}
|
||||
|
||||
unsigned
|
||||
host_idle(void)
|
||||
{
|
||||
#if defined(want_resched)
|
||||
if (want_resched) {
|
||||
#endif
|
||||
yield(curproc, NULL); /* XXX */
|
||||
need_resched(); /* XXX */
|
||||
#if defined(want_resched)
|
||||
}
|
||||
#endif
|
||||
printf("resched done\n");
|
||||
return (CURSIG(curproc) == 0);
|
||||
}
|
||||
|
||||
void *
|
||||
host_alloc(unsigned long size)
|
||||
{
|
||||
/*
|
||||
* XXX - it wants this page-aligned apparently.
|
||||
*/
|
||||
if (size <= (PAGE_SIZE / 2))
|
||||
size = PAGE_SIZE;
|
||||
return (malloc(size, M_PLEX86, M_WAITOK));
|
||||
}
|
||||
|
||||
void
|
||||
host_free(void *ptr)
|
||||
{
|
||||
free(ptr, M_PLEX86);
|
||||
}
|
||||
|
||||
unsigned
|
||||
host_map(Bit32u * page, int max_pages, void *ptr, unsigned size)
|
||||
{
|
||||
return retrieve_phy_pages(page, max_pages, ptr, size, 1);
|
||||
}
|
||||
|
||||
void *
|
||||
host_alloc_page(void)
|
||||
{
|
||||
return malloc(PAGE_SIZE, M_PLEX86, M_WAITOK);
|
||||
}
|
||||
|
||||
void
|
||||
host_free_page(void *ptr)
|
||||
{
|
||||
return free(ptr, M_PLEX86);
|
||||
}
|
||||
|
||||
Bit32u
|
||||
host_map_page(void *ptr)
|
||||
{
|
||||
Bit32u u;
|
||||
|
||||
if (ptr == NULL)
|
||||
return 0;
|
||||
u = kvtop(ptr) / PAGE_SIZE;
|
||||
#if FREEBSD_PLEX86_DEBUG
|
||||
printf("host_map_page(%p) -> %x\n", ptr, u);
|
||||
#endif
|
||||
return u;
|
||||
}
|
||||
|
||||
void
|
||||
hostprint(char *fmt,...)
|
||||
{
|
||||
va_list args;
|
||||
int ret;
|
||||
unsigned char buffer[256];
|
||||
|
||||
va_start(args, fmt);
|
||||
ret = vsnprintf(buffer, 256, fmt, args);
|
||||
if (ret == -1)
|
||||
log(LOG_WARNING,
|
||||
"plex86: hostprint: vsnprintf returns error.\n");
|
||||
else
|
||||
log(LOG_WARNING, "plex86: %s\n", buffer);
|
||||
}
|
||||
|
||||
static int
|
||||
plex86_modevent(module_t mod, int type, void *data)
|
||||
{
|
||||
linker_file_t lf;
|
||||
int error = 0;
|
||||
|
||||
switch (type) {
|
||||
case MOD_LOAD:
|
||||
plex86_hashtbl = NULL;
|
||||
|
||||
lf = linker_find_file_by_name("plex86");
|
||||
if (lf == NULL) {
|
||||
printf("plex86: can't find linker_file 'plex86'\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
monitor_pages.startOffset = lf->address;
|
||||
monitor_pages.startOffsetPageAligned =
|
||||
monitor_pages.startOffset & 0xfffff000;
|
||||
|
||||
if ((monitor_pages.n_pages = retrieve_phy_pages(monitor_pages.page,
|
||||
PLEX86_MAX_MONITOR_PAGES,
|
||||
lf->address,
|
||||
lf->size,
|
||||
0)) == 0) {
|
||||
log(LOG_WARNING, "plex86: could not store physical "
|
||||
"addresses for monitor pages\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
plex86_hashtbl = hashinit(PLEX86_VMHASHSIZE,
|
||||
M_PLEX86, &plex86_hashmask);
|
||||
|
||||
if (!hostModuleInit()) {
|
||||
log(LOG_WARNING, "hostModuleInit error\n");
|
||||
error = EINVAL;
|
||||
}
|
||||
|
||||
plex86_dev = make_dev(&plex86_cdevsw, 0 /* minor */ , UID_ROOT,
|
||||
GID_WHEEL, 0600, "plex86");
|
||||
|
||||
printf("plex86: Module loaded.\n");
|
||||
return (0);
|
||||
break;
|
||||
case MOD_UNLOAD:
|
||||
if (plex86sc.sc_open != 0)
|
||||
return (EBUSY);
|
||||
|
||||
destroy_dev(plex86_dev);
|
||||
|
||||
if (plex86_hashtbl != NULL) {
|
||||
free(plex86_hashtbl, M_PLEX86);
|
||||
}
|
||||
printf("plex86: Module unloaded.\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
error = ENXIO;
|
||||
break;
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
MODULE_VERSION(plex86, 1);
|
||||
DEV_MODULE(plex86, plex86_modevent, 0);
|
854
bochs/plex86/kernel/host-linux.c
Normal file
854
bochs/plex86/kernel/host-linux.c
Normal file
@ -0,0 +1,854 @@
|
||||
/*
|
||||
* plex86: run multiple x86 operating systems concurrently
|
||||
* Copyright (C) 1999-2003 Kevin P. Lawton
|
||||
*
|
||||
* host-linux.c: Linux specific VM host driver functionality
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "plex86.h"
|
||||
#define IN_HOST_SPACE
|
||||
#include "monitor.h"
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/wrapper.h>
|
||||
#include <linux/version.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
|
||||
#ifndef VERSION_CODE
|
||||
# define VERSION_CODE(vers,rel,seq) ( ((vers)<<16) | ((rel)<<8) | (seq) )
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)
|
||||
# include <asm/uaccess.h>
|
||||
#endif
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Compatibility macros for older kernels */
|
||||
/************************************************************************/
|
||||
|
||||
#ifndef EXPORT_NO_SYMBOLS
|
||||
# define EXPORT_NO_SYMBOLS register_symtab(NULL)
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,29)
|
||||
# define proc_register_dynamic proc_register
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < VERSION_CODE(2,2,0)
|
||||
#define NEED_RESCHED need_resched
|
||||
#else
|
||||
#define NEED_RESCHED current->need_resched
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < VERSION_CODE(2,1,0)
|
||||
static inline unsigned long copy_from_user(void *to, const void *from, unsigned long n)
|
||||
{
|
||||
int i;
|
||||
if ((i = verify_area(VERIFY_READ, from, n)) != 0)
|
||||
return i;
|
||||
memcpy_fromfs(to, from, n);
|
||||
return 0;
|
||||
}
|
||||
static inline unsigned long copy_to_user(void *to, const void *from, unsigned long n)
|
||||
{
|
||||
int i;
|
||||
if ((i = verify_area(VERIFY_WRITE, to, n)) != 0)
|
||||
return i;
|
||||
memcpy_tofs(to, from, n);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,18) && !defined(THIS_MODULE)
|
||||
/* Starting with version 2.1.18, the __this_module symbol is present,
|
||||
but the THIS_MODULE #define was introduced much later ... */
|
||||
#define THIS_MODULE (&__this_module)
|
||||
#endif
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Declarations */
|
||||
/************************************************************************/
|
||||
|
||||
/* Use dynamic major number allocation. (Set non-zero for static allocation) */
|
||||
#define PLEX86_MAJOR 0
|
||||
static int plex_major = PLEX86_MAJOR;
|
||||
#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,18)
|
||||
MODULE_PARM(plex_major, "i");
|
||||
MODULE_PARM_DESC(plex_major, "major number (default " __MODULE_STRING(PLEX86_MAJOR) ")");
|
||||
#endif
|
||||
|
||||
/* The kernel segment base */
|
||||
#if LINUX_VERSION_CODE < VERSION_CODE(2,1,0)
|
||||
# define KERNEL_OFFSET 0xc0000000
|
||||
#else
|
||||
# define KERNEL_OFFSET 0x00000000
|
||||
#endif
|
||||
|
||||
|
||||
/* File operations */
|
||||
static int plex86_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
|
||||
static int plex86_open(struct inode *, struct file *);
|
||||
|
||||
#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,31)
|
||||
static int plex86_release(struct inode *, struct file *);
|
||||
#else
|
||||
static void plex86_release(struct inode *, struct file *);
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)
|
||||
static int plex86_mmap(struct file * file, struct vm_area_struct * vma);
|
||||
#else
|
||||
static int plex86_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma);
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,9)
|
||||
/* New License scheme */
|
||||
#ifdef MODULE_LICENSE
|
||||
MODULE_LICENSE("GPL"); /* Close enough. */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Structures / Variables */
|
||||
/************************************************************************/
|
||||
|
||||
static int retrieve_vm_pages(Bit32u *page, int max_pages, void *addr, unsigned size);
|
||||
static unsigned retrieve_phy_pages(Bit32u *page, int max_pages, void *addr, unsigned size);
|
||||
static int retrieve_monitor_pages(void);
|
||||
|
||||
monitor_pages_t monitor_pages;
|
||||
extern unsigned intRedirCount[];
|
||||
|
||||
|
||||
static struct file_operations plex86_fops = {
|
||||
#if LINUX_VERSION_CODE >= VERSION_CODE(2,4,0)
|
||||
owner: THIS_MODULE,
|
||||
#endif
|
||||
mmap: plex86_mmap,
|
||||
ioctl: plex86_ioctl,
|
||||
open: plex86_open,
|
||||
release: plex86_release,
|
||||
};
|
||||
|
||||
|
||||
#ifdef CONFIG_DEVFS_FS
|
||||
#include <linux/devfs_fs_kernel.h>
|
||||
devfs_handle_t my_devfs_entry;
|
||||
#endif
|
||||
|
||||
/* For the /proc/driver/plex86 entry. */
|
||||
#if LINUX_VERSION_CODE >= VERSION_CODE(2,4,0) /* XXX - How far back? */
|
||||
int plex86_read_procmem(char *, char **, off_t, int);
|
||||
#else
|
||||
int plex86_read_procmem(char *, char **, off_t, int, int);
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < VERSION_CODE(2,3,25)
|
||||
static struct proc_dir_entry plex86_proc_entry = {
|
||||
0, /* dynamic inode */
|
||||
6, "driver/plex86", /* len, name */
|
||||
S_IFREG | S_IRUGO, /* mode */
|
||||
1, 0, 0,
|
||||
0,
|
||||
NULL,
|
||||
&plex86_read_procmem, /* read function */
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Main kernel module code */
|
||||
/************************************************************************/
|
||||
|
||||
int
|
||||
init_module(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* clear uninitialised structures */
|
||||
memset(&monitor_pages, 0, sizeof(monitor_pages));
|
||||
|
||||
/* register the device with the kernel */
|
||||
err = register_chrdev(plex_major, "plex86", &plex86_fops);
|
||||
if (err < 0) {
|
||||
printk(KERN_WARNING "plex86: can't get major %d\n", plex_major);
|
||||
return(err);
|
||||
}
|
||||
/* If this was a dynamic allocation, save the major for
|
||||
* the release code
|
||||
*/
|
||||
if(!plex_major)
|
||||
plex_major = err;
|
||||
|
||||
/* register the /proc entry */
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#if LINUX_VERSION_CODE >= VERSION_CODE(2,3,25)
|
||||
if (!create_proc_info_entry("driver/plex86", 0, NULL, plex86_read_procmem))
|
||||
printk(KERN_ERR "plex86: registering /proc/driver/plex86 failed\n");
|
||||
#else
|
||||
proc_register_dynamic(&proc_root, &plex86_proc_entry);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* register /dev/misc/plex86 with devfs */
|
||||
#ifdef CONFIG_DEVFS_FS
|
||||
my_devfs_entry = devfs_register(NULL, "misc/plex86",
|
||||
DEVFS_FL_DEFAULT,
|
||||
plex_major, 0 /* minor mode*/,
|
||||
S_IFCHR | 0666, &plex86_fops,
|
||||
NULL /* "info" */);
|
||||
if (!my_devfs_entry)
|
||||
printk(KERN_ERR "plex86: registering misc/plex86 devfs entry failed\n");
|
||||
#endif
|
||||
|
||||
/* retrieve the monitor physical pages */
|
||||
if (!retrieve_monitor_pages()) {
|
||||
printk(KERN_ERR "retrieve_monitor_pages returned error\n");
|
||||
err = -EINVAL;
|
||||
goto fail_retrieve_pages;
|
||||
}
|
||||
|
||||
/* Kernel independent code to be run when kernel module is loaded. */
|
||||
if ( !genericModuleInit() ) {
|
||||
printk(KERN_ERR "genericModuleInit returned error\n");
|
||||
err = -EINVAL;
|
||||
goto fail_cpu_capabilities;
|
||||
}
|
||||
|
||||
/* success */
|
||||
EXPORT_NO_SYMBOLS;
|
||||
return(0);
|
||||
|
||||
fail_cpu_capabilities:
|
||||
fail_retrieve_pages:
|
||||
/* unregister /proc entry */
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#if LINUX_VERSION_CODE >= VERSION_CODE(2,3,25)
|
||||
remove_proc_entry("driver/plex86", NULL);
|
||||
#else
|
||||
proc_unregister(&proc_root, plex86_proc_entry.low_ino);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* unregister device */
|
||||
unregister_chrdev(plex_major, "plex86");
|
||||
return err;
|
||||
}
|
||||
|
||||
void
|
||||
cleanup_module(void)
|
||||
{
|
||||
/* unregister device */
|
||||
unregister_chrdev(plex_major, "plex86");
|
||||
|
||||
/* unregister /proc entry */
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#if LINUX_VERSION_CODE >= VERSION_CODE(2,3,25)
|
||||
remove_proc_entry("driver/plex86", NULL);
|
||||
#else
|
||||
proc_unregister(&proc_root, plex86_proc_entry.low_ino);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEVFS_FS
|
||||
devfs_unregister(my_devfs_entry);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Open / Release a VM */
|
||||
/************************************************************************/
|
||||
|
||||
int
|
||||
plex86_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
vm_t *vm;
|
||||
#if LINUX_VERSION_CODE < VERSION_CODE(2,4,0)
|
||||
MOD_INC_USE_COUNT;
|
||||
#endif
|
||||
|
||||
/* Allocate a VM structure. */
|
||||
if ( (vm = vmalloc(sizeof(vm_t))) == NULL )
|
||||
return -ENOMEM;
|
||||
filp->private_data = vm;
|
||||
|
||||
/* Kernel independent device open code. */
|
||||
genericDeviceOpen(vm);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,31)
|
||||
int
|
||||
#else
|
||||
void
|
||||
#endif
|
||||
plex86_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
vm_t *vm = (vm_t *)filp->private_data;
|
||||
filp->private_data = NULL;
|
||||
|
||||
/* Free the virtual memory. */
|
||||
unreserve_guest_pages( vm );
|
||||
unallocVmPages( vm );
|
||||
|
||||
/* Free the VM structure. */
|
||||
memset( vm, 0, sizeof(*vm) );
|
||||
vfree( vm );
|
||||
|
||||
#if LINUX_VERSION_CODE < VERSION_CODE(2,4,0)
|
||||
MOD_DEC_USE_COUNT;
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,31)
|
||||
return(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
plex86_ioctl(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
vm_t *vm = (vm_t *)filp->private_data;
|
||||
int ret;
|
||||
|
||||
/* Call non host-specific ioctl() code which calls back to this
|
||||
* module only when it needs host-specific features.
|
||||
*/
|
||||
ret = ioctlGeneric(vm, inode, filp, cmd, arg);
|
||||
|
||||
/* Convert from plex86 errno codes to host-specific errno codes. Not
|
||||
* very exciting.
|
||||
*/
|
||||
if ( ret < 0 )
|
||||
ret = - hostConvertPlex86Errno(- ret);
|
||||
return( ret );
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)
|
||||
plex86_mmap(struct file * file, struct vm_area_struct * vma)
|
||||
#else
|
||||
plex86_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
|
||||
#endif
|
||||
{
|
||||
vm_t *vm = (vm_t *)file->private_data;
|
||||
int i, firstpage, nr_pages;
|
||||
Bit32u *pagesArray;
|
||||
unsigned stateMask;
|
||||
|
||||
/* Must have memory allocated */
|
||||
if (!vm->pages.guest_n_pages) {
|
||||
printk(KERN_WARNING "plex86: device not initialized\n");
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
/* Private mappings make no sense ... */
|
||||
if ( !(vma->vm_flags & VM_SHARED) ) {
|
||||
printk(KERN_WARNING "plex86: private mapping\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < VERSION_CODE(2,3,25)
|
||||
/* To simplify things, allow only page-aligned offsets */
|
||||
if ( vma->vm_offset & (PAGE_SIZE - 1) ) {
|
||||
printk(KERN_WARNING "plex86: unaligned offset %08lx\n", vma->vm_offset);
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Map all requested pages in ... */
|
||||
#if LINUX_VERSION_CODE >= VERSION_CODE(2,3,25)
|
||||
firstpage = vma->vm_pgoff;
|
||||
#else
|
||||
firstpage = vma->vm_offset >> PAGE_SHIFT;
|
||||
#endif
|
||||
nr_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
|
||||
|
||||
/* The memory map:
|
||||
* guest physical memory (guest_n_pages)
|
||||
* log_buffer (1)
|
||||
* guest_cpu (1)
|
||||
*/
|
||||
if ( firstpage == 0 ) {
|
||||
if (nr_pages != vm->pages.guest_n_pages) {
|
||||
printk(KERN_WARNING "plex86: mmap of guest phy mem, "
|
||||
"nr_pages of %u != guest_n_pages of %u\n",
|
||||
nr_pages, vm->pages.guest_n_pages);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* printk(KERN_WARNING "plex86: found mmap of guest phy memory.\n"); */
|
||||
pagesArray = &vm->pages.guest[0];
|
||||
stateMask = VMStateMMapPhyMem;
|
||||
}
|
||||
else if ( firstpage == (vm->pages.guest_n_pages+0) ) {
|
||||
if (nr_pages != 1) {
|
||||
printk(KERN_WARNING "plex86: mmap of log_buffer, pages>1.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
/* printk(KERN_WARNING "plex86: found mmap of log_buffer.\n"); */
|
||||
pagesArray = &vm->pages.log_buffer[0];
|
||||
stateMask = VMStateMMapPrintBuffer;
|
||||
}
|
||||
else if ( firstpage == (vm->pages.guest_n_pages+1) ) {
|
||||
if (nr_pages != 1) {
|
||||
printk(KERN_WARNING "plex86: mmap of guest_cpu, pages>1.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
/* printk(KERN_WARNING "plex86: found mmap of guest_cpu.\n"); */
|
||||
pagesArray = &vm->pages.guest_cpu;
|
||||
stateMask = VMStateMMapGuestCPU;
|
||||
}
|
||||
else {
|
||||
printk(KERN_WARNING "plex86: mmap with firstpage of 0x%x.\n", firstpage);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Sanity check */
|
||||
#if LINUX_VERSION_CODE >= VERSION_CODE(2,3,25)
|
||||
if ( ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) > nr_pages ) {
|
||||
printk(KERN_WARNING "plex86: mmap sanity checks failed.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
#else
|
||||
if ( (vma->vm_end - vma->vm_start) > (nr_pages << PAGE_SHIFT) ) {
|
||||
printk(KERN_WARNING "plex86: mmap sanity checks failed.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
for ( i = 0; i < nr_pages; i++ ) {
|
||||
if ( remap_page_range(vma->vm_start + (i << PAGE_SHIFT),
|
||||
pagesArray[i] << 12,
|
||||
PAGE_SIZE,
|
||||
vma->vm_page_prot ) )
|
||||
/* xxx What about fixing partial remaps? */
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < VERSION_CODE(2,1,0)
|
||||
/* Enter our inode into the VMA; no need to change the default ops */
|
||||
vma->vm_inode = inode;
|
||||
if (!inode->i_count)
|
||||
inode->i_count++;
|
||||
#endif
|
||||
vm->vmState |= stateMask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Status reporting: /proc code */
|
||||
/************************************************************************/
|
||||
|
||||
int
|
||||
plex86_read_procmem(char *buf, char **start, off_t offset,
|
||||
#if LINUX_VERSION_CODE >= VERSION_CODE(2,4,0)
|
||||
int len
|
||||
#else
|
||||
int len, int unused
|
||||
#endif
|
||||
)
|
||||
{
|
||||
unsigned i;
|
||||
len = 0;
|
||||
len += sprintf(buf, "monitor-->host interrupt reflection counts\n");
|
||||
for (i=0; i<256; i++) {
|
||||
if (intRedirCount[i])
|
||||
len += sprintf(buf+len, " 0x%2x:%10u\n", i, intRedirCount[i]);
|
||||
}
|
||||
return(len);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
retrieve_vm_pages(Bit32u *page, int max_pages, void *addr, unsigned size)
|
||||
{
|
||||
/*
|
||||
* Grrr. There doesn't seem to be an exported mechanism to retrieve
|
||||
* the physical pages underlying a vmalloc()'ed area. We do it the
|
||||
* hard way ...
|
||||
*/
|
||||
pageEntry_t *host_pgd;
|
||||
Bit32u host_cr3;
|
||||
Bit32u start_addr;
|
||||
int n_pages;
|
||||
int i;
|
||||
|
||||
start_addr = ((Bit32u)addr) & 0xfffff000;
|
||||
n_pages = BytesToPages( (((Bit32u)addr) - start_addr) + size );
|
||||
|
||||
if (!addr) {
|
||||
printk(KERN_WARNING "plex86: retrieve_vm_pages: addr NULL!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( n_pages > max_pages ) {
|
||||
printk(KERN_WARNING "plex86: retrieve_vm_pages: not enough pages!\n");
|
||||
printk(KERN_WARNING " npages(%u) > max_pages(%u)\n",
|
||||
n_pages, max_pages);
|
||||
return 0;
|
||||
}
|
||||
|
||||
asm volatile ("movl %%cr3, %0" : "=r" (host_cr3));
|
||||
host_pgd = (pageEntry_t *)(phys_to_virt(host_cr3 & ~0xfff));
|
||||
|
||||
for (i = 0; i < n_pages; i++)
|
||||
{
|
||||
Bit32u virt_addr = start_addr + i*PAGESIZE + KERNEL_OFFSET;
|
||||
pageEntry_t *pde = host_pgd + (virt_addr >> 22);
|
||||
pageEntry_t *pte = (pageEntry_t *)phys_to_virt(pde->fields.base << 12)
|
||||
+ ((virt_addr >> 12) & 0x3ff);
|
||||
|
||||
/* If page isn't present, assume end of area */
|
||||
if ( !pde->fields.P || ! pte->fields.P )
|
||||
{
|
||||
n_pages = i;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Abort if our page list is too small */
|
||||
if (i >= max_pages)
|
||||
{
|
||||
printk(KERN_WARNING "plex86: page list is too small!\n");
|
||||
printk(KERN_WARNING "n_pages=%u, max_pages=%u\n",
|
||||
n_pages, max_pages);
|
||||
return 0;
|
||||
}
|
||||
|
||||
page[i] = pte->fields.base;
|
||||
}
|
||||
|
||||
return n_pages;
|
||||
}
|
||||
|
||||
int
|
||||
retrieve_monitor_pages(void)
|
||||
{
|
||||
/*
|
||||
* Retrieve start address and size of this module.
|
||||
*
|
||||
* Note that with old kernels, we cannot access the module info (size),
|
||||
* hence we rely on the fact that Linux lets at least one page of
|
||||
* virtual address space unused after the end of the module.
|
||||
*/
|
||||
#ifdef THIS_MODULE
|
||||
void *start_addr = THIS_MODULE;
|
||||
unsigned size = THIS_MODULE->size;
|
||||
#else
|
||||
void *start_addr = &mod_use_count_;
|
||||
unsigned size = 0x10000000; /* Actual size determined below */
|
||||
#endif
|
||||
|
||||
int n_pages;
|
||||
|
||||
n_pages = retrieve_vm_pages(monitor_pages.page, PLEX86_MAX_MONITOR_PAGES,
|
||||
start_addr, size);
|
||||
if (n_pages == 0) {
|
||||
printk(KERN_ERR "retrieve_vm_pages returned error.\n");
|
||||
return( 0 ); /* Error. */
|
||||
}
|
||||
printk(KERN_WARNING "%u monitor pages located\n", n_pages);
|
||||
|
||||
monitor_pages.startOffset = (Bit32u)start_addr;
|
||||
monitor_pages.startOffsetPageAligned =
|
||||
monitor_pages.startOffset & 0xfffff000;
|
||||
monitor_pages.n_pages = n_pages;
|
||||
return( n_pages );
|
||||
}
|
||||
|
||||
void
|
||||
reserve_guest_pages(vm_t *vm)
|
||||
{
|
||||
vm_pages_t *pg = &vm->pages;
|
||||
unsigned p;
|
||||
|
||||
/*
|
||||
* As we want to map these pages to user space, we need to mark
|
||||
* them as 'reserved' pages by setting the PG_reserved bit.
|
||||
*
|
||||
* This has the effect that:
|
||||
* - remap_page_range accepts them as candidates for remapping
|
||||
* - the swapper does *not* try to swap these pages out, even
|
||||
* after they are mapped to user space
|
||||
*/
|
||||
|
||||
#if LINUX_VERSION_CODE >= VERSION_CODE(2,4,0)
|
||||
for (p = 0; p < pg->guest_n_pages; p++)
|
||||
set_bit(PG_reserved, &((mem_map + pg->guest[p])->flags));
|
||||
set_bit(PG_reserved, &((mem_map + pg->log_buffer[0])->flags));
|
||||
set_bit(PG_reserved, &((mem_map + pg->guest_cpu)->flags));
|
||||
#else
|
||||
for (p = 0; p < pg->guest_n_pages; p++)
|
||||
mem_map_reserve(pg->guest[p]);
|
||||
mem_map_reserve(pg->log_buffer[0]);
|
||||
mem_map_reserve(pg->guest_cpu);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
unreserve_guest_pages(vm_t *vm)
|
||||
{
|
||||
vm_pages_t *pg = &vm->pages;
|
||||
unsigned p;
|
||||
|
||||
/* Remove the PG_reserved flags before returning the pages */
|
||||
#if LINUX_VERSION_CODE >= VERSION_CODE(2,4,0)
|
||||
for (p = 0; p < pg->guest_n_pages; p++)
|
||||
clear_bit(PG_reserved, &((mem_map + pg->guest[p])->flags));
|
||||
clear_bit(PG_reserved, &((mem_map + pg->log_buffer[0])->flags));
|
||||
clear_bit(PG_reserved, &((mem_map + pg->guest_cpu)->flags));
|
||||
#else
|
||||
for (p = 0; p < pg->guest_n_pages; p++)
|
||||
mem_map_unreserve(pg->guest[p]);
|
||||
mem_map_unreserve(pg->log_buffer[0]);
|
||||
mem_map_unreserve(pg->guest_cpu);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
unsigned
|
||||
retrieve_phy_pages(Bit32u *page, int max_pages, void *addr_v, unsigned size)
|
||||
{
|
||||
/*
|
||||
* Grrr. There doesn't seem to be an exported mechanism to retrieve
|
||||
* the physical pages underlying a vmalloc()'ed area. We do it the
|
||||
* hard way ...
|
||||
*/
|
||||
pageEntry_t *host_pgd;
|
||||
Bit32u host_cr3;
|
||||
/*Bit32u start_addr = (Bit32u)addr & ~(PAGESIZE-1); */
|
||||
/*int n_pages = ((Bit32u)addr + size - start_addr + PAGESIZE-1) >> 12; */
|
||||
int i;
|
||||
Bit8u *addr;
|
||||
unsigned n_pages;
|
||||
|
||||
addr = (Bit8u *) addr_v;
|
||||
if ( ((Bit32u)addr) & 0xfff ) {
|
||||
printk(KERN_ERR "plex86: retrieve_phy_pages: not aligned!\n");
|
||||
return 0;
|
||||
}
|
||||
n_pages = BytesToPages(size);
|
||||
if (!addr) {
|
||||
printk(KERN_ERR "plex86: retrieve_phy_pages: addr NULL!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( n_pages > max_pages ) {
|
||||
printk(KERN_ERR "plex86: retrieve_phy_pages: n=%u > max=%u\n",
|
||||
n_pages, max_pages);
|
||||
return 0;
|
||||
}
|
||||
|
||||
asm volatile ("movl %%cr3, %0" : "=r" (host_cr3));
|
||||
host_pgd = (pageEntry_t *)(phys_to_virt(host_cr3 & ~0xfff));
|
||||
|
||||
for (i = 0; i < n_pages; i++) {
|
||||
Bit32u laddr;
|
||||
pageEntry_t *pde;
|
||||
pageEntry_t *pte;
|
||||
|
||||
laddr = KERNEL_OFFSET + ((Bit32u) addr);
|
||||
pde = host_pgd + (laddr >> 22);
|
||||
pte = ((pageEntry_t *)phys_to_virt(pde->fields.base << 12))
|
||||
+ ((laddr >> 12) & 0x3ff);
|
||||
if ( !pde->fields.P ) {
|
||||
printk(KERN_ERR "retrieve_phy_pages: PDE.P==0: i=%u, n=%u laddr=0x%x\n",
|
||||
i, n_pages, laddr);
|
||||
return 0;
|
||||
}
|
||||
if ( !pte->fields.P ) {
|
||||
printk(KERN_ERR "retrieve_phy_pages: PTE.P==0: i=%u, n=%u laddr=0x%x\n",
|
||||
i, n_pages, laddr);
|
||||
return 0;
|
||||
}
|
||||
page[i] = pte->fields.base;
|
||||
addr += 4096;
|
||||
}
|
||||
return(n_pages);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* The requisite host-specific functions. */
|
||||
/************************************************************************/
|
||||
|
||||
unsigned
|
||||
hostIdle(void)
|
||||
{
|
||||
if (NEED_RESCHED)
|
||||
schedule();
|
||||
|
||||
/* return !current_got_fatal_signal(); */
|
||||
return( ! signal_pending(current) );
|
||||
}
|
||||
|
||||
void *
|
||||
hostAllocZeroedMem(unsigned long size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
ptr = vmalloc(size);
|
||||
if ( ((Bit32u) ptr) & 0x00000fff )
|
||||
return( 0 ); /* Error. */
|
||||
|
||||
/* Zero pages. This also demand maps the pages in, which we need
|
||||
* since we'll cycle through all the pages to get the physical
|
||||
* address mappings.
|
||||
*/
|
||||
mon_memzero(ptr, size);
|
||||
return( ptr );
|
||||
}
|
||||
|
||||
void
|
||||
hostFreeMem(void *ptr)
|
||||
{
|
||||
vfree(ptr);
|
||||
}
|
||||
|
||||
void *
|
||||
hostAllocZeroedPage(void)
|
||||
{
|
||||
return( (void *) get_zeroed_page(GFP_KERNEL) );
|
||||
}
|
||||
|
||||
void
|
||||
hostFreePage(void *ptr)
|
||||
{
|
||||
free_page( (Bit32u)ptr );
|
||||
}
|
||||
|
||||
|
||||
unsigned
|
||||
hostGetAllocedMemPhyPages(Bit32u *page, int max_pages, void *ptr, unsigned size)
|
||||
{
|
||||
return( retrieve_phy_pages(page, max_pages, ptr, size) );
|
||||
}
|
||||
|
||||
Bit32u
|
||||
hostGetAllocedPagePhyPage(void *ptr)
|
||||
{
|
||||
if (!ptr) return 0;
|
||||
/* return MAP_NR(ptr); */
|
||||
return(__pa(ptr) >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
void
|
||||
hostPrint(char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int ret;
|
||||
unsigned char buffer[256];
|
||||
|
||||
va_start(args, fmt);
|
||||
ret = mon_vsnprintf(buffer, 256, fmt, args);
|
||||
if (ret == -1) {
|
||||
printk(KERN_ERR "hostPrint: vsnprintf returns error.\n");
|
||||
}
|
||||
else {
|
||||
printk(KERN_WARNING "%s\n", buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
hostConvertPlex86Errno(unsigned ret)
|
||||
{
|
||||
switch (ret) {
|
||||
case 0: return(0);
|
||||
case Plex86ErrnoEBUSY: return(EBUSY);
|
||||
case Plex86ErrnoENOMEM: return(ENOMEM);
|
||||
case Plex86ErrnoEFAULT: return(EFAULT);
|
||||
case Plex86ErrnoEINVAL: return(EINVAL);
|
||||
default:
|
||||
printk(KERN_ERR "ioctlAllocVPhys: case %u\n", ret);
|
||||
return(EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Bit32u
|
||||
hostKernelOffset(void)
|
||||
{
|
||||
return( KERNEL_OFFSET );
|
||||
}
|
||||
|
||||
unsigned
|
||||
hostMMapCheck(void *i, void *f)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct file *filp;
|
||||
|
||||
inode = (struct inode *) i;
|
||||
filp = (struct file *) f;
|
||||
|
||||
#if LINUX_VERSION_CODE >= VERSION_CODE(2,3,99)
|
||||
/* Not sure when this changed. If you know, email us. */
|
||||
if (inode->i_data.i_mmap != NULL)
|
||||
#else
|
||||
if (inode->i_mmap != NULL)
|
||||
#endif
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
hostModuleCountReset(vm_t *vm, void *inode, void *filp)
|
||||
{
|
||||
#if LINUX_VERSION_CODE < VERSION_CODE(2,4,0)
|
||||
while (MOD_IN_USE) {
|
||||
MOD_DEC_USE_COUNT;
|
||||
}
|
||||
|
||||
MOD_INC_USE_COUNT; /* bump back to 1 so release can decrement */
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned long
|
||||
hostCopyFromUser(void *to, void *from, unsigned long len)
|
||||
{
|
||||
return( copy_from_user(to, from, len) );
|
||||
}
|
||||
|
||||
unsigned long
|
||||
hostCopyToUser(void *to, void *from, unsigned long len)
|
||||
{
|
||||
return( copy_to_user(to, from, len) );
|
||||
}
|
566
bochs/plex86/kernel/host-netbsd.c
Normal file
566
bochs/plex86/kernel/host-netbsd.c
Normal file
@ -0,0 +1,566 @@
|
||||
/*
|
||||
* plex86: run multiple x86 operating systems concurrently
|
||||
*
|
||||
* Copyright (C) 2000 Frank van der Linden (fvdl@wasabisystems.com)
|
||||
*
|
||||
* host-netbsd.c: NetBSD-specific code for kernel module.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
/* XXXX stuff that conflicts with NetBSD namespace */
|
||||
|
||||
#define timer_t __bsd_timer_t
|
||||
#define write_eflags __netbsd_write_eflags
|
||||
#define read_eflags __netbsd_read_eflags
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/exec.h>
|
||||
#include <sys/lkm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/null.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#undef NETBSD_PLEX86_DEBUG
|
||||
|
||||
#if __NetBSD_Version__ > 105009900
|
||||
#include <uvm/uvm_extern.h>
|
||||
#include <uvm/uvm_param.h>
|
||||
#else
|
||||
#include <vm/vm.h>
|
||||
#endif
|
||||
|
||||
#undef timer_t
|
||||
#undef write_eflags
|
||||
#undef read_eflags
|
||||
|
||||
#include "plex86.h"
|
||||
#define IN_HOST_SPACE
|
||||
#include "monitor.h"
|
||||
|
||||
int plex86_open(dev_t dev, int oflags, int devtype, struct proc *p);
|
||||
int plex86_close(dev_t dev, int cflags, int devtype, struct proc *p);
|
||||
paddr_t plex86_mmap(dev_t dev, off_t offset, int length);
|
||||
int plex86_ioctl(dev_t dev, u_long cmd, caddr_t data, int flags,
|
||||
struct proc *p);
|
||||
|
||||
static int plex86_handle(struct lkm_table *, int);
|
||||
static vm_t *find_vm(struct proc *);
|
||||
static void register_vm(vm_t *, struct proc *);
|
||||
static void unregister_all(void);
|
||||
#if 0
|
||||
static void unregister_vm(vm_t *, struct proc *);
|
||||
#endif
|
||||
|
||||
static unsigned retrieve_phy_pages(Bit32u *, int, void *, unsigned, int);
|
||||
|
||||
static struct cdevsw plex86dev = {
|
||||
plex86_open, plex86_close,
|
||||
(dev_type_read((*))) enodev, (dev_type_write((*))) enodev,
|
||||
plex86_ioctl, (dev_type_stop((*))) enodev, 0,
|
||||
seltrue, plex86_mmap, 0
|
||||
};
|
||||
|
||||
static struct plex86_softc {
|
||||
int sc_open;
|
||||
} plex86sc;
|
||||
|
||||
MOD_DEV("plex86", LM_DT_CHAR, -1, &plex86dev)
|
||||
|
||||
monitor_pages_t monitor_pages;
|
||||
|
||||
/*
|
||||
* Hash table stuff to maintain proc <-> vm mapping.
|
||||
* 23 entries should be plenty.. unless someone plans to run more than
|
||||
* 23 guest OSs..
|
||||
*
|
||||
* Note that a process can only open the device once with this scheme.
|
||||
*/
|
||||
|
||||
LIST_HEAD(plex86_hashhead, plex86_vmentry);
|
||||
|
||||
struct plex86_vmentry {
|
||||
pid_t vm_pid;
|
||||
vm_t *vm_vm;
|
||||
LIST_ENTRY(plex86_vmentry) vm_entry;
|
||||
};
|
||||
|
||||
struct plex86_hashhead *plex86_hashtbl;
|
||||
u_long plex86_hashmask;
|
||||
|
||||
#define PLEX86_VMHASHSIZE 23
|
||||
#define PLEX86_VMHASH(p) ((u_long)((p)->p_pid) & plex86_hashmask)
|
||||
|
||||
int
|
||||
plex86_lkmentry(struct lkm_table *lkmtp, int cmd, int ver)
|
||||
{
|
||||
DISPATCH(lkmtp, cmd, ver, plex86_handle, plex86_handle, plex86_handle)
|
||||
}
|
||||
|
||||
static int
|
||||
plex86_handle(struct lkm_table *lkmtp, int cmd)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case LKM_E_LOAD:
|
||||
if (lkmexists(lkmtp))
|
||||
return EEXIST;
|
||||
monitor_pages.startOffset = lkmtp->area;
|
||||
monitor_pages.startOffsetPageAligned =
|
||||
monitor_pages.startOffset & 0xfffff000;
|
||||
monitor_pages.n_pages = lkmtp->size / PAGE_SIZE;
|
||||
if (retrieve_phy_pages(monitor_pages.page,
|
||||
PLEX86_MAX_MONITOR_PAGES, (void *)lkmtp->area,
|
||||
lkmtp->size, 0) == 0) {
|
||||
log(LOG_WARNING, "plex86: could not store physical "
|
||||
"addresses for monitor pages\n");
|
||||
return EIO;
|
||||
}
|
||||
#if __NetBSD_Version__ > 105009900
|
||||
plex86_hashtbl = hashinit(PLEX86_VMHASHSIZE, HASH_LIST,
|
||||
M_DEVBUF, M_WAITOK, &plex86_hashmask);
|
||||
#else
|
||||
plex86_hashtbl = hashinit(PLEX86_VMHASHSIZE, M_DEVBUF,
|
||||
M_WAITOK, &plex86_hashmask);
|
||||
#endif
|
||||
if (!hostModuleInit()) {
|
||||
log(LOG_WARNING, "hostModuleInit error\n");
|
||||
error = EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case LKM_E_UNLOAD:
|
||||
if (plex86sc.sc_open != 0)
|
||||
return EBUSY;
|
||||
free(plex86_hashtbl, M_DEVBUF);
|
||||
break;
|
||||
|
||||
case LKM_E_STAT:
|
||||
break;
|
||||
|
||||
default:
|
||||
error = EIO;
|
||||
break;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
plex86_open(dev_t dev, int oflags, int devtype, struct proc *p)
|
||||
{
|
||||
vm_t *vm;
|
||||
|
||||
if (suser(p->p_ucred, &p->p_acflag) != 0)
|
||||
return EPERM;
|
||||
|
||||
vm = find_vm(p);
|
||||
if (vm == NULL) {
|
||||
vm = malloc(sizeof (vm_t), M_DEVBUF, M_WAITOK);
|
||||
if (vm == NULL)
|
||||
return EIO;
|
||||
memset(vm, 0, sizeof(vm_t));
|
||||
register_vm(vm, p);
|
||||
plex86sc.sc_open++;
|
||||
} else
|
||||
return EBUSY;
|
||||
|
||||
/* Kernel independent device open code. */
|
||||
hostDeviceOpenInit(vm);
|
||||
|
||||
#ifdef NETBSD_PLEX86_DEBUG
|
||||
printf("plex86: pid %u opened device, vm %p\n", p->p_pid, vm);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
plex86_close(dev_t dev, int cflags, int devtype, struct proc *p)
|
||||
{
|
||||
unregister_all();
|
||||
plex86sc.sc_open = 0;
|
||||
#ifdef NETBSD_PLEX86_DEBUG
|
||||
printf("plex86: pid %u closed device\n", p->p_pid);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
paddr_t
|
||||
plex86_mmap(dev_t dev, off_t offset, int prot)
|
||||
{
|
||||
struct proc *p = curproc;
|
||||
vm_t *vm;
|
||||
int page;
|
||||
off_t endguestoff;
|
||||
|
||||
vm = find_vm(p);
|
||||
if (vm == NULL)
|
||||
return ENXIO;
|
||||
#if 1
|
||||
#warning "kludge to mmap message buffer"
|
||||
endguestoff = (off_t)(vm->pages.guest_n_megs * 1024 * 1024);
|
||||
if (offset >= endguestoff && prot == PROT_READ) {
|
||||
page = (offset - endguestoff) / PAGE_SIZE;
|
||||
return vm->pages.log_buffer[page];
|
||||
}
|
||||
#endif
|
||||
|
||||
page = offset / PAGE_SIZE;
|
||||
if (page < 0 || page > vm->pages.guest_n_pages) {
|
||||
log(LOG_WARNING, "plex86: mmap: offset %lx out of range\n",
|
||||
(unsigned long)offset);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return vm->pages.guest[page];
|
||||
}
|
||||
|
||||
int
|
||||
plex86_ioctl(dev_t dev, u_long cmd, caddr_t data, int flags,
|
||||
struct proc *p)
|
||||
{
|
||||
int error;
|
||||
vm_t *vm;
|
||||
|
||||
vm = find_vm(p);
|
||||
if (vm == NULL)
|
||||
return EINVAL;
|
||||
|
||||
switch (cmd) {
|
||||
case PLEX86_ALLOCVPHYS:
|
||||
{
|
||||
unsigned long arg = *((unsigned long*)data);
|
||||
guest_cpu_t guest_cpu;
|
||||
|
||||
if (vm->mon_state != MON_STATE_UNINITIALIZED ||
|
||||
vm->pages.guest_n_megs != 0)
|
||||
return EBUSY;
|
||||
printf("plex86_ioctl: ALLOCVPHYS: requested size %lu\n",
|
||||
arg);
|
||||
if (arg > PLEX86_MAX_PHY_MEGS || arg < 4 || (arg & ~0x3) != arg)
|
||||
return EINVAL;
|
||||
|
||||
/* Allocate memory */
|
||||
error = allocVMPages(vm, arg);
|
||||
if (error != 0) {
|
||||
log(LOG_WARNING, "plex86: allocVMPages failed (%d)\n",
|
||||
error);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
if (init_guest_phy_mem(vm) != 0) {
|
||||
log(LOG_ERR, "plex86: init_guest_phy_mem failed\n");
|
||||
unallocVMPages(vm);
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
getCpuResetValues(&guest_cpu);
|
||||
log(LOG_WARNING, "plex86: cpu.cr0 = 0x%x\n", guest_cpu.cr0);
|
||||
if (!init_monitor(vm, 0, 0, &guest_cpu) ||
|
||||
!setGuestCPU(vm, 0, &guest_cpu) ||
|
||||
!mapMonitor(vm, guest_cpu.eflags, 0)) {
|
||||
log(LOG_ERR, "plex86: init_monitor failed\n");
|
||||
unallocVMPages(vm);
|
||||
return EFAULT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PLEX86_TEARDOWN:
|
||||
unallocVMPages(vm);
|
||||
break;
|
||||
|
||||
case PLEX86_ALLOCINT:
|
||||
return EINVAL;
|
||||
case PLEX86_RELEASEINT:
|
||||
return EINVAL;
|
||||
case PLEX86_PRESCANDEPTH:
|
||||
{
|
||||
unsigned long arg = *(unsigned long *)data;
|
||||
|
||||
if ((arg < PrescanDepthMin) || (arg > PrescanDepthMax)) {
|
||||
log(LOG_WARNING, "plex86: Requested prescan depth %lu"
|
||||
" out of range [%u..%u]\n", arg, PrescanDepthMin,
|
||||
PrescanDepthMax);
|
||||
return EINVAL;
|
||||
}
|
||||
vm->prescanDepth = (unsigned)arg;
|
||||
break;
|
||||
}
|
||||
case PLEX86_SETINTR:
|
||||
ioctlSetIntr(vm, *(unsigned long *)data);
|
||||
break;
|
||||
case PLEX86_SET_A20:
|
||||
{
|
||||
unsigned long arg = *(unsigned long *)data;
|
||||
if (!ioctlSetA20E(vm, arg))
|
||||
return EINVAL;
|
||||
break;
|
||||
}
|
||||
case PLEX86_MESSAGEQ:
|
||||
{
|
||||
vm_messages_t msg;
|
||||
|
||||
if (vm->mon_state != MON_STATE_RUNNABLE)
|
||||
return EINVAL;
|
||||
|
||||
error = copyin(*(void **)data, &msg.header, sizeof msg.header);
|
||||
if (error != 0)
|
||||
return error;
|
||||
|
||||
if ((msg.header.msg_len + sizeof(msg.header)) > sizeof(msg))
|
||||
return EINVAL;
|
||||
|
||||
if (msg.header.msg_len != 0) {
|
||||
error = copyin(&((vm_messages_t *)*(void **)data)->msg,
|
||||
&msg.msg, msg.header.msg_len);
|
||||
if (error != 0)
|
||||
return error;
|
||||
}
|
||||
|
||||
#warning "deal with LDT %gs and %fs that the NetBSD kernel uses"
|
||||
/* XXXX */
|
||||
__asm("movl $0, %eax");
|
||||
__asm("movl %eax, %gs");
|
||||
__asm("movl %eax, %fs");
|
||||
|
||||
if (ioctlMessageQ(vm, &msg)) {
|
||||
log(LOG_WARNING, "plex86: ioctlMessageQ failed\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
error = copyout(&msg, *(void **)data,
|
||||
sizeof (msg.header) + msg.header.msg_len);
|
||||
return error;
|
||||
}
|
||||
case PLEX86_RESET:
|
||||
break;
|
||||
case PLEX86_PHYMEM_MOD:
|
||||
break;
|
||||
case PLEX86_FORCE_INT:
|
||||
if (vm->mon_state != MON_STATE_RUNNABLE)
|
||||
return -EINVAL;
|
||||
vm->dbg_force_int = 0x100 | (unsigned)data;
|
||||
break;
|
||||
case PLEX86_PRESCANRING3:
|
||||
{
|
||||
unsigned long arg = *(unsigned long *)data;
|
||||
if (arg > PrescanRing3On) {
|
||||
log(LOG_WARNING,
|
||||
"plex86: Requested PrescanRing3 val(%lu) OOB\n",
|
||||
arg);
|
||||
return EINVAL;
|
||||
}
|
||||
vm->prescanRing3 = arg;
|
||||
break;
|
||||
}
|
||||
case PLEX86_GENERIC:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
log(LOG_WARNING, "plex86: unknown ioctl %lx\n", cmd);
|
||||
return EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
register_vm(vm_t *vm, struct proc *p)
|
||||
{
|
||||
struct plex86_hashhead *php;
|
||||
struct plex86_vmentry *vhp;
|
||||
|
||||
php = &plex86_hashtbl[PLEX86_VMHASH(p)];
|
||||
#ifdef DIAGNOSTIC
|
||||
for (vhp = php->lh_first; vhp != NULL; vhp = vhp->vm_entry.le_next) {
|
||||
if (vhp->vm_pid == p_pid)
|
||||
panic("plex86: vm already registered, pid %u\n",
|
||||
p->pid);
|
||||
}
|
||||
#endif
|
||||
vhp = malloc(sizeof (struct plex86_vmentry), M_DEVBUF, M_WAITOK);
|
||||
vhp->vm_pid = p->p_pid;
|
||||
vhp->vm_vm = vm;
|
||||
LIST_INSERT_HEAD(php, vhp, vm_entry);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
unregister_vm(vm_t *vm, struct proc *p)
|
||||
{
|
||||
struct plex86_hashhead *php;
|
||||
struct plex86_vmentry *vhp;
|
||||
|
||||
php = &plex86_hashtbl[PLEX86_VMHASH(p)];
|
||||
for (vhp = php->lh_first; vhp != NULL; vhp = vhp->vm_entry.le_next) {
|
||||
if (vhp->vm_pid == p->p_pid) {
|
||||
LIST_REMOVE(vhp, vm_entry);
|
||||
free(vhp->vm_vm, M_DEVBUF);
|
||||
free(vhp, M_DEVBUF);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
unregister_all(void)
|
||||
{
|
||||
int i;
|
||||
struct plex86_hashhead *php;
|
||||
struct plex86_vmentry *vhp;
|
||||
|
||||
for (i = 0; i < PLEX86_VMHASHSIZE; i++) {
|
||||
php = &plex86_hashtbl[i];
|
||||
for (vhp = php->lh_first; vhp != NULL;
|
||||
vhp = vhp->vm_entry.le_next) {
|
||||
#ifdef NETBSD_PLEX86_DEBUG
|
||||
printf("plex86: unregister vm %p, pid %u\n",
|
||||
vhp->vm_vm, vhp->vm_pid);
|
||||
#endif
|
||||
LIST_REMOVE(vhp, vm_entry);
|
||||
free(vhp->vm_vm, M_DEVBUF);
|
||||
free(vhp, M_DEVBUF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static vm_t *
|
||||
find_vm(struct proc *p)
|
||||
{
|
||||
struct plex86_hashhead *php;
|
||||
struct plex86_vmentry *vhp;
|
||||
|
||||
php = &plex86_hashtbl[PLEX86_VMHASH(p)];
|
||||
for (vhp = php->lh_first; vhp != NULL; vhp = vhp->vm_entry.le_next) {
|
||||
if (vhp->vm_pid == p->p_pid)
|
||||
return vhp->vm_vm;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
retrieve_phy_pages(Bit32u *page, int max_pages, void *addr_v, unsigned size,
|
||||
int aligned)
|
||||
{
|
||||
Bit32u start_addr;
|
||||
unsigned n_pages, i;
|
||||
|
||||
if (!aligned)
|
||||
start_addr = (Bit32u)addr_v & ~(PAGE_SIZE-1);
|
||||
else {
|
||||
start_addr = (Bit32u)addr_v;
|
||||
if (start_addr & (PAGE_SIZE -1)) {
|
||||
log(LOG_WARNING, "plex86: retrieve_phy_pages: address "
|
||||
"%p not aligned\n", addr_v);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
n_pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||
if (n_pages > max_pages) {
|
||||
log(LOG_WARNING, "plex86: retrieve_phy_pages: page list "
|
||||
"too small\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_pages; i++) {
|
||||
page[i] = vtophys((vaddr_t)start_addr) / PAGE_SIZE;
|
||||
start_addr += PAGE_SIZE;
|
||||
}
|
||||
|
||||
return n_pages;
|
||||
}
|
||||
|
||||
unsigned
|
||||
host_idle(void)
|
||||
{
|
||||
if (want_resched)
|
||||
yield();
|
||||
return (CURSIG(curproc) == 0);
|
||||
}
|
||||
|
||||
void *
|
||||
host_alloc(unsigned long size)
|
||||
{
|
||||
/*
|
||||
* XXX - it wants this page-aligned apparently.
|
||||
*/
|
||||
if (size <= (PAGE_SIZE / 2))
|
||||
size = PAGE_SIZE;
|
||||
return malloc(size, M_DEVBUF, M_WAITOK);
|
||||
}
|
||||
|
||||
void
|
||||
host_free(void *ptr)
|
||||
{
|
||||
free(ptr, M_DEVBUF);
|
||||
}
|
||||
|
||||
unsigned
|
||||
host_map(Bit32u *page, int max_pages, void *ptr, unsigned size)
|
||||
{
|
||||
return retrieve_phy_pages(page, max_pages, ptr, size, 1);
|
||||
}
|
||||
|
||||
void *
|
||||
host_alloc_page(void)
|
||||
{
|
||||
return malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
|
||||
}
|
||||
|
||||
void
|
||||
host_free_page(void *ptr)
|
||||
{
|
||||
return free(ptr, M_DEVBUF);
|
||||
}
|
||||
|
||||
Bit32u
|
||||
host_map_page(void *ptr)
|
||||
{
|
||||
Bit32u u;
|
||||
|
||||
if (ptr == NULL)
|
||||
return 0;
|
||||
u = vtophys(ptr) / PAGE_SIZE;
|
||||
/* printf("host_map_page(%p) -> %x\n", ptr, u); */
|
||||
return u;
|
||||
}
|
||||
|
||||
void
|
||||
hostprint(char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int ret;
|
||||
unsigned char buffer[256];
|
||||
|
||||
va_start(args, fmt);
|
||||
ret = mon_vsnprintf(buffer, 256, fmt, args);
|
||||
if (ret == -1)
|
||||
log(LOG_WARNING,
|
||||
"plex86: hostprint: vsnprintf returns error.\n");
|
||||
else
|
||||
log(LOG_WARNING, "plex86: %s\n", buffer);
|
||||
}
|
151
bochs/plex86/kernel/host-null.c
Normal file
151
bochs/plex86/kernel/host-null.c
Normal file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* plex86: run multiple x86 operating systems concurrently
|
||||
* Copyright (C) 1999-2003 Kevin P. Lawton
|
||||
*
|
||||
* host-null.c: host OS specific stubs. These provide a reference for
|
||||
* ports of plex86 to various host OSes.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "plex86.h"
|
||||
#define IN_HOST_SPACE
|
||||
#include "monitor.h"
|
||||
|
||||
/* Note: for comments on what various functions are expected to do, as
|
||||
* well as a reference implemntation, read the 'host-linux.c' file.
|
||||
* It's likely the most up-to-date.
|
||||
*/
|
||||
|
||||
|
||||
/* OS specific includes here. */
|
||||
|
||||
|
||||
/* Some declarations for the entry points etc here. */
|
||||
|
||||
|
||||
|
||||
|
||||
monitor_pages_t monitor_pages;
|
||||
|
||||
#define NULL 0
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
vm_t *vm = NULL;
|
||||
|
||||
genericModuleInit();
|
||||
genericDeviceOpen(vm);
|
||||
initMonitor(vm);
|
||||
initGuestPhyMem(vm);
|
||||
ioctlGeneric(vm, NULL, NULL, 0, 0);
|
||||
return(0);
|
||||
}
|
||||
|
||||
void
|
||||
reserve_guest_pages(vm_t *vm)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
unreserve_guest_pages(vm_t *vm)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned
|
||||
hostIdle(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *
|
||||
hostAllocZeroedMem(unsigned long size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
hostFreeMem(void *ptr)
|
||||
{
|
||||
}
|
||||
|
||||
void *
|
||||
hostAllocZeroedPage(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
hostFreePage(void *ptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
unsigned
|
||||
hostGetAllocedMemPhyPages(Bit32u *page, int max_pages, void *ptr, unsigned size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Bit32u
|
||||
hostGetAllocedPagePhyPage(void *ptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
hostPrint(char *fmt, ...)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
hostConvertPlex86Errno(unsigned ret)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Bit32u
|
||||
hostKernelOffset(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned
|
||||
hostMMapCheck(void *i, void *f)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
hostModuleCountReset(vm_t *vm, void *inode, void *filp)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned long
|
||||
hostCopyFromUser(void *to, void *from, unsigned long len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
hostCopyToUser(void *to, void *from, unsigned long len)
|
||||
{
|
||||
return 0;
|
||||
}
|
66
bochs/plex86/kernel/include/descriptor2.h
Normal file
66
bochs/plex86/kernel/include/descriptor2.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* plex86: run multiple x86 operating systems concurrently
|
||||
* Copyright (C) 1999-2003 Kevin P. Lawton
|
||||
*
|
||||
* descriptor2.h: defines for descriptors and selectors
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __DESCRIPTOR2_H__
|
||||
#define __DESCRIPTOR2_H__
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Bit16u offset_low;
|
||||
selector_t selector;
|
||||
unsigned count:5;
|
||||
unsigned RESERVED:3;
|
||||
unsigned type:5;
|
||||
unsigned dpl:2;
|
||||
unsigned p:1;
|
||||
Bit16u offset_high;
|
||||
} __attribute__ ((packed)) gate_t;
|
||||
|
||||
|
||||
#define SET_INT_GATE(d, S,O,P,DPL, D) {\
|
||||
d.selector = (S);\
|
||||
d.offset_high = (O) >> 16;\
|
||||
d.offset_low = (O) & 0xffff;\
|
||||
d.RESERVED = 0;\
|
||||
d.type = ((D)<<3) | 0x6;\
|
||||
d.dpl = (DPL);\
|
||||
d.p = (P);\
|
||||
}
|
||||
|
||||
#define SET_TRAP_GATE(d, S,O,P,DPL, D) {\
|
||||
d.selector = (S);\
|
||||
d.offset_high = (O) >> 16;\
|
||||
d.offset_low = (O) & 0xffff;\
|
||||
d.RESERVED = 0;\
|
||||
d.type = ((D)<<3) | 0x7;\
|
||||
d.dpl = (DPL);\
|
||||
d.p = (P);\
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Bit32u offset;
|
||||
Bit16u selector;
|
||||
} __attribute ((packed)) far_jmp_info_t;
|
||||
|
||||
#endif /* __DESCRIPTOR2_H__ */
|
78
bochs/plex86/kernel/include/eflags.h
Normal file
78
bochs/plex86/kernel/include/eflags.h
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* plex86: run multiple x86 operating systems concurrently
|
||||
* Copyright (C) 1999-2003 Kevin P. Lawton
|
||||
*
|
||||
* eflags.h: Bitfields of EFLAGS registers
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __EFLAGS_H__
|
||||
#define __EFLAGS_H__
|
||||
|
||||
/*
|
||||
* the eflags field looks like this:
|
||||
* bit: 0 1 2 3 4 5 6 7 8 9 A B C/D E F 10 11 12 13 14 15 16
|
||||
* flg: CF 1 PF 0 AF 0 ZF SF TF IF DF OF IOPL NT 0 RF VM AC VIF VIP ID 0
|
||||
*/
|
||||
|
||||
#define FLG_CF (1<<0)
|
||||
#define FLG_PF (1<<2)
|
||||
#define FLG_AF (1<<4)
|
||||
#define FLG_ZF (1<<6)
|
||||
#define FLG_SF (1<<7)
|
||||
#define FLG_TF (1<<8)
|
||||
#define FLG_IF (1<<9)
|
||||
#define FLG_DF (1<<10)
|
||||
#define FLG_OF (1<<11)
|
||||
#define FLG_IOPL (3<<12)
|
||||
#define FLG_NT (1<<14)
|
||||
#define FLG_RF (1<<16)
|
||||
#define FLG_VM (1<<17)
|
||||
#define FLG_AC (1<<18)
|
||||
#define FLG_VIF (1<<19)
|
||||
#define FLG_VIP (1<<20)
|
||||
#define FLG_ID (1<<21)
|
||||
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
Bit8u cf:1;
|
||||
Bit8u R1:1;
|
||||
Bit8u pf:1;
|
||||
Bit8u R3:1;
|
||||
Bit8u af:1;
|
||||
Bit8u R5:1;
|
||||
Bit8u zf:1;
|
||||
Bit8u sf:1;
|
||||
Bit8u tf:1;
|
||||
Bit8u if_:1;
|
||||
Bit8u df:1;
|
||||
Bit8u of:1;
|
||||
Bit8u iopl:2;
|
||||
Bit8u nt:1;
|
||||
Bit8u R15:1;
|
||||
Bit8u rf:1;
|
||||
Bit8u vm:1;
|
||||
Bit8u ac:1;
|
||||
Bit8u vif:1;
|
||||
Bit8u vip:1;
|
||||
Bit8u id:1;
|
||||
Bit16u R31_22:10;
|
||||
} __attribute__ ((packed)) fields;
|
||||
Bit32u raw;
|
||||
} __attribute__ ((packed)) eflags_t;
|
||||
|
||||
#endif /* __EFLAGS_H__ */
|
59
bochs/plex86/kernel/include/guest_context.h
Normal file
59
bochs/plex86/kernel/include/guest_context.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* plex86: run multiple x86 operating systems concurrently
|
||||
* Copyright (C) 1999-2003 Kevin P. Lawton
|
||||
*
|
||||
* guest_context.h: monitor stack frame after exception/interrupt
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __GUEST_CONTEXT_H__
|
||||
#define __GUEST_CONTEXT_H__
|
||||
|
||||
#include "eflags.h"
|
||||
|
||||
/* This is the guest context (from ring3) pushed on the monitor stack (ring0)
|
||||
* during an exception/interrupt. Part is pushed automatically by the
|
||||
* CPU, part by the interrupt handling code.
|
||||
*
|
||||
* Values are pushed starting with the end of this structure, towards
|
||||
* the beginning, since stack pushes descend in address.
|
||||
*/
|
||||
typedef struct {
|
||||
Bit32u gs;
|
||||
Bit32u fs;
|
||||
Bit32u ds;
|
||||
Bit32u es;
|
||||
|
||||
Bit32u edi;
|
||||
Bit32u esi;
|
||||
Bit32u ebp;
|
||||
Bit32u dummy_esp;
|
||||
Bit32u ebx;
|
||||
Bit32u edx;
|
||||
Bit32u ecx;
|
||||
Bit32u eax;
|
||||
|
||||
Bit32u vector;
|
||||
Bit32u error;
|
||||
|
||||
Bit32u eip;
|
||||
Bit32u cs;
|
||||
eflags_t eflags;
|
||||
Bit32u esp;
|
||||
Bit32u ss;
|
||||
} guest_context_t;
|
||||
|
||||
#endif /* __GUEST_CONTEXT_H__ */
|
717
bochs/plex86/kernel/include/monitor.h
Normal file
717
bochs/plex86/kernel/include/monitor.h
Normal file
@ -0,0 +1,717 @@
|
||||
/*
|
||||
* plex86: run multiple x86 operating systems concurrently
|
||||
* Copyright (C) 1999-2003 Kevin P. Lawton
|
||||
*
|
||||
* monitor.h: main VM monitor defines
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __MONITOR_H__
|
||||
#define __MONITOR_H__
|
||||
|
||||
#if defined(__NetBSD__) || defined(__FreeBSD__)
|
||||
#include <machine/stdarg.h>
|
||||
#else
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "descriptor.h"
|
||||
#include "descriptor2.h"
|
||||
#include "tss.h"
|
||||
#include "paging.h"
|
||||
#include "eflags.h"
|
||||
#include "guest_context.h"
|
||||
|
||||
/* Method1: push event info (CPU pushes error code before) */
|
||||
typedef struct
|
||||
{
|
||||
Bit8u pushl; /* Always 0x68 == pushl */
|
||||
Bit32u vector; /* Interrupt vector number */
|
||||
Bit8u jmp; /* Always 0xe9 == jmp */
|
||||
Bit32u reloc; /* Relative offset of destination */
|
||||
} __attribute__ ((packed)) idt_method1_t;
|
||||
|
||||
/* Method2: push a dummy error first, then event info */
|
||||
typedef struct
|
||||
{
|
||||
Bit8u pushla; /* Always 0x68 == pushl */
|
||||
Bit32u dummy; /* Dummy error code */
|
||||
Bit8u pushlb; /* Always 0x68 == pushl */
|
||||
Bit32u vector; /* Interrupt vector number */
|
||||
Bit8u jmp; /* Always 0xe9 == jmp */
|
||||
Bit32u reloc; /* Relative offset of destination */
|
||||
} __attribute__ ((packed)) idt_method2_t;
|
||||
|
||||
typedef union
|
||||
{
|
||||
idt_method1_t m1;
|
||||
idt_method2_t m2;
|
||||
} idt_stub_t;
|
||||
|
||||
|
||||
/* Nexus fields. This C structure maps to identical assembly */
|
||||
/* fields in nexus.S. Make sure to update both! These fields */
|
||||
/* are accessible to the nexus code during the transition from */
|
||||
/* host<->guest and are stored in a single page. */
|
||||
|
||||
typedef struct {
|
||||
/* guest pointer to vm_t structure. */
|
||||
void *vm;
|
||||
|
||||
/* These fields are only used by the transition code. */
|
||||
/* They hold all info necessary to switch back to the host. */
|
||||
gdt_info_t host_gdt_info;
|
||||
gdt_info_t host_idt_info;
|
||||
far_jmp_info_t host_jmp_info;
|
||||
far_jmp_info_t host_stack_info;
|
||||
Bit16u host_ldt_sel;
|
||||
Bit16u host_tss_sel;
|
||||
Bit32u host_cr0;
|
||||
Bit32u host_cr2;
|
||||
Bit32u host_cr3;
|
||||
Bit32u host_cr4;
|
||||
|
||||
/* These fields are filled by the host-side code, and used */
|
||||
/* by the transition code. They contain all info necessary */
|
||||
/* to switch to the monitor/guest address space. */
|
||||
/* This info changes whenever the monitor migrates. */
|
||||
gdt_info_t mon_gdt_info;
|
||||
gdt_info_t mon_idt_info;
|
||||
far_jmp_info_t mon_jmp_info;
|
||||
far_jmp_info_t mon_stack_info;
|
||||
Bit16u mon_ldt_sel;
|
||||
Bit16u mon_tss_sel;
|
||||
Bit32u mon_base;
|
||||
Bit32u mon_cr0;
|
||||
Bit32u mon_cr3;
|
||||
Bit32u mon_cr4;
|
||||
Bit32u mon_eflags;
|
||||
|
||||
/* These fields contain info used by the transition code to */
|
||||
/* create the temporary identity mapping. They never change. */
|
||||
pageEntry_t transition_pde;
|
||||
pageEntry_t *transition_pde_p_host;
|
||||
pageEntry_t *transition_pde_p_mon;
|
||||
Bit32u transition_laddr;
|
||||
} __attribute__ ((packed)) nexus_t;
|
||||
|
||||
|
||||
/* For reference, the following describes where bits from the guest */
|
||||
/* eflags register are stored/managed. */
|
||||
/* */
|
||||
/* Key: */
|
||||
/* g: Flag value as requested by guest */
|
||||
/* V: Virtualized flag value, as loaded in eflags when guest is executing */
|
||||
/* ?: Unhandled yet, request of set bit causes panic for now */
|
||||
/* */
|
||||
/* === ======= ====== ======= ======= ======= */
|
||||
/* |I|V|V|A|V|R|0|N|IO|O|D|I|T|S|Z|0|A|0|P|1|C| flag */
|
||||
/* |D|I|I|C|M|F| |T|PL|F|F|F|F|F|F| |F| |F| |F| */
|
||||
/* | |P|F| | | | | | | | | | | | | | | | | | | */
|
||||
/* |g|?|?|g|V|g|g|g|VV|g|g|V|g|g|g|g|g|g|g|g|g| context->eflags */
|
||||
/* | |?|?| |g| | | |gg| | |g| | | | | | | | | | veflags */
|
||||
|
||||
/* #define VirtualizedEflags 0x001a3200 */
|
||||
#define VirtualizedEflags 0x001a3300
|
||||
|
||||
|
||||
/* I define the 'nexus' as the set of data structures which */
|
||||
/* must exist in the current linear guest address space. The */
|
||||
/* host linear address space is not available while the current */
|
||||
/* guest code is running, since we are using a completely */
|
||||
/* different set of page mappings for the guest. However, */
|
||||
/* at some point an exception/interrupt will occur. The */
|
||||
/* interrupt mechanisms require that several structures exist in */
|
||||
/* the current linear address space in order to service such */
|
||||
/* an event. These data structures make up part of our VM, */
|
||||
/* a thin layer which exists in the guest. Following is a */
|
||||
/* list of what data structures compose this 'nexus': */
|
||||
/* */
|
||||
/* - IDT (max 2048 bytes) */
|
||||
/* - GDT (max 65536 bytes) */
|
||||
/* - LDT (max 65536 bytes) */
|
||||
/* - TSS (max 8328 = 104 + 32 int redir + 8192 I/O permissions) */
|
||||
/* - kernel stack page */
|
||||
/* - transition code (host <--> guest) */
|
||||
/* - interrupt handler stubs */
|
||||
/* - Page Tables; PDE & PTE pages. */
|
||||
|
||||
/*
|
||||
* Sizes of various nexus data structures used by the monitor
|
||||
*/
|
||||
|
||||
#define PLEX86_MAX_PHY_MEGS 32
|
||||
#define PAGESIZE 4096
|
||||
|
||||
#define IDT_STUB_SIZE 15
|
||||
#define BytesToPages(b) ( ((b)+4095) >> 12 )
|
||||
|
||||
#define MON_IDT_SIZE (8*256)
|
||||
#define MON_GDT_SIZE (8*512)
|
||||
#define MON_LDT_SIZE (8*1)
|
||||
#define MON_IDT_STUBS_SIZE (IDT_STUB_SIZE*256)
|
||||
#define MON_TSS_SIZE (104)
|
||||
|
||||
#define MON_IDT_PAGES BytesToPages(MON_IDT_SIZE)
|
||||
#define MON_GDT_PAGES BytesToPages(MON_GDT_SIZE)
|
||||
#define MON_LDT_PAGES BytesToPages(MON_LDT_SIZE)
|
||||
#define MON_IDT_STUBS_PAGES BytesToPages(MON_IDT_STUBS_SIZE)
|
||||
#define MON_TSS_PAGES BytesToPages(MON_TSS_SIZE)
|
||||
|
||||
#define MON_GUEST_PAGES (PLEX86_MAX_PHY_MEGS * 256)
|
||||
/* +++ MON_PAGE_TABLES is kind of random */
|
||||
#define MON_PAGE_TABLES (10*((PLEX86_MAX_PHY_MEGS+3) >> 2))
|
||||
|
||||
#define MAX_VM_STRUCT_PAGES (68)
|
||||
|
||||
#define LOG_BUFF_PAGES 1
|
||||
#define LOG_BUFF_SIZE ((LOG_BUFF_PAGES)*4096)
|
||||
|
||||
/*
|
||||
* Pages allocated for the VM by the host kernel driver.
|
||||
* N Megs of physical memory are allocated, per the user's
|
||||
* request, for the guest OS/application code.
|
||||
* Additionally, some other overhead pages are allocated
|
||||
* for structures such as the page directory, page tables,
|
||||
* and other virtualized facilities.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
/* requested size of the guest[] array in megs and pages */
|
||||
unsigned guest_n_megs;
|
||||
unsigned guest_n_pages;
|
||||
unsigned guest_n_bytes;
|
||||
|
||||
/* pages comprising the vm_t struct itself. */
|
||||
Bit32u vm[MAX_VM_STRUCT_PAGES];
|
||||
|
||||
/* for the guest OS/app code */
|
||||
Bit32u guest[MON_GUEST_PAGES];
|
||||
|
||||
/* for the monitor's page directory */
|
||||
Bit32u page_dir;
|
||||
|
||||
/* for the monitor's page table */
|
||||
Bit32u page_tbl[MON_PAGE_TABLES];
|
||||
|
||||
/* Map of the linear addresses of page tables currently */
|
||||
/* mapped into the monitor space. */
|
||||
Bit32u page_tbl_laddr_map;
|
||||
|
||||
/* for the extra page table that maps our nexus code and structures */
|
||||
Bit32u nexus_page_tbl;
|
||||
|
||||
/* For the CPU state passed between user and kernel/monitor space. */
|
||||
Bit32u guest_cpu;
|
||||
|
||||
/* We need a Page Table for identity mapping the transition code */
|
||||
/* between host and monitor spaces. */
|
||||
Bit32u transition_PT;
|
||||
|
||||
Bit32u log_buffer[LOG_BUFF_PAGES];
|
||||
|
||||
/* Physical addresses of host pages which comprise the actual */
|
||||
/* monitor structures. These will be mapped into the current */
|
||||
/* guest task's linear address space as well. */
|
||||
Bit32u nexus;
|
||||
Bit32u idt[MON_IDT_PAGES];
|
||||
Bit32u gdt[MON_GDT_PAGES];
|
||||
Bit32u ldt[MON_LDT_PAGES];
|
||||
Bit32u tss[MON_TSS_PAGES];
|
||||
Bit32u idt_stubs[MON_IDT_STUBS_PAGES];
|
||||
} vm_pages_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
void *guest;
|
||||
|
||||
pageEntry_t *page_dir;
|
||||
page_t *page_tbl;
|
||||
unsigned *page_tbl_laddr_map;
|
||||
page_t *nexus_page_tbl;
|
||||
guest_cpu_t *guest_cpu;
|
||||
page_t *transition_PT;
|
||||
unsigned char *log_buffer;
|
||||
Bit8u *code_phy_page; /* only use in mon space */
|
||||
Bit8u *tmp_phy_page0; /* only use in mon space */
|
||||
Bit8u *tmp_phy_page1; /* only use in mon space */
|
||||
|
||||
nexus_t *nexus;
|
||||
/* Pointer into the monitor stack, so we can easily retrieve the */
|
||||
/* stack snapshot upon interrupt/exception. */
|
||||
guest_context_t *guest_context;
|
||||
gate_t *idt;
|
||||
descriptor_t *gdt;
|
||||
descriptor_t *ldt;
|
||||
tss_t *tss;
|
||||
idt_stub_t *idt_stubs;
|
||||
} vm_addr_t;
|
||||
|
||||
|
||||
/* These bits define the possible usage and attributes assigned */
|
||||
/* to a particular guest physical page. These are useful for keeping */
|
||||
/* track of what kinds of system structures are contained in a page */
|
||||
/* at a given time, and if the page has associated cached code */
|
||||
/* information in the prescan logic. We can also tag particular */
|
||||
/* pages with other more static attributes. */
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
Bit32u access_perm:2; /* */
|
||||
Bit32u lmap_count:2; /* */
|
||||
Bit32u ptbl:1; /* page table */
|
||||
Bit32u pdir:1; /* page directory */
|
||||
Bit32u vcode:1; /* vcode */
|
||||
Bit32u memMapIO:1; /* MemMapIO */
|
||||
Bit32u RO:1; /* RO */
|
||||
Bit32u allocated:1; /* Allocated */
|
||||
Bit32u swappable:1; /* Swappable */
|
||||
Bit32u spare:1; /* (spare) */
|
||||
Bit32u laddr_backlink:20; /* 1st unvirtualized laddr backlink */
|
||||
} __attribute__ ((packed)) fields;
|
||||
Bit32u raw;
|
||||
} __attribute__ ((packed)) phy_page_attr_t;
|
||||
|
||||
typedef struct {
|
||||
phy_page_attr_t attr;
|
||||
Bit64u tsc; /* for comparing to CR3 timestamp counter */
|
||||
} __attribute__ ((packed)) phy_page_usage_t;
|
||||
|
||||
/* Possible values of the access_perm field above. */
|
||||
#define PagePermRW 0
|
||||
#define PagePermRO 1
|
||||
#define PagePermEmulate 2
|
||||
#define PagePermNA PagePermEmulate /* No Access is synomym */
|
||||
|
||||
|
||||
/* Bitmasks to access fields in structure above. */
|
||||
#define PageUsagePTbl 0x010
|
||||
#define PageUsagePDir 0x020
|
||||
|
||||
#define PageUsageMemMapIO 0x080
|
||||
#define PageUsageRO 0x100
|
||||
#define PageUsageAllocated 0x200
|
||||
#define PageUsageSwappable 0x400
|
||||
|
||||
/* Group of attributes which retain their value, even when CR3 */
|
||||
/* is reloaded and the page mappings are flushed. */
|
||||
#define PageUsageSticky \
|
||||
( PageUsageMemMapIO | PageUsageRO | \
|
||||
PageUsageAllocated | PageUsageSwappable )
|
||||
|
||||
/* Group of attributes which are not compatible with a Page Table */
|
||||
/* occupying a physical page. */
|
||||
#define PageBadUsage4PTbl \
|
||||
( PageUsagePDir | PageUsageMemMapIO | PageUsageRO )
|
||||
|
||||
/* Group of attributes which are not compatible with a Page Directory */
|
||||
/* occupying a physical page. Keep in mind, when the PDir is marked, */
|
||||
/* no other dynamic bits will be set. */
|
||||
#define PageBadUsage4PDir \
|
||||
( PageUsageMemMapIO | PageUsageRO )
|
||||
|
||||
#define PageUsageCausesNA \
|
||||
( PageUsagePTbl | PageUsagePDir | PageUsageMemMapIO )
|
||||
#define PageUsageCausesRO \
|
||||
( PageUsageRO )
|
||||
|
||||
#define PDEUnhandled 0x000001d8
|
||||
#define PTEUnhandled 0x00000198
|
||||
|
||||
|
||||
#define ExceptionDE 0 /* Divide Error (fault) */
|
||||
#define ExceptionDB 1 /* Debug (fault/trap) */
|
||||
#define ExceptionBP 3 /* Breakpoint (trap) */
|
||||
#define ExceptionOF 4 /* Overflow (trap) */
|
||||
#define ExceptionBR 5 /* BOUND (fault) */
|
||||
#define ExceptionUD 6
|
||||
#define ExceptionNM 7
|
||||
#define ExceptionDF 8
|
||||
#define ExceptionTS 10
|
||||
#define ExceptionNP 11
|
||||
#define ExceptionSS 12
|
||||
#define ExceptionGP 13
|
||||
#define ExceptionPF 14
|
||||
#define ExceptionMF 16
|
||||
#define ExceptionAC 17
|
||||
|
||||
|
||||
#define CR0_PE (1<<0)
|
||||
#define CR0_MP (1<<1)
|
||||
#define CR0_EM (1<<2)
|
||||
#define CR0_TS (1<<3)
|
||||
#define CR0_ET (1<<4)
|
||||
#define CR0_NE (1<<5)
|
||||
#define CR0_WP (1<<16)
|
||||
#define CR0_AM (1<<18)
|
||||
#define CR0_NW (1<<29)
|
||||
#define CR0_CD (1<<30)
|
||||
#define CR0_PG (1<<31)
|
||||
|
||||
/*
|
||||
* Complete state of the VM (Virtual Machine).
|
||||
*/
|
||||
typedef struct {
|
||||
|
||||
/* Store eflags values of the guest which are virtualized to
|
||||
* run in the monitor
|
||||
*/
|
||||
eflags_t veflags;
|
||||
|
||||
unsigned executeMethod;
|
||||
unsigned vmState;
|
||||
|
||||
unsigned mon_request;
|
||||
unsigned guestFaultNo;
|
||||
|
||||
unsigned redirect_vector;
|
||||
|
||||
Bit32u kernel_offset;
|
||||
|
||||
#define MonitorSpace 0
|
||||
#define UserSpace 1
|
||||
#define HostSpace 2
|
||||
|
||||
volatile unsigned inMonFault;
|
||||
|
||||
/* Extra info on aborts, especially when a message can't
|
||||
* be printed out
|
||||
*/
|
||||
unsigned abort_code;
|
||||
|
||||
struct {
|
||||
Bit64u t0; /* TSC before excecution of guest code */
|
||||
Bit64u cyclesElapsed; /* Cycles of guest execution */
|
||||
unsigned a20; /* address 20 line enabled */
|
||||
Bit32u a20AddrMask; /* mask to apply to phy address */
|
||||
Bit32u a20IndexMask; /* mask to apply to phy address */
|
||||
} system;
|
||||
|
||||
cpuid_info_t guestCPUIDInfo;
|
||||
|
||||
/* This macro yields a physical address after applying the A20 line
|
||||
* enable mask to the original physical address.
|
||||
*/
|
||||
#define A20Addr(vm, paddr) ( (paddr) & ((vm)->system.a20AddrMask) )
|
||||
#define A20PageIndex(vm, pi) ( (pi) & ((vm)->system.a20IndexMask) )
|
||||
|
||||
/* Keep an index of the next available Page Table */
|
||||
unsigned ptbl_laddr_map_i;
|
||||
|
||||
Bit32u mon_pde_mask; /* Upper 10 bits of monitor lin addr space */
|
||||
Bit32u mon_pdi; /* Same value shifted down 22 bits. */
|
||||
Bit64u vpaging_tsc; /* time stamp of last page mappings flush */
|
||||
|
||||
/* We need to keep track of what each of the guest's physical */
|
||||
/* pages contains, and maintain some additional attributes. */
|
||||
/* We determine which kinds of information reside in the page, */
|
||||
/* dynamically. */
|
||||
phy_page_usage_t page_usage[MON_GUEST_PAGES];
|
||||
|
||||
struct {
|
||||
volatile unsigned event; /* Any log event occurred. */
|
||||
/* Inactive, OK to dump to host and change */
|
||||
volatile unsigned locked;
|
||||
/* Number of times buffer wrapped since last print to kernel */
|
||||
/* debug facility */
|
||||
volatile unsigned offset; /* Current index within buffer */
|
||||
volatile unsigned error; /* Error printing. (ex. string too long) */
|
||||
} log_buffer_info;
|
||||
|
||||
vm_addr_t *addr;
|
||||
vm_pages_t pages; /* memory pages allocated by the host */
|
||||
|
||||
/* Host specific fields. These fields should NOT be accessed */
|
||||
/* from code which may execute in either host or monitor/guest */
|
||||
/* spaces, unless you need to _specifically_ manipulate a */
|
||||
/* host-specific field. */
|
||||
struct {
|
||||
vm_addr_t addr; /* addresses of data structures in host space */
|
||||
void (*__host2mon)(void); /* Host to guest nexus entry point */
|
||||
pageEntry_t nexus_pde; /* PDE pointing to nexus page table */
|
||||
} host;
|
||||
|
||||
/* Guest specific fields. These fields should NOT be accessed */
|
||||
/* from code which may execute in either host or monitor/guest */
|
||||
/* spaces, unless you need to _specifically_ manipulate a */
|
||||
/* guest-specific field. */
|
||||
struct {
|
||||
vm_addr_t addr; /* addresses of data structures in guest space */
|
||||
void (*__mon2host)(void); /* monitor to host entry point */
|
||||
} guest;
|
||||
} vm_t;
|
||||
|
||||
|
||||
extern char __nexus_start, __nexus_end, __mon_cs;
|
||||
extern char __host2mon, __mon2host, __handle_fault, __handle_int;
|
||||
extern char __ret_to_guest;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This structure describes the pages containing the code/data
|
||||
* of the monitor itself (inside the kernel module)
|
||||
*/
|
||||
|
||||
#define PLEX86_MAX_MONITOR_PAGES 128
|
||||
|
||||
typedef struct {
|
||||
/* virtual address space occupied by the module */
|
||||
Bit32u startOffset;
|
||||
Bit32u startOffsetPageAligned;
|
||||
/* number of pages */
|
||||
unsigned n_pages;
|
||||
|
||||
/* the pages themselves */
|
||||
Bit32u page[PLEX86_MAX_MONITOR_PAGES];
|
||||
} monitor_pages_t;
|
||||
|
||||
extern monitor_pages_t monitor_pages;
|
||||
extern cpuid_info_t cpuid_info;
|
||||
|
||||
|
||||
|
||||
#if !defined(IN_HOST_SPACE) && !defined(IN_MONITOR_SPACE) && \
|
||||
!defined(IN_NEXUS_SPACE) && !defined(IN_R3_SPACE)
|
||||
#error "No space defined for this file"
|
||||
#endif
|
||||
|
||||
#if defined(IN_NEXUS_SPACE) || defined(IN_MONITOR_SPACE)
|
||||
void sysFlushPrintBuf(vm_t *);
|
||||
#endif /* {NEXUS, MONITOR} */
|
||||
|
||||
#if defined(IN_HOST_SPACE) || defined(IN_MONITOR_SPACE) || \
|
||||
defined(IN_NEXUS_SPACE)
|
||||
int monprint(vm_t *, char *fmt, ...);
|
||||
int mon_vsnprintf(char *str, unsigned size, const char *fmt,
|
||||
va_list args);
|
||||
void resetPrintBuf(vm_t *);
|
||||
void setINTR(vm_t *, unsigned val);
|
||||
Bit8u picIAC(vm_t *);
|
||||
|
||||
#define cache_sreg(vm, sreg) ({})
|
||||
#define cache_selector(vm, sreg) ({})
|
||||
|
||||
void mon_memzero(void *ptr, int size);
|
||||
void mon_memcpy(void *dst, void *src, int size);
|
||||
void *mon_memset(void *s, unsigned c, unsigned n);
|
||||
|
||||
#define MON_BASE_FROM_LADDR(laddr) \
|
||||
((laddr) - monitor_pages.startOffsetPageAligned)
|
||||
|
||||
/* IO logic functions. */
|
||||
unsigned ioInit(vm_t *vm);
|
||||
int registerIORHandler(vm_t *vm, unsigned space, void *thisPtr,void *callback,
|
||||
Bit32u base, unsigned len, char *name);
|
||||
int registerIOWHandler(vm_t *vm, unsigned space, void *thisPtr, void *callback,
|
||||
Bit32u base, unsigned len, char *name);
|
||||
|
||||
int registerIRQ(vm_t *vm, unsigned space, unsigned irq,
|
||||
const char *name);
|
||||
int unregisterIRQ(vm_t *vm, unsigned space, unsigned irq,
|
||||
const char *name);
|
||||
|
||||
#if 0
|
||||
void dtInitialize(vm_t *vm);
|
||||
void dtInitHashTables(vm_t *vm);
|
||||
void dtInitG2THashTable(vm_t *vm);
|
||||
unsigned isPMR3NativeCompatible(vm_t *);
|
||||
|
||||
#define DoZero (1<<0)
|
||||
#define DontZero (0<<0)
|
||||
#define AtHead (1<<1)
|
||||
#define AtTail (0<<1)
|
||||
Bit32u
|
||||
dtTranslateG2T(vm_t *vm, Bit32u guestOff, Bit32u guestLinAddr,
|
||||
Bit32u guestPhyAddr);
|
||||
#endif
|
||||
|
||||
#endif /* {HOST, MONITOR, NEXUS} */
|
||||
|
||||
|
||||
|
||||
#if defined(IN_HOST_SPACE) || defined(IN_MONITOR_SPACE)
|
||||
/* ============================================================
|
||||
* These are the functions which are available in either of the
|
||||
* host or monitor/guest spaces.
|
||||
*/
|
||||
|
||||
|
||||
/* Access to label offsets in nexus.S... From the host address perspective */
|
||||
#define HOST_NEXUS_OFFSET(vm, field) \
|
||||
( ((Bit32u)vm->host.addr.nexus) + \
|
||||
(((Bit32u) &field) - ((Bit32u) &__nexus_start)) )
|
||||
|
||||
/* From the monitor/guest address perspective. */
|
||||
#define MON_NEXUS_OFFSET(vm, field) \
|
||||
( ((Bit32u)vm->guest.addr.nexus) + \
|
||||
(((Bit32u) &field) - ((Bit32u) &__nexus_start)) )
|
||||
|
||||
/* Translate from guest laddr to monitor laddr */
|
||||
#define Guest2Monitor(vm, laddr) ( ((Bit32u) (laddr)) - \
|
||||
vm->addr->nexus->mon_base )
|
||||
#define MonOff2Lin(vm, off) ( ((Bit32u) (off)) + \
|
||||
vm->addr->nexus->mon_base )
|
||||
|
||||
static __inline__ Bit64u
|
||||
vm_rdtsc(void) {
|
||||
Bit64u ret;
|
||||
asm volatile (
|
||||
"rdtsc"
|
||||
: "=A" (ret)
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* {HOST, MONITOR} */
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef IN_HOST_SPACE
|
||||
/* ==========================================================
|
||||
* These are the functions which are available to the monitor
|
||||
* running in the host space.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Generate a software interrupt
|
||||
*/
|
||||
|
||||
#define soft_int(n) \
|
||||
asm volatile ( \
|
||||
" movb %b0, __soft_int_vector \n\t" \
|
||||
" jmp __soft_int_n \n\t" \
|
||||
"__soft_int_n: \n\t" \
|
||||
" sti \n\t" \
|
||||
" .byte 0xcd \n\t" \
|
||||
"__soft_int_vector: \n\t" \
|
||||
" .byte 0x00 \n\t" \
|
||||
: \
|
||||
: "r" ((Bit8u) (n) ) \
|
||||
: "memory" \
|
||||
)
|
||||
|
||||
int initMonitor(vm_t *);
|
||||
unsigned mapMonitor(vm_t *);
|
||||
unsigned initGuestPhyMem(vm_t *);
|
||||
void set_guest_context(vm_t *, guest_context_t *context);
|
||||
void get_guest_context(vm_t *, guest_context_t *context);
|
||||
int runGuestLoop(vm_t *);
|
||||
void unallocVmPages(vm_t *);
|
||||
int allocVmPages(vm_t *, unsigned nmegs);
|
||||
void initShadowPaging(vm_t *vm);
|
||||
void genericDeviceOpen(vm_t *);
|
||||
unsigned genericModuleInit(void);
|
||||
|
||||
unsigned hostIdle(void);
|
||||
void *hostAllocZeroedMem(unsigned long size);
|
||||
void hostFreeMem(void *ptr);
|
||||
void *hostAllocZeroedPage(void);
|
||||
void hostFreePage(void *ptr);
|
||||
unsigned hostGetAllocedMemPhyPages(Bit32u *page, int max_pages, void *ptr,
|
||||
unsigned size);
|
||||
Bit32u hostGetAllocedPagePhyPage(void *ptr);
|
||||
void hostPrint(char *fmt, ...);
|
||||
Bit32u hostKernelOffset(void);
|
||||
|
||||
unsigned getCpuCapabilities(void);
|
||||
|
||||
#define Plex86ErrnoEBUSY 1
|
||||
#define Plex86ErrnoENOMEM 2
|
||||
#define Plex86ErrnoEFAULT 3
|
||||
#define Plex86ErrnoEINVAL 4
|
||||
|
||||
int ioctlGeneric(vm_t *vm, void *inode, void *filp,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
int ioctlExecute(vm_t *vm, plex86IoctlExecute_t *executeMsg);
|
||||
unsigned ioctlAllocVPhys(vm_t *vm, unsigned long arg);
|
||||
void copyGuestStateToUserSpace(vm_t *vm);
|
||||
void reserve_guest_pages(vm_t *vm);
|
||||
void unreserve_guest_pages(vm_t *vm);
|
||||
int hostConvertPlex86Errno(unsigned ret);
|
||||
unsigned hostMMapCheck(void *i, void *f);
|
||||
void hostModuleCountReset(vm_t *vm, void *inode, void *filp);
|
||||
unsigned long hostCopyFromUser(void *to, void *from, unsigned long len);
|
||||
unsigned long hostCopyToUser(void *to, void *from, unsigned long len);
|
||||
|
||||
#define vm_save_flags(x) \
|
||||
asm volatile("pushfl ; popl %0": "=g" (x): :"memory")
|
||||
|
||||
#define vm_restore_flags(x) \
|
||||
asm volatile("pushl %0 ; popfl": :"g" (x): "memory", "cc")
|
||||
|
||||
#endif /* HOST Space */
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef IN_MONITOR_SPACE
|
||||
/* ==========================================================
|
||||
* These are the functions which are available to the monitor
|
||||
* running in the monitor/guest space.
|
||||
*/
|
||||
|
||||
|
||||
void monpanic(vm_t *, char *fmt, ...) __attribute__ ((noreturn));
|
||||
void monpanic_nomess(vm_t *);
|
||||
|
||||
|
||||
void sysRemapMonitor(vm_t *);
|
||||
void toHostGuestFault(vm_t *, unsigned fault);
|
||||
|
||||
|
||||
void guestPageFault(vm_t *, guest_context_t *context, Bit32u cr2);
|
||||
void *open_guest_phy_page(vm_t *, Bit32u ppage_index, Bit8u *mon_offset);
|
||||
void close_guest_phy_page(vm_t *, Bit32u ppage_index);
|
||||
|
||||
#define MapLinOK 0
|
||||
#define MapLinMonConflict 1
|
||||
#define MapLinAlreadyMapped 2
|
||||
#define MapLinPPageOOB 3
|
||||
#define MapLinException 4
|
||||
#define MapLinEmulate 5
|
||||
unsigned mapGuestLinAddr(vm_t *, Bit32u guest_laddr,
|
||||
Bit32u *guest_ppage_index, unsigned us,
|
||||
unsigned rw, Bit32u attr, Bit32u *error);
|
||||
unsigned addPageAttributes(vm_t *, Bit32u ppi, Bit32u attr);
|
||||
phy_page_usage_t *getPageUsage(vm_t *, Bit32u ppage_index);
|
||||
void virtualize_lconstruct(vm_t *, Bit32u l0, Bit32u l1, unsigned perm);
|
||||
|
||||
unsigned getMonPTi(vm_t *, unsigned pdi, unsigned source);
|
||||
#define invlpg_mon_offset(mon_offset) \
|
||||
asm volatile ("invlpg (%0)": :"r" (mon_offset): "memory")
|
||||
|
||||
/* For now nothing, but we should conditionally compile in code
|
||||
* to panic when the expression is not true.
|
||||
*/
|
||||
|
||||
#define VM_ASSERT(vm, expression) \
|
||||
if ( !(expression) ) \
|
||||
monpanic(vm, "Assertion (%s) failed at %s:%u", \
|
||||
#expression, __FILE__, __LINE__)
|
||||
|
||||
#define CLI() asm volatile ("cli": : : "memory")
|
||||
#define STI() asm volatile ("sti": : : "memory")
|
||||
|
||||
extern const selector_t nullSelector;
|
||||
extern const descriptor_t nullDescriptor;
|
||||
|
||||
#endif /* MONITOR Space. */
|
||||
|
||||
#endif /* __MONITOR_H__ */
|
51
bochs/plex86/kernel/include/paging.h
Normal file
51
bochs/plex86/kernel/include/paging.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* plex86: run multiple x86 operating systems concurrently
|
||||
* Copyright (C) 1999-2003 Kevin P. Lawton
|
||||
*
|
||||
* paging.h: defines for x86 paging structures
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __PAGING_H__
|
||||
#define __PAGING_H__
|
||||
|
||||
#define PG_D 0x00000040
|
||||
#define PG_A 0x00000020
|
||||
|
||||
/* Page Directory/Table format */
|
||||
typedef union {
|
||||
Bit32u raw;
|
||||
struct {
|
||||
Bit32u P:1;
|
||||
Bit32u RW:1;
|
||||
Bit32u US:1;
|
||||
Bit32u PWT:1;
|
||||
Bit32u PCD:1;
|
||||
Bit32u A:1;
|
||||
Bit32u D:1;
|
||||
Bit32u PS:1;
|
||||
Bit32u G:1;
|
||||
Bit32u avail:3;
|
||||
Bit32u base:20;
|
||||
} __attribute__ ((packed)) fields;
|
||||
} __attribute__ ((packed)) pageEntry_t;
|
||||
|
||||
typedef union {
|
||||
Bit8u bytes[4096];
|
||||
pageEntry_t pte[1024];
|
||||
} page_t;
|
||||
|
||||
#endif /* __PAGING_H__ */
|
50
bochs/plex86/kernel/include/tss.h
Normal file
50
bochs/plex86/kernel/include/tss.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* plex86: run multiple x86 operating systems concurrently
|
||||
* Copyright (C) 1999-2003 Kevin P. Lawton
|
||||
*
|
||||
* tss.h: defines for x86 hardware tasking structures
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __TSS_H__
|
||||
#define __TSS_H__
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Bit16u back, RESERVED0; /* Backlink */
|
||||
Bit32u esp0; /* The CK stack pointer */
|
||||
Bit16u ss0, RESERVED1; /* The CK stack selector */
|
||||
Bit32u esp1; /* The parent KL stack pointer */
|
||||
Bit16u ss1, RESERVED2; /* The parent KL stack selector */
|
||||
Bit32u esp2; /* Unused */
|
||||
Bit16u ss2, RESERVED3; /* Unused */
|
||||
Bit32u cr3; /* The page directory pointer */
|
||||
Bit32u eip; /* The instruction pointer */
|
||||
Bit32u eflags; /* The flags */
|
||||
Bit32u eax, ecx, edx, ebx; /* The general purpose registers */
|
||||
Bit32u esp, ebp, esi, edi; /* The special purpose registers */
|
||||
Bit16u es, RESERVED4; /* The extra selector */
|
||||
Bit16u cs, RESERVED5; /* The code selector */
|
||||
Bit16u ss, RESERVED6; /* The application stack selector */
|
||||
Bit16u ds, RESERVED7; /* The data selector */
|
||||
Bit16u fs, RESERVED8; /* And another extra selector */
|
||||
Bit16u gs, RESERVED9; /* ... and another one */
|
||||
Bit16u ldt, RESERVED10; /* The local descriptor table */
|
||||
Bit16u trap; /* The trap flag (for debugging) */
|
||||
Bit16u io; /* The I/O Map base address */
|
||||
} __attribute__ ((packed)) tss_t;
|
||||
|
||||
#endif /* __TSS_H__ */
|
1735
bochs/plex86/kernel/monitor-host.c
Normal file
1735
bochs/plex86/kernel/monitor-host.c
Normal file
File diff suppressed because it is too large
Load Diff
53
bochs/plex86/kernel/monitor-mon.c
Normal file
53
bochs/plex86/kernel/monitor-mon.c
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* plex86: run multiple x86 operating systems concurrently
|
||||
* Copyright (C) 1999-2003 Kevin P. Lawton
|
||||
*
|
||||
* system-mon.c: The 'motherboard' logic which connects the entire
|
||||
* PC system.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "plex86.h"
|
||||
#define IN_MONITOR_SPACE
|
||||
#include "monitor.h"
|
||||
|
||||
void
|
||||
sysFlushPrintBuf(vm_t *vm)
|
||||
{
|
||||
CLI();
|
||||
vm->mon_request = MonReqFlushPrintBuf;
|
||||
vm->guest.__mon2host();
|
||||
STI();
|
||||
}
|
||||
|
||||
void
|
||||
sysRemapMonitor(vm_t *vm)
|
||||
{
|
||||
CLI();
|
||||
vm->mon_request = MonReqRemapMonitor;
|
||||
vm->guest.__mon2host();
|
||||
STI();
|
||||
}
|
||||
|
||||
void
|
||||
toHostGuestFault(vm_t *vm, unsigned fault)
|
||||
{
|
||||
CLI();
|
||||
vm->mon_request = MonReqGuestFault;
|
||||
vm->guestFaultNo = fault;
|
||||
vm->guest.__mon2host();
|
||||
STI();
|
||||
}
|
326
bochs/plex86/kernel/nexus.S
Normal file
326
bochs/plex86/kernel/nexus.S
Normal file
@ -0,0 +1,326 @@
|
||||
/*
|
||||
* plex86: run multiple x86 operating systems concurrently
|
||||
* Copyright (C) 1999-2001 Kevin P. Lawton
|
||||
*
|
||||
* nexus.S: code to transition between host and monitor/guest
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
|
||||
.text
|
||||
|
||||
|
||||
/* This module consists of relocatable code and data necessary to
|
||||
* effect transitions between the host <--> guest. This information
|
||||
* is purposely stored in this single page, so that we have access
|
||||
* to it during our transitions between the monitor interrupt handler,
|
||||
* and our host.
|
||||
*
|
||||
* I coded the relevant parts to use completely relocatable
|
||||
* accesses to the following fields. This is necessary, so that
|
||||
* we can float this code page anywhere in the monitor's linear
|
||||
* address space.
|
||||
*/
|
||||
|
||||
/* ===============================================================
|
||||
* NOTE: If you modify ANY of the following fields, you must also
|
||||
* update the corresponding entries in the C typedef 'nexus_t'.
|
||||
* That construct is used from C land to access values in this
|
||||
* relocatable page.
|
||||
*/
|
||||
|
||||
.globl __nexus_start
|
||||
__nexus_start:
|
||||
|
||||
__vm: ;.skip 4, 0
|
||||
|
||||
__host_gdt_info: ;.skip 6, 0
|
||||
__host_idt_info: ;.skip 6, 0
|
||||
__host_jmp_info: ;.skip 6, 0
|
||||
__host_stack_info: ;.skip 6, 0
|
||||
__host_ldt_sel: ;.skip 2, 0
|
||||
__host_tss_sel: ;.skip 2, 0
|
||||
__host_cr0: ;.skip 4, 0
|
||||
__host_cr2: ;.skip 4, 0
|
||||
__host_cr3: ;.skip 4, 0
|
||||
__host_cr4: ;.skip 4, 0
|
||||
|
||||
__mon_gdt_info: ;.skip 6, 0
|
||||
__mon_idt_info: ;.skip 6, 0
|
||||
__mon_jmp_info: ;.skip 6, 0
|
||||
__mon_stack_info: ;.skip 6, 0
|
||||
__mon_ldt_sel: ;.skip 2, 0
|
||||
__mon_tss_sel: ;.skip 2, 0
|
||||
__mon_base: ;.skip 4, 0
|
||||
__mon_cr0: ;.skip 4, 0
|
||||
__mon_cr3: ;.skip 4, 0
|
||||
__mon_cr4: ;.skip 4, 0
|
||||
__mon_eflags: ;.skip 4, 0
|
||||
|
||||
__transition_pde: ;.skip 4, 0
|
||||
__transition_pde_p_host: ;.skip 4, 0
|
||||
__transition_pde_p_mon: ;.skip 4, 0
|
||||
__transition_laddr: ;.skip 4, 0
|
||||
|
||||
/* ===============================================================
|
||||
* End NOTE.
|
||||
*/
|
||||
|
||||
#define OFFSET_OF(field) [field - __nexus_start]
|
||||
|
||||
/* These are the offsets of the structures above, from the */
|
||||
/* beginning of this section. */
|
||||
#define HOST_GDT_INFO OFFSET_OF(__host_gdt_info)
|
||||
#define HOST_IDT_INFO OFFSET_OF(__host_idt_info)
|
||||
#define HOST_JMP_INFO OFFSET_OF(__host_jmp_info)
|
||||
#define HOST_STACK_INFO OFFSET_OF(__host_stack_info)
|
||||
#define HOST_LDT_SEL OFFSET_OF(__host_ldt_sel)
|
||||
#define HOST_TSS_SEL OFFSET_OF(__host_tss_sel)
|
||||
#define HOST_CR0 OFFSET_OF(__host_cr0)
|
||||
#define HOST_CR2 OFFSET_OF(__host_cr2)
|
||||
#define HOST_CR3 OFFSET_OF(__host_cr3)
|
||||
#define HOST_CR4 OFFSET_OF(__host_cr4)
|
||||
|
||||
#define MON_GDT_INFO OFFSET_OF(__mon_gdt_info)
|
||||
#define MON_IDT_INFO OFFSET_OF(__mon_idt_info)
|
||||
#define MON_JMP_INFO OFFSET_OF(__mon_jmp_info)
|
||||
#define MON_STACK_INFO OFFSET_OF(__mon_stack_info)
|
||||
#define MON_LDT_SEL OFFSET_OF(__mon_ldt_sel)
|
||||
#define MON_TSS_SEL OFFSET_OF(__mon_tss_sel)
|
||||
#define MON_CR0 OFFSET_OF(__mon_cr0)
|
||||
#define MON_CR3 OFFSET_OF(__mon_cr3)
|
||||
#define MON_CR4 OFFSET_OF(__mon_cr4)
|
||||
#define MON_BASE OFFSET_OF(__mon_base)
|
||||
|
||||
#define TRANSITION_PDE OFFSET_OF(__transition_pde)
|
||||
#define TRANSITION_PDE_P_HOST OFFSET_OF(__transition_pde_p_host)
|
||||
#define TRANSITION_PDE_P_MON OFFSET_OF(__transition_pde_p_mon)
|
||||
#define TRANSITION_LADDR OFFSET_OF(__transition_laddr)
|
||||
|
||||
|
||||
/* To make this code page and data accesses to the fields above */
|
||||
/* relocatable, I use the following conventions. I load EBX with */
|
||||
/* a pointer to the beginning of this page, to be used with an */
|
||||
/* access through the CS: segment. We can easily get the */
|
||||
/* current EIP with a call/pop EBX, so the combination of CS:EBX, */
|
||||
/* accesses this page no matter where it is located. */
|
||||
|
||||
|
||||
/* ================================================================== */
|
||||
.globl __host2mon /* Start function __host2mon() */
|
||||
__host2mon:
|
||||
/* Save host context first, so it can be restored later */
|
||||
pushfl /* Save host flags */
|
||||
pushal /* Save host general regs */
|
||||
pushl %es /* Save host segments */
|
||||
pushl %ds
|
||||
pushl %fs
|
||||
pushl %gs
|
||||
|
||||
/* Put EIP of beginning of this section in EBX to be used to */
|
||||
/* access data. */
|
||||
call null_call
|
||||
null_call:
|
||||
popl %ebx
|
||||
subl $(OFFSET_OF(null_call)), %ebx
|
||||
|
||||
/* Create identity mapping of this page into the monitor context */
|
||||
movl (TRANSITION_PDE_P_HOST)(%ebx), %eax
|
||||
movl (TRANSITION_PDE)(%ebx), %ebp
|
||||
xchgl %ebp, (%eax) /* old PDE saved in %ebp to be restored below */
|
||||
|
||||
/* Save host GDT, LDT, IDT, and TSS */
|
||||
sgdt (HOST_GDT_INFO)(%ebx)
|
||||
sidt (HOST_IDT_INFO)(%ebx)
|
||||
sldt (HOST_LDT_SEL)(%ebx)
|
||||
str (HOST_TSS_SEL)(%ebx)
|
||||
|
||||
movl %esp, (HOST_STACK_INFO)(%ebx) /* Save host SS:ESP */
|
||||
movw %ss, (4+HOST_STACK_INFO)(%ebx) /* for later restore */
|
||||
|
||||
leal (OFFSET_OF(__host_cs))(%ebx), %eax /* Save the CS:EIP for monitor to */
|
||||
movl %eax, (HOST_JMP_INFO)(%ebx) /* jump to when reloading host CS. */
|
||||
movw %cs, (4+HOST_JMP_INFO)(%ebx) /* See __guest2host below. */
|
||||
|
||||
/* Save host CRx values */
|
||||
movl %cr0, %eax
|
||||
movl %cr2, %ecx
|
||||
movl %cr4, %edx
|
||||
movl %cr3, %esi
|
||||
|
||||
movl %eax, (HOST_CR0)(%ebx)
|
||||
movl %ecx, (HOST_CR2)(%ebx)
|
||||
movl %edx, (HOST_CR4)(%ebx)
|
||||
movl %esi, (HOST_CR3)(%ebx)
|
||||
|
||||
/* Compute monitor CRx values */
|
||||
movl (MON_CR0)(%ebx), %eax
|
||||
movl (MON_CR4)(%ebx), %edx
|
||||
movl (MON_CR3)(%ebx), %esi
|
||||
|
||||
/* Before changing the PSE bit in CR4, we have to switch over */
|
||||
/* to the new CR3 (this page identity mapped anyways). Otherwise */
|
||||
/* the processor could flush the TLB, and reload the entry for */
|
||||
/* this page, only to find it's marked with a 4Meg Page, but we */
|
||||
/* have that support turned off, before we actually */
|
||||
/* reloaded CR3! */
|
||||
movl %esi, %cr3 /* Set monitor CR3 */
|
||||
movl %eax, %cr0 /* Set monitor CR0 */
|
||||
movl %edx, %cr4 /* Set monitor CR4 */
|
||||
movl %esi, %cr3 /* Set monitor CR3 */
|
||||
|
||||
jmp null_jmp0
|
||||
null_jmp0:
|
||||
|
||||
/* Switch to monitor GDT, LDT, and IDT */
|
||||
lgdt (MON_GDT_INFO)(%ebx)
|
||||
lidt (MON_IDT_INFO)(%ebx)
|
||||
lldt (MON_LDT_SEL)(%ebx)
|
||||
|
||||
/* Switch to monitor stack and CS */
|
||||
/* and jump to the monitor-side nexus page */
|
||||
lss (MON_STACK_INFO)(%ebx), %esp
|
||||
ljmp (MON_JMP_INFO)(%ebx)
|
||||
.globl __mon_cs
|
||||
__mon_cs:
|
||||
|
||||
/* Reset DS:EBX to point to the monitor-side nexus page */
|
||||
movw %ss, %ax
|
||||
movw %ax, %ds /* copy SS to DS */
|
||||
movw %ax, %es /* copy SS to ES */
|
||||
movl %esp, %ebx
|
||||
andl $0xfffff000, %ebx
|
||||
|
||||
/* Clear busy bit of the monitor TSS and switch to it */
|
||||
movzwl (MON_TSS_SEL)(%ebx), %eax
|
||||
andl $0xfffffff8, %eax
|
||||
addl (MON_GDT_INFO+2)(%ebx), %eax
|
||||
subl (MON_BASE)(%ebx), %eax
|
||||
andl $0xfffffdff, 4(%eax)
|
||||
ltr (MON_TSS_SEL)(%ebx)
|
||||
|
||||
/* We no longer need the nexus page identity mapped. Fix the mapping */
|
||||
/* back to the way it should be, in case guest code uses it. */
|
||||
movl (TRANSITION_PDE_P_MON)(%ebx), %eax
|
||||
movl %ebp, (%eax) /* %ebp still contains the original value */
|
||||
movl (TRANSITION_LADDR)(%ebx), %eax
|
||||
invlpg (%eax) /* Tell TLB about the change */
|
||||
/* +++ xxx fix this, need to convert pure laddr to offset */
|
||||
movl %cr3, %eax /* +++ xxx */
|
||||
movl %eax, %cr3 /* +++ xxx */
|
||||
|
||||
/* */
|
||||
/* We can now restore the monitor context from it's stack. */
|
||||
/* */
|
||||
popl %gs
|
||||
popl %fs
|
||||
popal /* Restore mon general registers */
|
||||
popfl /* Restore mon eflags */
|
||||
ret /* Resume execution in monitor exception handler code. */
|
||||
|
||||
|
||||
|
||||
/* ================================================================== */
|
||||
.globl __mon2host /* Start function __mon2host() */
|
||||
__mon2host:
|
||||
pushfl /* Save mon flags */
|
||||
pushal /* Save mon general registers */
|
||||
pushl %fs
|
||||
pushl %gs
|
||||
|
||||
/* Set EBX to point to this nexus page */
|
||||
movl %esp, %ebx
|
||||
andl $0xfffff000, %ebx
|
||||
|
||||
movl %esp, (MON_STACK_INFO)(%ebx) /* Save mon ESP */
|
||||
|
||||
/* Identity map this code page to host address space. */
|
||||
movl (TRANSITION_PDE_P_MON)(%ebx), %eax
|
||||
movl (TRANSITION_PDE)(%ebx), %ebp
|
||||
xchgl %ebp, (%eax) /* old PDE saved in %ebp to be restored below */
|
||||
movl (TRANSITION_LADDR)(%ebx), %eax
|
||||
|
||||
/* Switch EBX to point to the identity mapped copy of */
|
||||
/* the nexus page, and jump to the copy of this code there. */
|
||||
subl (MON_BASE)(%ebx), %eax
|
||||
invlpg (%eax) /* Tell TLB about the change */
|
||||
movl %eax, %ebx
|
||||
leal (OFFSET_OF(__mon_nexus_jmp))(%ebx), %eax
|
||||
jmp *%eax
|
||||
__mon_nexus_jmp:
|
||||
|
||||
/* We are still in the monitor context, but are running at the */
|
||||
/* same CS.base+EIP location in either host or monitor context, */
|
||||
/* and this page is identity mapped between the 2 contexts. */
|
||||
/* We can now switch to the host CR3, and be sure that execution */
|
||||
/* will resume at the next instruction. */
|
||||
|
||||
/* NOTE: Don't try to access the stack after CR3 was reloaded */
|
||||
/* but before we switched back to the host stack! */
|
||||
|
||||
/* Restore host CRx values */
|
||||
movl (HOST_CR0)(%ebx), %eax
|
||||
movl (HOST_CR2)(%ebx), %ecx
|
||||
movl (HOST_CR4)(%ebx), %edx
|
||||
movl (HOST_CR3)(%ebx), %esi
|
||||
|
||||
movl %eax, %cr0
|
||||
movl %ecx, %cr2
|
||||
movl %edx, %cr4
|
||||
movl %esi, %cr3
|
||||
|
||||
jmp null_jmp1
|
||||
null_jmp1:
|
||||
|
||||
/* Switch to host GDT, LDT, and IDT */
|
||||
lgdt (HOST_GDT_INFO)(%ebx)
|
||||
lidt (HOST_IDT_INFO)(%ebx)
|
||||
lldt (HOST_LDT_SEL)(%ebx)
|
||||
|
||||
/* Restore host stack and CS */
|
||||
lss (HOST_STACK_INFO)(%ebx), %esp
|
||||
ljmp (HOST_JMP_INFO)(%ebx)
|
||||
__host_cs:
|
||||
|
||||
/* Clear busy bit of the host TSS and switch to it */
|
||||
/* Note that DS is still the monitor segment with base (MON_BASE). */
|
||||
movzwl (HOST_TSS_SEL)(%ebx), %eax
|
||||
andl $0xfffffff8, %eax
|
||||
addl (HOST_GDT_INFO+2)(%ebx), %eax
|
||||
subl (MON_BASE)(%ebx), %eax
|
||||
andl $0xfffffdff, 4(%eax)
|
||||
ltr (HOST_TSS_SEL)(%ebx)
|
||||
|
||||
/* We no longer need the nexus page identity mapped, so we clean */
|
||||
/* up the monitor page directory in case the host looks at it. */
|
||||
/* Note that SS is already the host segment. */
|
||||
movl (TRANSITION_PDE_P_HOST)(%ebx), %eax
|
||||
ss; movl %ebp, (%eax) /* %ebp still contains the original value */
|
||||
|
||||
/* Now we can restore the rest of */
|
||||
/* the host context from the host stack. Look at __host2guest */
|
||||
/* for the format of the values stored on the host stack. */
|
||||
popl %gs
|
||||
popl %fs
|
||||
popl %ds
|
||||
popl %es
|
||||
popal
|
||||
popfl
|
||||
ret
|
||||
|
||||
.globl __nexus_end
|
||||
__nexus_end:
|
745
bochs/plex86/kernel/paging-mon.c
Normal file
745
bochs/plex86/kernel/paging-mon.c
Normal file
@ -0,0 +1,745 @@
|
||||
/*
|
||||
* plex86: run multiple x86 operating systems concurrently
|
||||
* Copyright (C) 1999-2003 Kevin P. Lawton
|
||||
*
|
||||
* paging-mon.c: Virtualized (monitor) paging functionality.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "plex86.h"
|
||||
#define IN_MONITOR_SPACE
|
||||
#include "monitor.h"
|
||||
|
||||
|
||||
|
||||
static unsigned allocatePT(vm_t *, unsigned pdi);
|
||||
static unsigned strengthenPagePermissions(vm_t *, phy_page_usage_t *usage,
|
||||
unsigned new_access_perm);
|
||||
/*static void sanity_check_pdir(vm_t *vm, unsigned id, Bit32u guest_laddr); */
|
||||
|
||||
/* +++ fix retrieve mon pages function and .base issue */
|
||||
/* also open_guest_phy_page expects shifted page val */
|
||||
/* +++ write_physical() has hack to ignore when perm!=RW, fix! */
|
||||
/* +++ add async handling in emulation.c, like in preGuest() */
|
||||
|
||||
/* Cases which would generate a mon #PF */
|
||||
/* ==================================== */
|
||||
/* lazy map */
|
||||
/* r/w to current code page */
|
||||
/* guest #PF (access checks of cpl,rw) */
|
||||
/* w to RO construct */
|
||||
/* r/w to NA construct */
|
||||
|
||||
/* inhibits */
|
||||
|
||||
|
||||
#if 0
|
||||
======= Old notes =====================================================
|
||||
IDT,GDT,LDT: limit = 64K; TR is a dont care
|
||||
What to do with PDir, PTbl?
|
||||
What to do about coherence probs with page tables and TLB?
|
||||
When are A,D bits copied between monitor and host?
|
||||
Need check for mapping of space used by monitor
|
||||
|
||||
Code cache probably should not have laddr in it
|
||||
|
||||
guest.PG==0, how are phy pages unmarked when constructs move?
|
||||
guest.PG transition: dump everything (flush)
|
||||
|
||||
remapping descriptor tables after page flush
|
||||
make sure to validate phy_attr everywhere before using it.
|
||||
|
||||
checks for the phy_attr of page that PDir goes in
|
||||
page fault because of monP?E.RW==0, but guestP?E==1
|
||||
|
||||
/* +++ what about virtualized linear structs like GDT, IDT, ... */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
unsigned
|
||||
allocatePT(vm_t *vm, unsigned pdi)
|
||||
{
|
||||
unsigned map_i;
|
||||
|
||||
/* Allocate one of the (preallocated) pages for */
|
||||
/* the monitor to use for a page table at the PDI given. */
|
||||
|
||||
map_i = vm->ptbl_laddr_map_i;
|
||||
|
||||
if (map_i >= MON_PAGE_TABLES) {
|
||||
monpanic(vm, "allocatePT: out of page tables\n");
|
||||
}
|
||||
#if ANAL_CHECKS
|
||||
if (vm->guest.addr.page_tbl_laddr_map[pdi] != -1) {
|
||||
monprint(vm, "allocatePT: check failed.\n");
|
||||
monpanic(vm, " pdi=0x%x, laddr_map=0x%x\n",
|
||||
pdi, vm->guest.addr.page_tbl_laddr_map[pdi]);
|
||||
}
|
||||
#endif
|
||||
vm->guest.addr.page_tbl_laddr_map[pdi] = map_i;
|
||||
vm->ptbl_laddr_map_i++;
|
||||
return(map_i);
|
||||
}
|
||||
|
||||
unsigned
|
||||
getMonPTi(vm_t *vm, unsigned pdi, unsigned source)
|
||||
{
|
||||
unsigned map_i;
|
||||
map_i = vm->guest.addr.page_tbl_laddr_map[pdi];
|
||||
#if ANAL_CHECKS
|
||||
if (map_i == -1) {
|
||||
monprint(vm, "getMonPTi: check failed.\n");
|
||||
monpanic(vm, " pdi=0x%x, map_i=0x%x, source=%u\n",
|
||||
pdi, map_i, source);
|
||||
}
|
||||
if (map_i >= MON_PAGE_TABLES)
|
||||
monpanic(vm, "getMonPTi: map_i OOB\n");
|
||||
#endif
|
||||
return(map_i);
|
||||
}
|
||||
|
||||
|
||||
/* Invalidate the mapping of a guest page in the monitor.
|
||||
* When situations change, such as a change in the permissions
|
||||
* necessary to virtualize the page properly, we'll need to do
|
||||
* this first, before remapping with the new permissions.
|
||||
*/
|
||||
unsigned
|
||||
strengthenPagePermissions(vm_t *vm, phy_page_usage_t *pusage,
|
||||
unsigned new_access_perm)
|
||||
{
|
||||
pusage->attr.fields.access_perm = new_access_perm;
|
||||
|
||||
if (pusage->attr.fields.lmap_count == 0) {
|
||||
/* No linear addresses are mapped to this phy page yet.
|
||||
* Nothing to do. */
|
||||
return 0;
|
||||
}
|
||||
else if (pusage->attr.fields.lmap_count == 1) {
|
||||
/* One linear address is mapped to this phy page. */
|
||||
Bit32u pdi, pti;
|
||||
pageEntry_t *monPDE, *monPTE;
|
||||
page_t *monPTbl;
|
||||
unsigned map_i;
|
||||
|
||||
pdi = (pusage->attr.fields.laddr_backlink >> 10);
|
||||
pti = (pusage->attr.fields.laddr_backlink & 0x3ff);
|
||||
monPDE = &vm->guest.addr.page_dir[pdi];
|
||||
if ( !monPDE->fields.P )
|
||||
monpanic(vm, "strengthenPP: monPDE.P==0\n");
|
||||
map_i = getMonPTi(vm,pdi,10);
|
||||
monPTbl = &vm->guest.addr.page_tbl[map_i];
|
||||
monPTE = &monPTbl->pte[pti];
|
||||
if ( !monPTE->fields.P ) {
|
||||
|
||||
/*monprint(vm, "strengthenPP: bl=0x%x, AP=%u\n",
|
||||
*pusage->attr.fields.laddr_backlink, new_access_perm); */
|
||||
|
||||
/*monpanic(vm, "strengthenPP: monPTE.P==0\n"); */
|
||||
}
|
||||
else if (pusage->attr.fields.access_perm==PagePermNA) {
|
||||
/* Permissions were changed to No Access */
|
||||
monPTE->raw = 0;
|
||||
}
|
||||
else if (pusage->attr.fields.access_perm==PagePermRO) {
|
||||
/* Permissions were changed to RO */
|
||||
monPTE->fields.RW = 0;
|
||||
}
|
||||
else {
|
||||
monpanic(vm, "strengthenPP: PagePermRW\n");
|
||||
}
|
||||
/* Flush the old TLB entry */
|
||||
invlpg_mon_offset(
|
||||
Guest2Monitor(vm, pusage->attr.fields.laddr_backlink<<12)
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
/* Multiple linear addresses are mapped to this phy page. */
|
||||
/* Since we dont store enough backlink info to virtualize all */
|
||||
/* linear addresses which point to this phy page, we have to dump */
|
||||
/* all dynamic mappings and start over. */
|
||||
monpanic(vm, "strengthenPP: multiple lin addr\n");
|
||||
/*monPagingRemap(vm);*/
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
addPageAttributes(vm_t *vm, Bit32u ppi, Bit32u req_attr)
|
||||
{
|
||||
phy_page_usage_t *pusage;
|
||||
unsigned new_access_perm;
|
||||
|
||||
VM_ASSERT(vm, ppi < vm->pages.guest_n_pages);
|
||||
|
||||
pusage = &vm->page_usage[ppi];
|
||||
if (pusage->tsc < vm->vpaging_tsc) {
|
||||
/* The dynamic attributes for this page are not valid since
|
||||
* the last remap. getPageUsage() has logic to build attributes.
|
||||
*/
|
||||
getPageUsage(vm, ppi);
|
||||
}
|
||||
|
||||
/* Build new attributes based on old ones, and requested ones. */
|
||||
pusage->attr.raw |= req_attr;
|
||||
|
||||
/* Look at strength of new access restrictions */
|
||||
if (pusage->attr.raw & PageUsageCausesNA)
|
||||
new_access_perm = PagePermNA;
|
||||
else if (pusage->attr.raw & PageUsageCausesRO)
|
||||
new_access_perm = PagePermRO;
|
||||
else
|
||||
new_access_perm = PagePermRW;
|
||||
|
||||
if (new_access_perm > pusage->attr.fields.access_perm) {
|
||||
/* New usage causes a stronger access restriction. Remap them. */
|
||||
return( strengthenPagePermissions(vm, pusage, new_access_perm) );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
phy_page_usage_t *
|
||||
getPageUsage(vm_t *vm, Bit32u ppi)
|
||||
{
|
||||
phy_page_usage_t *pusage;
|
||||
|
||||
VM_ASSERT(vm, ppi < vm->pages.guest_n_pages);
|
||||
pusage = &vm->page_usage[ppi];
|
||||
|
||||
if (pusage->tsc < vm->vpaging_tsc) {
|
||||
/* The dynamic attributes for this page are not valid since
|
||||
* the last remap. Clear them out, and timestamp.
|
||||
*/
|
||||
pusage->tsc = vm_rdtsc();
|
||||
pusage->attr.raw &= PageUsageSticky;
|
||||
if (pusage->attr.raw & PageUsageCausesNA)
|
||||
pusage->attr.fields.access_perm = PagePermNA;
|
||||
else if (pusage->attr.raw & PageUsageCausesRO)
|
||||
pusage->attr.fields.access_perm = PagePermRO;
|
||||
else
|
||||
pusage->attr.fields.access_perm = PagePermRW;
|
||||
}
|
||||
return(pusage);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
open_guest_phy_page(vm_t *vm, Bit32u ppi, Bit8u *mon_offset)
|
||||
{
|
||||
page_t *pageTable;
|
||||
Bit32u pti, mon_range_offset;
|
||||
|
||||
VM_ASSERT(vm, ppi < vm->pages.guest_n_pages);
|
||||
/* Since we rewind our CS/DS.base so that the beginning of our */
|
||||
/* monitor pages land on the beginning of a new 4Meg boundary */
|
||||
/* (separate PDE), find out what mon_offset is in terms of */
|
||||
/* an offset from the beginning of the PDE boundary. */
|
||||
mon_range_offset = ( ((Bit32u) mon_offset) -
|
||||
monitor_pages.startOffsetPageAligned );
|
||||
pti = (mon_range_offset >> 12) & 0x3ff;
|
||||
pageTable = vm->guest.addr.nexus_page_tbl;
|
||||
|
||||
/* Remap the base field. All the rest of the fields are */
|
||||
/* set previously, and can remain the same. */
|
||||
pageTable->pte[pti].fields.base = vm->pages.guest[ppi];
|
||||
invlpg_mon_offset( (Bit32u) mon_offset );
|
||||
return(mon_offset);
|
||||
}
|
||||
|
||||
void
|
||||
close_guest_phy_page(vm_t *vm, Bit32u ppi)
|
||||
{
|
||||
/* ppi is >> 12 already */
|
||||
/* +++ */
|
||||
}
|
||||
|
||||
void
|
||||
virtualize_lconstruct(vm_t *vm, Bit32u l0, Bit32u l1, unsigned perm)
|
||||
{
|
||||
/* Mark pages for a protected construct in linear space as */
|
||||
/* virtualized (protected), if it is mapped into monitor space. */
|
||||
/* Pages which are not yet mapped in, are virtualized dynamically */
|
||||
/* when they are mapped in. */
|
||||
|
||||
Bit32u pdi, pdi0, pdi1, pti, pti0, pti1;
|
||||
pageEntry_t *monPDE, *monPTE;
|
||||
page_t *monPTbl;
|
||||
|
||||
/* +++ For now, can just dump all page mappings and start over */
|
||||
/* again. Need to complete this function, so we can virtualize */
|
||||
/* only those pages which need it, and keep the other ones. */
|
||||
/* +++ Need to look at perm also. */
|
||||
monpanic(vm, "vir_lconstruct: unfinished.\n");
|
||||
/*monPagingRemap(vm);*/
|
||||
return;
|
||||
|
||||
if (vm->guest.addr.guest_cpu->cr0.fields.pg)
|
||||
monpanic(vm, "virtualize_lconstruct: guest PG==1\n");
|
||||
if (l0 >= l1)
|
||||
monpanic(vm, "virtualize_lconstruct: l0>=l1!\n");
|
||||
if ( (l1-l0) > (64*1024) )
|
||||
monpanic(vm, "virtualize_lconstruct: span is > 64k!\n");
|
||||
pdi0 = l0 >> 22;
|
||||
pdi1 = l1 >> 22;
|
||||
pti0 = (l0 >> 12) & 0x000003ff;
|
||||
for (pdi=pdi0; pdi<=pdi1; pdi++) {
|
||||
if ( pdi == vm->mon_pdi )
|
||||
monpanic(vm, "virtualize_lconstruct: conflict with monitor space\n");
|
||||
monPDE = &vm->guest.addr.page_dir[pdi];
|
||||
if (monPDE->fields.P) {
|
||||
if (pdi<pdi1)
|
||||
pti1 = 0x3ff; /* spans multiple pdi's, use last index of range */
|
||||
else
|
||||
pti1 = (l1 >> 12) & 0x000003ff; /* use index of last address */
|
||||
for (pti=pti0; pti<=pti1; pti++) {
|
||||
/* +++ */
|
||||
/* +++ FIX THIS!!!, set depending on guest.CR0.PG */
|
||||
/* +++ */
|
||||
monPTbl = &vm->guest.addr.page_tbl[pdi];
|
||||
monPTE = &monPTbl->pte[pti];
|
||||
if (monPTE->fields.P) {
|
||||
/* +++ finish this! */
|
||||
/* The physical page for this linear address is allocated */
|
||||
/* and mapped into the monitor. We can access the attributes */
|
||||
/* for this physical page. Even if it has been virtualized */
|
||||
/* before, we still need to mark it since it could have been */
|
||||
/* virtualized due to a physical page constraint. */
|
||||
monpanic(vm, "virtualize_lconstruct: finish.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
pti0 = 0; /* start address at boundary of next PDI */
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
mapGuestLinAddr(vm_t *vm, Bit32u guest_laddr, Bit32u *guest_ppi,
|
||||
unsigned req_us, unsigned req_rw, Bit32u attr,
|
||||
Bit32u *error)
|
||||
{
|
||||
Bit32u pdi, pti;
|
||||
Bit32u guest_lpage_index, ptbl_ppi;
|
||||
page_t *monPTbl;
|
||||
pageEntry_t *monPDE, *monPTE;
|
||||
pageEntry_t *guestPDir, guestPDE, *guestPTbl, guestPTE;
|
||||
Bit32u guest_pdir_page_index;
|
||||
unsigned pt_index, us, rw;
|
||||
phy_page_usage_t *pusage;
|
||||
unsigned wasRemap = 0;
|
||||
|
||||
guest_lpage_index = guest_laddr >> 12;
|
||||
pdi = guest_lpage_index >> 10;
|
||||
pti = guest_lpage_index & 0x3ff;
|
||||
monPDE = &vm->guest.addr.page_dir[pdi];
|
||||
|
||||
if (vm->guest.addr.guest_cpu->cr0.fields.pg) {
|
||||
/* Check out the guest's mapping of this address to see */
|
||||
/* if would allow for an access. */
|
||||
/* First, get the guest PDE */
|
||||
guest_pdir_page_index = A20Addr(vm, vm->guest.addr.guest_cpu->cr3) >> 12;
|
||||
if (guest_pdir_page_index >= vm->pages.guest_n_pages)
|
||||
monpanic(vm, "mapGuestLinAddr: PG=1 guest PDE OOB\n");
|
||||
/* Open a window into guest physical memory */
|
||||
guestPDir = open_guest_phy_page(vm, guest_pdir_page_index,
|
||||
vm->guest.addr.tmp_phy_page0);
|
||||
guestPDE = guestPDir[pdi];
|
||||
|
||||
/* See if present, before fetching PTE */
|
||||
if (guestPDE.fields.P==0) {
|
||||
*error = 0x00000000; /* RSVD=0, P=0 */
|
||||
goto np_exception;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (vm->guestCpuIDInfo.procSignature.fields.family < 6) {
|
||||
/* Update A bit of PDE memory image if not already */
|
||||
if ( guestPDE.fields.A == 0 ) {
|
||||
guestPDE.fields.A = 1;
|
||||
guestPDir[pdi] = guestPDE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Second, get the guest PDE */
|
||||
ptbl_ppi = A20PageIndex(vm, guestPDE.fields.base);
|
||||
if (ptbl_ppi >= vm->pages.guest_n_pages)
|
||||
monpanic(vm, "mapGuestLinAddr: PG=1 guest PTE OOB\n");
|
||||
guestPTbl = open_guest_phy_page(vm, ptbl_ppi,
|
||||
vm->guest.addr.tmp_phy_page1);
|
||||
guestPTE = guestPTbl[pti];
|
||||
|
||||
if (guestPTE.fields.P==0) {
|
||||
*error = 0x00000000; /* RSVD=0, P=0 */
|
||||
goto np_exception;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* +++ */
|
||||
if (guestPDE.raw & PDEUnhandled)
|
||||
monpanic(vm, "mapGuestLinAddr: guestPDE 0x%08x\n", guestPDE.raw);
|
||||
#endif
|
||||
/* See if requested guest priv is weaker than guest PDE priv */
|
||||
if (req_us > guestPDE.fields.US) {
|
||||
*error = 0x00000001; /* RSVD=0, P=1 */
|
||||
goto access_exception;
|
||||
}
|
||||
if ( (req_rw > guestPDE.fields.RW) &&
|
||||
(vm->guest.addr.guest_cpu->cr0.fields.wp || req_us) ) {
|
||||
*error = 0x00000001; /* RSVD=0, P=1 */
|
||||
goto access_exception;
|
||||
}
|
||||
|
||||
#warning "ignoring PTEUnhandled bits"
|
||||
#if 0
|
||||
if (guestPTE.raw & PTEUnhandled)
|
||||
monpanic(vm, "mapGuestLinAddr: guestPTE 0x%08x\n", guestPTE.raw);
|
||||
#endif
|
||||
if (req_us > guestPTE.fields.US) {
|
||||
*error = 0x00000001; /* RSVD=0, P=1 */
|
||||
goto access_exception;
|
||||
}
|
||||
if ( (req_rw > guestPTE.fields.RW) &&
|
||||
(vm->guest.addr.guest_cpu->cr0.fields.wp || req_us) ) {
|
||||
*error = 0x00000001; /* RSVD=0, P=1 */
|
||||
goto access_exception;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (vm->guestCpuIDInfo.procSignature.fields.family >= 6) {
|
||||
/* Update A bit of PDE memory image if not already */
|
||||
if ( guestPDE.fields.A == 0 ) {
|
||||
guestPDE.fields.A = 1;
|
||||
guestPDir[pdi] = guestPDE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update A bit in PTE memory image if not already */
|
||||
if ( (guestPTE.fields.A == 0) ||
|
||||
((req_rw==1) && !guestPTE.fields.D) ) {
|
||||
guestPTE.fields.A = 1;
|
||||
if (req_rw==1)
|
||||
guestPTE.fields.D = 1;
|
||||
guestPTbl[pti] = guestPTE;
|
||||
}
|
||||
#endif
|
||||
|
||||
*guest_ppi = A20PageIndex(vm, guestPTE.fields.base);
|
||||
}
|
||||
else {
|
||||
/* guest paging is off, linear address is physical address */
|
||||
guest_pdir_page_index = 0; /* keep compiler quiet */
|
||||
*guest_ppi = A20PageIndex(vm, guest_lpage_index);
|
||||
}
|
||||
if (*guest_ppi >= vm->pages.guest_n_pages)
|
||||
return(MapLinPPageOOB);
|
||||
|
||||
/* +++ mapping in guest pages, check static phy_attr bits first before */
|
||||
/* +++ allowing non-protected. */
|
||||
|
||||
|
||||
mapIntoMonitor:
|
||||
|
||||
/* At this point, we know that the guest's paging system
|
||||
* (if enabled) would allow for this access. Now we have to
|
||||
* see about mapping it into the monitor linear address space.
|
||||
*/
|
||||
pusage = getPageUsage(vm, *guest_ppi);
|
||||
|
||||
if (wasRemap > 1)
|
||||
monpanic(vm, "wasRemap>1\n");
|
||||
|
||||
/*
|
||||
* Check monitor PDE
|
||||
*/
|
||||
if (monPDE->fields.P == 0) {
|
||||
/* OK, Lazy PT map/allocate */
|
||||
if (vm->guest.addr.guest_cpu->cr0.fields.pg) {
|
||||
phy_page_usage_t *pde_pusage;
|
||||
|
||||
pde_pusage =
|
||||
getPageUsage(vm, A20PageIndex(vm, guestPDE.fields.base));
|
||||
if (pde_pusage->attr.raw & PageBadUsage4PTbl) {
|
||||
|
||||
#warning "PDE->PDir hack"
|
||||
/*monprint(vm, "PDE.base=0x%x CR3=0x%x\n",
|
||||
* A20PageIndex(vm, guestPDE.fields.base),
|
||||
* A20Addr(vm, vm->guest_cpu.cr3));
|
||||
*/
|
||||
return(MapLinEmulate);
|
||||
}
|
||||
|
||||
if (pde_pusage->attr.raw & PageUsagePTbl) {
|
||||
/* It is possible that multiple PDE entries will point to */
|
||||
/* the same Page Table. In this case, we need to search to */
|
||||
/* find which one the monitor already mapped in, and get */
|
||||
/* a pointer to the Page Table allocated by the monitor. */
|
||||
Bit32u guest_ptbl_index;
|
||||
unsigned i;
|
||||
|
||||
guestPDir = open_guest_phy_page(vm, guest_pdir_page_index,
|
||||
vm->guest.addr.tmp_phy_page0);
|
||||
guest_ptbl_index = A20PageIndex(vm, guestPDir[pdi].fields.base);
|
||||
monPTbl = (void *) 0;
|
||||
pt_index = 0; /* keep compiler quiet */
|
||||
for (i=0; i<1024; i++) {
|
||||
if (i==pdi) continue; /* skip current PDI */
|
||||
guestPDE = guestPDir[i];
|
||||
if ( guestPDE.fields.P &&
|
||||
(A20PageIndex(vm, guestPDE.fields.base)==guest_ptbl_index) ) {
|
||||
/* OK, guest has a PDE which matches. If it is mapped into */
|
||||
/* the monitor already, then we are done searching. */
|
||||
if (vm->guest.addr.page_dir[i].fields.P) {
|
||||
pt_index = getMonPTi(vm, i, 11);
|
||||
vm->guest.addr.page_tbl_laddr_map[pdi] = pt_index;
|
||||
monPTbl = &vm->guest.addr.page_tbl[pt_index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
close_guest_phy_page(vm, guest_pdir_page_index);
|
||||
if (i>=1024)
|
||||
monpanic(vm, "mapGuestLinAddr: PDE maps to existing PTbl.\n");
|
||||
}
|
||||
else {
|
||||
/* Allocate PT using paged scheme. */
|
||||
pt_index = allocatePT(vm, pdi);
|
||||
monPTbl = &vm->guest.addr.page_tbl[pt_index];
|
||||
mon_memzero(monPTbl, sizeof(*monPTbl));
|
||||
}
|
||||
|
||||
if (vm->guest.addr.guest_cpu->sreg[SRegCS].des.dpl==3) {
|
||||
/* For user code, we can use the guest US & RW values as-is, */
|
||||
/* since they are honored as such with either CR0.WP value. */
|
||||
us = guestPDE.fields.US;
|
||||
rw = guestPDE.fields.RW;
|
||||
}
|
||||
else { /* guest supervisor code */
|
||||
/* For supervisor code, access rules are different dependent on */
|
||||
/* the value of CR0.WP. */
|
||||
if (vm->guest.addr.guest_cpu->cr0.fields.wp==0) {
|
||||
/* If CR0.WP=0, then supervisor code can write to any page, */
|
||||
/* and permissions are effectively ignored. */
|
||||
us = 1;
|
||||
rw = 1;
|
||||
}
|
||||
else { /* CR0.WP==1 */
|
||||
/* If CR0.WP=0, then supervisor code can read from any page, */
|
||||
/* but write permission depends on the RW bit. */
|
||||
us = 1;
|
||||
rw = guestPDE.fields.RW;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Base/Avail=0/G=0/PS=0/D=d/A=a/PCD=0/PWT=0/US=us/RW=rw/P=1 */
|
||||
monPDE->raw =
|
||||
(vm->pages.page_tbl[pt_index] << 12) | (guestPDE.raw & 0x60) |
|
||||
(us<<2) | (rw<<1) | 1;
|
||||
if ( addPageAttributes(vm, A20PageIndex(vm, guestPDE.fields.base),
|
||||
PageUsagePTbl) ) {
|
||||
wasRemap++;
|
||||
goto mapIntoMonitor;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Allocate PT using non-paged scheme. */
|
||||
pt_index = allocatePT(vm, pdi);
|
||||
monPTbl = &vm->guest.addr.page_tbl[pt_index];
|
||||
mon_memzero(monPTbl, 4096);
|
||||
/* Base/Avail=0/G=0/PS=0/D=0/A=0/PCD=0/PWT=0/US=1/RW=1/P=1 */
|
||||
monPDE->raw =
|
||||
(vm->pages.page_tbl[pt_index] << 12) | 0x7;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* monPDE->P == 1 */
|
||||
|
||||
/* Make sure this laddr does not conflict with monitor space */
|
||||
/* This can only happen when monPDE.P==1, since the monitor */
|
||||
/* is always mapped in. */
|
||||
if ( (guest_laddr & 0xffc00000) == vm->mon_pde_mask )
|
||||
return(MapLinMonConflict);
|
||||
|
||||
pt_index = getMonPTi(vm, pdi, 12);
|
||||
monPTbl = &vm->guest.addr.page_tbl[pt_index];
|
||||
}
|
||||
|
||||
monPTE = &monPTbl->pte[pti];
|
||||
|
||||
/*
|
||||
* Check monitor PTE
|
||||
*/
|
||||
if (monPTE->fields.P == 0) {
|
||||
if (vm->guest.addr.guest_cpu->cr0.fields.pg) {
|
||||
if (vm->guest.addr.guest_cpu->sreg[SRegCS].des.dpl==3) {
|
||||
/* For user code, we can use the guest US & RW values as-is, */
|
||||
/* since they are honored as such with either CR0.WP value. */
|
||||
us = guestPTE.fields.US;
|
||||
rw = guestPTE.fields.RW;
|
||||
}
|
||||
else { /* guest supervisor code */
|
||||
/* For supervisor code, access rules are different dependent on */
|
||||
/* the value of CR0.WP. */
|
||||
if (vm->guest.addr.guest_cpu->cr0.fields.wp==0) {
|
||||
/* If CR0.WP=0, then supervisor code can write to any page, */
|
||||
/* and permissions are effectively ignored. */
|
||||
us = 1;
|
||||
rw = 1;
|
||||
}
|
||||
else { /* CR0.WP==1 */
|
||||
/* If CR0.WP=0, then supervisor code can read from any page, */
|
||||
/* but write permission depends on the RW bit. */
|
||||
us = 1;
|
||||
rw = guestPTE.fields.RW;
|
||||
}
|
||||
}
|
||||
if (pusage->attr.fields.access_perm==PagePermRO) {
|
||||
rw = 0;
|
||||
if (req_rw)
|
||||
return(MapLinEmulate);
|
||||
}
|
||||
else if (pusage->attr.fields.access_perm==PagePermNA)
|
||||
return(MapLinEmulate);
|
||||
|
||||
/* Base/Avail=0/G=0/PS=0/D=d/A=a/PCD=0/PWT=0/US=1/RW=rw/P=1 */
|
||||
monPTE->raw =
|
||||
(vm->pages.guest[*guest_ppi] << 12) | (guestPTE.raw & 0x60) |
|
||||
0x5 | (rw<<1);
|
||||
}
|
||||
else { /* CR0.PG==0 */
|
||||
rw = 1; /* Paging off is effectively RW */
|
||||
if (pusage->attr.fields.access_perm==PagePermRO) {
|
||||
rw = 0;
|
||||
if (req_rw)
|
||||
return(MapLinEmulate);
|
||||
}
|
||||
else if (pusage->attr.fields.access_perm==PagePermNA)
|
||||
return(MapLinEmulate);
|
||||
/* Base/Avail=0/G=0/PS=0/D=0/A=0/PCD=0/PWT=0/US=1/RW=rw/P=1 */
|
||||
monPTE->raw =
|
||||
(vm->pages.guest[*guest_ppi] << 12) | 0x5 | (rw<<1);
|
||||
}
|
||||
|
||||
/* Mark physical page as having an unvirtualized linear address
|
||||
* mapped to it.
|
||||
*/
|
||||
if (pusage->attr.fields.lmap_count == 0) {
|
||||
pusage->attr.fields.lmap_count = 1;
|
||||
pusage->attr.fields.laddr_backlink = guest_lpage_index;
|
||||
}
|
||||
else if (pusage->attr.fields.lmap_count == 1) {
|
||||
pusage->attr.fields.lmap_count = 2; /* max out count */
|
||||
/* Count maxed out, we only store laddr_backlink of 1st mapping. */
|
||||
}
|
||||
else {
|
||||
/* Count maxed out, we don't store any more info. */
|
||||
}
|
||||
|
||||
invlpg_mon_offset( Guest2Monitor(vm, guest_laddr) );
|
||||
return(MapLinOK);
|
||||
}
|
||||
else {
|
||||
/* PTE.P == 1 */
|
||||
return(MapLinAlreadyMapped);
|
||||
}
|
||||
|
||||
np_exception:
|
||||
access_exception:
|
||||
*error |= (req_us<<2) | (req_rw<<1);
|
||||
return(MapLinException);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
guestPageFault(vm_t *vm, guest_context_t *context, Bit32u cr2)
|
||||
{
|
||||
Bit32u guest_ppi, error, gerror;
|
||||
unsigned us, rw;
|
||||
|
||||
/* Make sure this laddr does not conflict with monitor space */
|
||||
if ( (cr2 & 0xffc00000) == vm->mon_pde_mask )
|
||||
monpanic(vm, "PageFault: guest access to monitor space\n");
|
||||
|
||||
error = context->error;
|
||||
if (error & 0x8) /* If RSVD bits used in PDir */
|
||||
monpanic(vm, "guestPageFault: RSVD\n");
|
||||
|
||||
us = vm->guest.addr.guest_cpu->sreg[SRegCS].des.dpl == 3;
|
||||
rw = (error >> 1) & 1;
|
||||
|
||||
/* +++ should base attr (currently 0) on whether this is */
|
||||
/* code or data??? only if siv==1 */
|
||||
switch (mapGuestLinAddr(vm, cr2, &guest_ppi, us, rw, 0, &gerror)) {
|
||||
case MapLinOK:
|
||||
return;
|
||||
case MapLinMonConflict:
|
||||
monpanic(vm, "guestPageFault: MapLinMonConflict:\n");
|
||||
case MapLinAlreadyMapped:
|
||||
monpanic(vm, "guestPageFault: MapLinAlreadyMapped:\n");
|
||||
/*emulate_instr(vm, context, 2);*/
|
||||
return;
|
||||
case MapLinPPageOOB:
|
||||
monpanic(vm, "guestPageFault: MapLinPPageOOB (0x%x):\n", cr2);
|
||||
case MapLinEmulate:
|
||||
monpanic(vm, "guestPageFault: MapLinEmulate:\n");
|
||||
/*emulate_instr(vm, context, 3);*/
|
||||
return;
|
||||
|
||||
case MapLinException:
|
||||
/*monpanic(vm, "guestPageFault: emulate_exception was here.\n");*/
|
||||
/*emulate_exception(vm, ExceptionPF, gerror);*/
|
||||
toHostGuestFault(vm, ExceptionPF);
|
||||
return;
|
||||
|
||||
default:
|
||||
monpanic(vm, "guestPageFault: MapLin: default case:\n");
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void
|
||||
sanity_check_pdir(vm_t *vm, unsigned id, Bit32u guest_laddr)
|
||||
{
|
||||
pageEntry_t *monPDE;
|
||||
Bit32u pdi;
|
||||
unsigned pt_index;
|
||||
|
||||
for (pdi=0; pdi<1024; pdi++) {
|
||||
monPDE = &vm->guest.addr.page_dir[pdi];
|
||||
if ( (pdi!=vm->mon_pdi) &&
|
||||
monPDE->fields.P ) {
|
||||
|
||||
pt_index = vm->guest.addr.page_tbl_laddr_map[pdi];
|
||||
if (pt_index == -1)
|
||||
monpanic(vm, "sanity_check_pdir: pt_index==-1\n");
|
||||
if (pt_index >= vm->pages.guest_n_pages)
|
||||
monpanic(vm, "sanity_check_pdir: pt_index OOB\n");
|
||||
if ( monPDE->fields.base != vm->pages.page_tbl[pt_index] ) {
|
||||
monprint(vm, "gaddr=0x%x\n", guest_laddr);
|
||||
monprint(vm, "pt_index=%u\n", pt_index);
|
||||
monprint(vm, "map[0x302]=%u\n",
|
||||
vm->guest.addr.page_tbl_laddr_map[0x302]);
|
||||
monpanic(vm, "sanity_check_pdir: id=%u "
|
||||
"pdi=0x%x\n", id, pdi);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
71
bochs/plex86/kernel/panic-mon.c
Normal file
71
bochs/plex86/kernel/panic-mon.c
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* plex86: run multiple x86 operating systems concurrently
|
||||
* Copyright (C) 1999-2003 Kevin P. Lawton
|
||||
*
|
||||
* panic-mon.c: Monitor panic facility.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "plex86.h"
|
||||
#define IN_MONITOR_SPACE
|
||||
#include "monitor.h"
|
||||
|
||||
extern int mon_vprint(vm_t *vm, char *fmt, va_list args);
|
||||
|
||||
|
||||
/*======================================== */
|
||||
/* Only to be used in monitor/guest space! */
|
||||
/*======================================== */
|
||||
|
||||
void
|
||||
monpanic(vm_t *vm, char *fmt, ...)
|
||||
{
|
||||
monprint(vm, "plex86 panic: ");
|
||||
if (fmt)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
mon_vprint(vm, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
loop:
|
||||
|
||||
CLI();
|
||||
|
||||
vm->mon_request = MonReqPanic;
|
||||
vm->guest.__mon2host();
|
||||
|
||||
/* mon2host() should never return in this case. In case it ever */
|
||||
/* does because our logic is broken, keep returning back to */
|
||||
/* the host so we at least don't hang the machine. */
|
||||
goto loop;
|
||||
}
|
||||
|
||||
void
|
||||
monpanic_nomess(vm_t *vm)
|
||||
{
|
||||
loop:
|
||||
CLI();
|
||||
vm->mon_request = MonReqPanic;
|
||||
vm->guest.__mon2host();
|
||||
|
||||
/* mon2host() should never return in this case. In case it ever */
|
||||
/* does because our logic is broken, keep returning back to */
|
||||
/* the host so we at least don't hang the machine. */
|
||||
goto loop;
|
||||
}
|
266
bochs/plex86/kernel/print-nexus.c
Normal file
266
bochs/plex86/kernel/print-nexus.c
Normal file
@ -0,0 +1,266 @@
|
||||
/*
|
||||
* plex86: run multiple x86 operating systems concurrently
|
||||
* Copyright (C) 1999-2003 Kevin P. Lawton
|
||||
*
|
||||
* print-nexus.c: Monitor debug print facility
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "plex86.h"
|
||||
#define IN_NEXUS_SPACE
|
||||
#include "monitor.h"
|
||||
|
||||
int mon_vprint(vm_t *vm, char *fmt, va_list args);
|
||||
|
||||
static unsigned int power_of_ten[] = {
|
||||
1,
|
||||
10,
|
||||
100,
|
||||
1000,
|
||||
10000,
|
||||
100000,
|
||||
1000000,
|
||||
10000000,
|
||||
100000000,
|
||||
1000000000,
|
||||
};
|
||||
|
||||
int
|
||||
monprint(vm_t *vm, char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int ret;
|
||||
|
||||
va_start(args, fmt);
|
||||
ret = mon_vprint(vm, fmt, args);
|
||||
va_end(args);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
int
|
||||
mon_vprint(vm_t *vm, char *fmt, va_list args)
|
||||
{
|
||||
unsigned offset, size;
|
||||
unsigned char *log_buff_p;
|
||||
int ret;
|
||||
|
||||
if (vm->log_buffer_info.locked)
|
||||
return 0;
|
||||
|
||||
vm->log_buffer_info.locked = 1;
|
||||
vm->log_buffer_info.event = 1;
|
||||
offset = vm->log_buffer_info.offset;
|
||||
|
||||
/* Sanity check */
|
||||
if (offset >= LOG_BUFF_SIZE) {
|
||||
vm->addr->log_buffer[0] = 0; /* Null terminate. */
|
||||
resetPrintBuf(vm);
|
||||
return(0);
|
||||
}
|
||||
|
||||
size = LOG_BUFF_SIZE - offset;
|
||||
log_buff_p = &vm->addr->log_buffer[offset];
|
||||
|
||||
ret = mon_vsnprintf(log_buff_p, size, fmt, args);
|
||||
|
||||
if (ret == -1) {
|
||||
/* Terminate current contents since new print request did not work. */
|
||||
*log_buff_p = 0;
|
||||
/* If we are in the monitor space, then we can request that the
|
||||
* current buffer contents be printed.
|
||||
*/
|
||||
resetPrintBuf(vm);
|
||||
if (vm->addr != &vm->host.addr) {
|
||||
sysFlushPrintBuf(vm);
|
||||
}
|
||||
|
||||
/* Print request did not fit. dump buffer contents and try again
|
||||
* using whole buffer.
|
||||
*/
|
||||
size = LOG_BUFF_SIZE;
|
||||
log_buff_p = &vm->addr->log_buffer[0];
|
||||
ret = mon_vsnprintf(log_buff_p, size, fmt, args);
|
||||
if (ret == -1) {
|
||||
/* We have serious problems. This print request will not even
|
||||
* fit in the whole buffer.
|
||||
*/
|
||||
vm->addr->log_buffer[0] = 0; /* Null terminate. */
|
||||
resetPrintBuf(vm);
|
||||
/* xxx Put error in buffer here. */
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
vm->log_buffer_info.offset += ret;
|
||||
vm->log_buffer_info.locked = 0;
|
||||
#if 0 /* Fri Dec 27 21:43:05 EST 2002 */
|
||||
if (vm->addr != &vm->host.addr) {
|
||||
resetPrintBuf(vm);
|
||||
sysFlushPrintBuf(vm);
|
||||
}
|
||||
#endif
|
||||
return(ret);
|
||||
}
|
||||
|
||||
void
|
||||
resetPrintBuf(vm_t *vm)
|
||||
{
|
||||
vm->log_buffer_info.event = 0;
|
||||
vm->log_buffer_info.locked = 0;
|
||||
vm->log_buffer_info.offset = 0;
|
||||
vm->log_buffer_info.error = 0;
|
||||
}
|
||||
|
||||
|
||||
/* For now, this is a simple vsnprintf() type of function. We need
|
||||
* to fill a little
|
||||
*/
|
||||
|
||||
int
|
||||
mon_vsnprintf(char *str, unsigned size, const char *fmt, va_list args)
|
||||
{
|
||||
int count = 0;
|
||||
unsigned format_width;
|
||||
unsigned char c;
|
||||
|
||||
while (*fmt) {
|
||||
switch (*fmt) {
|
||||
|
||||
case '%':
|
||||
format_width = 0;
|
||||
fmt++;
|
||||
c = *fmt++;
|
||||
/* Get optional field width */
|
||||
if ( (c>='0') && (c<='9') ) {
|
||||
do {
|
||||
format_width = (format_width * 10) + (c - '0');
|
||||
c = *fmt++;
|
||||
} while ( (c>='0') && (c<='9') );
|
||||
}
|
||||
/* %x: hexadecimal */
|
||||
if ( c == 'x' ) {
|
||||
unsigned int val, leadin;
|
||||
int j;
|
||||
unsigned nibble;
|
||||
|
||||
val = va_arg(args, unsigned int);
|
||||
leadin = 1;
|
||||
|
||||
for (j=7; j>=0; j--) {
|
||||
nibble = (val >> (4 * j)) & 0x0f;
|
||||
if (leadin && j && !format_width && !nibble)
|
||||
continue;
|
||||
if (leadin && j && format_width && ((j+1)>format_width) &&
|
||||
!nibble)
|
||||
continue;
|
||||
leadin = 0;
|
||||
if ( (count+2) >= size ) goto error;
|
||||
if (nibble <= 9)
|
||||
*str++ = nibble + '0';
|
||||
else
|
||||
*str++ = (nibble-10) + 'A';
|
||||
count++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* %c: character */
|
||||
if ( c == 'c' ) {
|
||||
unsigned char val;
|
||||
val = va_arg(args, unsigned);
|
||||
if ( (count+2) >= size ) goto error;
|
||||
*str++ = val;
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
|
||||
/* %s: string */
|
||||
if ( c == 's' ) {
|
||||
unsigned char *s;
|
||||
s = va_arg(args, unsigned char *);
|
||||
if ( (count+2) >= size ) goto error;
|
||||
count++;
|
||||
while (*s) {
|
||||
if ( (count+2) >= size ) goto error;
|
||||
*str++ = *s++; /* Copy char from string to output buffer. */
|
||||
count++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* %u: unsigned int */
|
||||
if ( c == 'u' ) {
|
||||
unsigned int val, leadin;
|
||||
int j;
|
||||
unsigned digit;
|
||||
|
||||
val = va_arg(args, unsigned int);
|
||||
leadin = 1;
|
||||
|
||||
for (j=9; j>=0; j--) {
|
||||
if (leadin && j && !format_width && (val < power_of_ten[j]))
|
||||
continue;
|
||||
if (leadin && j && format_width && ((j+1)>format_width) &&
|
||||
(val < power_of_ten[j]))
|
||||
continue;
|
||||
leadin = 0;
|
||||
digit = (val / power_of_ten[j]);
|
||||
if ( (count+2) >= size ) goto error;
|
||||
*str++ = digit + '0';
|
||||
count++;
|
||||
val -= (digit * power_of_ten[j]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* %b : binary (non-standard but useful) */
|
||||
if ( c == 'b' ) {
|
||||
unsigned int val, bit, leadin;
|
||||
int j;
|
||||
val = va_arg(args, unsigned int);
|
||||
leadin = 1;
|
||||
for (j=31; j>=0; j--) {
|
||||
bit = (val >> j) & 1;
|
||||
if (leadin && j && !format_width && !bit)
|
||||
continue;
|
||||
if (leadin && j && format_width && ((j+1)>format_width) && !bit)
|
||||
continue;
|
||||
leadin = 0;
|
||||
if ( (count+2) >= size ) goto error;
|
||||
*str++ = bit + '0';
|
||||
count++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Error, unrecognized format char */
|
||||
goto error;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* pass char through */
|
||||
if ( (count+2) >= size ) goto error;
|
||||
*str++ = *fmt++;
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*str = 0; /* Complete string with null char */
|
||||
return(count);
|
||||
|
||||
error:
|
||||
return(-1);
|
||||
}
|
55
bochs/plex86/kernel/util-nexus.c
Normal file
55
bochs/plex86/kernel/util-nexus.c
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* plex86: run multiple x86 operating systems concurrently
|
||||
* Copyright (C) 1999-2003 Kevin P. Lawton
|
||||
*
|
||||
* util-nexus.c: convenience routines which can be accessed from
|
||||
* either space.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "plex86.h"
|
||||
#define IN_NEXUS_SPACE
|
||||
#include "monitor.h"
|
||||
|
||||
|
||||
|
||||
void
|
||||
mon_memzero(void *ptr, int size)
|
||||
{
|
||||
char *p = ptr;
|
||||
while (size--)
|
||||
*p++ = 0;
|
||||
}
|
||||
|
||||
void
|
||||
mon_memcpy(void *dst, void *src, int size)
|
||||
{
|
||||
char *d = dst;
|
||||
char *s = src;
|
||||
while (size--)
|
||||
*d++ = *s++;
|
||||
}
|
||||
|
||||
void *
|
||||
mon_memset(void *dst, unsigned c, unsigned n)
|
||||
{
|
||||
unsigned char *d = dst;
|
||||
while (n--) {
|
||||
*d++ = c;
|
||||
}
|
||||
return(dst);
|
||||
}
|
55
bochs/plex86/misc/load_module.sh
Executable file
55
bochs/plex86/misc/load_module.sh
Executable file
@ -0,0 +1,55 @@
|
||||
#! /bin/bash
|
||||
#
|
||||
# A simple script to load up the kernel module and create the device nodes
|
||||
# for it.
|
||||
#
|
||||
# Note:
|
||||
# this must be run as root
|
||||
#
|
||||
|
||||
# Work out where the module is
|
||||
kmodule="`dirname $0`/../kernel/plex86.o"
|
||||
|
||||
# Check that root is executing us
|
||||
if [ "$EUID" != "0" ]; then
|
||||
echo "Sorry, you need to be root for this script to work."
|
||||
echo "use 'su -c $0' and enter the root password when prompted"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
# Check if the module exists
|
||||
if [ ! -f "$kmodule" ]; then
|
||||
echo "The kernel module ($kmodule) does not exist!"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
# Check if the module is already loaded
|
||||
if [ "x`grep plex86 /proc/devices`" != "x" ]; then
|
||||
echo "The kernel module is already loaded!"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
# Remove any stale device nodes
|
||||
# (extend for any minor devices created in the future)
|
||||
rm -f /dev/plex86
|
||||
|
||||
# Load up the module with insmod
|
||||
/sbin/insmod $kmodule
|
||||
|
||||
# Check if the module loaded
|
||||
major=`grep plex86 /proc/devices | awk '/plex86/ {print $1;}'`
|
||||
if [ "x$major" = "x" ]; then
|
||||
echo "The kernel module failed to load!"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
# Create the device node and set its permissions
|
||||
# (extend for any minor devices created in the future)
|
||||
if [ ! -c /dev/plex86 ]; then
|
||||
/bin/mknod /dev/plex86 c $major 0
|
||||
fi
|
||||
chmod a+rw /dev/plex86
|
||||
|
||||
# Job done - Give a little positive feedback
|
||||
echo "The kernel module is sucessfully installed."
|
||||
exit 0
|
17
bochs/plex86/misc/netbsd_post.sh
Executable file
17
bochs/plex86/misc/netbsd_post.sh
Executable file
@ -0,0 +1,17 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# This is the post-install script called by modload after it has loaded
|
||||
# the module.
|
||||
#
|
||||
# Sample modload commandline:
|
||||
#
|
||||
# modload -e plex86_lkmentry -p netbsd_post.sh plex86.o
|
||||
#
|
||||
if [ $# -ne 3 ]; then
|
||||
echo "$0 should only be called from modload(8) with 3 args"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -f /dev/plex86
|
||||
mknod /dev/plex86 c $3 0
|
||||
exit 0
|
34
bochs/plex86/misc/unload_module.sh
Executable file
34
bochs/plex86/misc/unload_module.sh
Executable file
@ -0,0 +1,34 @@
|
||||
#! /bin/bash
|
||||
#
|
||||
# A simple script to unload the kernel module and remove the old device nodes
|
||||
# for it.
|
||||
#
|
||||
# Note:
|
||||
# this must be run as root
|
||||
#
|
||||
|
||||
# Check that root is executing us
|
||||
if [ "$EUID" != "0" ]; then
|
||||
echo "Sorry, you need to be root for this script to work."
|
||||
echo "use 'su -c $0' and enter the root password when prompted"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
# Check if the module is already loaded
|
||||
if [ "x`grep plex86 /proc/devices`" != "x" ]; then
|
||||
/sbin/rmmod plex86
|
||||
|
||||
# Check that it really went (OK - I'm paranoid)
|
||||
if [ "x`grep plex86 /proc/devices`" != "x" ]; then
|
||||
echo "The kernel module failed to unload!"
|
||||
exit -1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Remove any stale device nodes
|
||||
# (extend for any minor devices created in the future)
|
||||
rm -f /dev/plex86
|
||||
|
||||
# Job done - Give a little positive feedback
|
||||
echo "The kernel module is no longer installed."
|
||||
exit 0
|
225
bochs/plex86/plex86.h
Normal file
225
bochs/plex86/plex86.h
Normal file
@ -0,0 +1,225 @@
|
||||
/************************************************************************
|
||||
* $Id: plex86.h,v 1.1 2003-01-01 17:32:04 kevinlawton Exp $
|
||||
************************************************************************
|
||||
*
|
||||
* plex86: run multiple x86 operating systems concurrently
|
||||
* Copyright (C) 1999-2003 Kevin P. Lawton
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __PLEX86_H__
|
||||
#define __PLEX86_H__
|
||||
|
||||
#include "config.h"
|
||||
#include "descriptor.h"
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
selector_t sel;
|
||||
descriptor_t des;
|
||||
unsigned valid;
|
||||
} guest_sreg_t;
|
||||
|
||||
#define SRegES 0
|
||||
#define SRegCS 1
|
||||
#define SRegSS 2
|
||||
#define SRegDS 3
|
||||
#define SRegFS 4
|
||||
#define SRegGS 5
|
||||
|
||||
|
||||
typedef union {
|
||||
Bit32u raw;
|
||||
struct {
|
||||
Bit32u pe:1;
|
||||
Bit32u mp:1;
|
||||
Bit32u em:1;
|
||||
Bit32u ts:1;
|
||||
Bit32u et:1;
|
||||
Bit32u ne:1;
|
||||
Bit32u R15_6:10;
|
||||
Bit32u wp:1;
|
||||
Bit32u R17:1;
|
||||
Bit32u am:1;
|
||||
Bit32u R28_19:10;
|
||||
Bit32u nw:1;
|
||||
Bit32u cd:1;
|
||||
Bit32u pg:1;
|
||||
} __attribute__ ((packed)) fields;
|
||||
} __attribute__ ((packed)) cr0_t;
|
||||
|
||||
typedef union {
|
||||
Bit32u raw;
|
||||
struct {
|
||||
Bit32u vme:1;
|
||||
Bit32u pvi:1;
|
||||
Bit32u tsd:1;
|
||||
Bit32u de:1;
|
||||
Bit32u pse:1;
|
||||
Bit32u pae:1;
|
||||
Bit32u mce:1;
|
||||
Bit32u pge:1;
|
||||
Bit32u pce:1;
|
||||
Bit32u reserved:23;
|
||||
} __attribute__ ((packed)) fields;
|
||||
} __attribute__ ((packed)) cr4_t;
|
||||
|
||||
typedef struct {
|
||||
Bit32u maxval; /* maximum val to pass to CPUID instruction */
|
||||
Bit8u vendorID[12+1]; /* 12 packed Vendor ID string bytes plus null */
|
||||
union {
|
||||
Bit32u raw;
|
||||
struct {
|
||||
Bit32u stepping:4;
|
||||
Bit32u model:4;
|
||||
Bit32u family:4;
|
||||
Bit32u procType:2;
|
||||
Bit32u Reserved31_14:18;
|
||||
} __attribute__ ((packed)) fields;
|
||||
} __attribute__ ((packed)) procSignature;
|
||||
union {
|
||||
Bit32u raw;
|
||||
struct {
|
||||
Bit32u fpu:1;
|
||||
Bit32u vme:1;
|
||||
Bit32u de:1;
|
||||
Bit32u pse:1;
|
||||
Bit32u tsc:1;
|
||||
Bit32u msr:1;
|
||||
Bit32u pae:1;
|
||||
Bit32u mce:1;
|
||||
Bit32u cx8:1;
|
||||
Bit32u apic:1;
|
||||
Bit32u Reserved10:1;
|
||||
Bit32u sep:1;
|
||||
Bit32u mtrr:1;
|
||||
Bit32u pge:1;
|
||||
Bit32u mca:1;
|
||||
Bit32u cmov:1;
|
||||
Bit32u pat:1;
|
||||
Bit32u pse36:1;
|
||||
Bit32u Reserved22_18:5;
|
||||
Bit32u mmx:1;
|
||||
Bit32u fxsr:1;
|
||||
Bit32u Reserved31_25:7;
|
||||
} __attribute__ ((packed)) fields;
|
||||
} __attribute__ ((packed)) featureFlags;
|
||||
} cpuid_info_t;
|
||||
|
||||
typedef struct {
|
||||
Bit32u edi;
|
||||
Bit32u esi;
|
||||
Bit32u ebp;
|
||||
Bit32u esp;
|
||||
Bit32u ebx;
|
||||
Bit32u edx;
|
||||
Bit32u ecx;
|
||||
Bit32u eax;
|
||||
|
||||
Bit32u eflags;
|
||||
Bit32u eip;
|
||||
guest_sreg_t sreg[6];
|
||||
guest_sreg_t ldtr;
|
||||
guest_sreg_t tr;
|
||||
gdt_info_t gdtr;
|
||||
gdt_info_t idtr;
|
||||
Bit32u dr0, dr1, dr2, dr3, dr6, dr7;
|
||||
Bit32u tr3, tr4, tr5, tr6, tr7;
|
||||
cr0_t cr0;
|
||||
Bit32u cr1, cr2, cr3;
|
||||
cr4_t cr4;
|
||||
unsigned a20Enable;
|
||||
} guest_cpu_t;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* ioctl() names.
|
||||
*/
|
||||
|
||||
#if defined(__linux__) || defined(__NetBSD__) || defined(__FreeBSD__)
|
||||
#ifdef __linux__
|
||||
#include <asm/ioctl.h>
|
||||
#else
|
||||
#include <sys/ioccom.h>
|
||||
#endif
|
||||
#define PLEX86_ALLOCVPHYS _IO('k', 2)
|
||||
#define PLEX86_RESET _IO('k', 3)
|
||||
#define PLEX86_TEARDOWN _IO('k', 4)
|
||||
#define PLEX86_EXECUTE _IO('k', 5)
|
||||
#define PLEX86_CPUID _IO('k', 6)
|
||||
#else
|
||||
#define PLEX86_ALLOCVPHYS 0x6b02
|
||||
#define PLEX86_RESET 0x6b03
|
||||
#define PLEX86_TEARDOWN 0x6b04
|
||||
#define PLEX86_EXECUTE 0x6b05
|
||||
#define PLEX86_CPUID 0x6b06
|
||||
#endif
|
||||
|
||||
|
||||
/* Requests that the VM monitor makes to host-kernel space or
|
||||
* host-user space.
|
||||
*/
|
||||
#define MonReqNone 0
|
||||
#define MonReqFlushPrintBuf 1
|
||||
#define MonReqRedirect 4 /* Only to host-kernel. */
|
||||
#define MonReqRemapMonitor 5
|
||||
#define MonReqGuestFault 6
|
||||
#define MonReqPanic 8
|
||||
|
||||
#define VMStateFDOpened 0x001
|
||||
#define VMStateMemAllocated 0x002
|
||||
#define VMStateGuestCPUID 0x004
|
||||
#define VMStateMMapPhyMem 0x008
|
||||
#define VMStateMMapPrintBuffer 0x010
|
||||
#define VMStateMMapGuestCPU 0x020
|
||||
#define VMStateInitMonitor 0x040
|
||||
#define VMStateMapMonitor 0x080
|
||||
#define VMStatePanic 0x100
|
||||
|
||||
#define VMStateReady (VMStateFDOpened | VMStateMemAllocated | \
|
||||
VMStateGuestCPUID | VMStateMMapPhyMem | VMStateMMapPrintBuffer | \
|
||||
VMStateMMapGuestCPU | VMStateInitMonitor | VMStateMapMonitor )
|
||||
#define VMStateMMapAll \
|
||||
(VMStateMMapPhyMem | VMStateMMapPrintBuffer | VMStateMMapGuestCPU)
|
||||
|
||||
typedef struct {
|
||||
unsigned state;
|
||||
unsigned request;
|
||||
unsigned guestFaultNo;
|
||||
} plex86MonitorState_t;
|
||||
|
||||
typedef struct {
|
||||
#define Plex86ExecuteMethodNative 10
|
||||
#define Plex86ExecuteMethodBreakpoint 11
|
||||
unsigned executeMethod;
|
||||
|
||||
/* User space --> Monitor space. */
|
||||
Bit64u cyclesRequested;
|
||||
unsigned instructionsRequested;
|
||||
|
||||
/* Monitor space --> User space. */
|
||||
Bit64u cyclesExecuted;
|
||||
unsigned instructionsExecuted;
|
||||
plex86MonitorState_t monitorState;
|
||||
} plex86IoctlExecute_t;
|
||||
|
||||
#endif /* #ifndef __PLEX86_H__ */
|
Loading…
Reference in New Issue
Block a user