Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4690764bba | ||
|
|
3c1cf9fa86 | ||
|
|
1f47a9223e | ||
|
|
33e3963e1b | ||
|
|
cd4c3e888a | ||
|
|
7916e2245d | ||
|
|
abd0aaff03 | ||
|
|
c39d5b78f6 | ||
|
|
4d40895f2c | ||
|
|
e477b8b81b | ||
|
|
b118d61e55 | ||
|
|
2f62b397b5 | ||
|
|
907a5b2690 | ||
|
|
0849bf0821 | ||
|
|
305034817d | ||
|
|
ec410fc9ce | ||
|
|
68a7931591 | ||
|
|
c9159e5321 | ||
|
|
8c9b861e74 | ||
|
|
5797fa5d7e | ||
|
|
8ef9a8ece3 | ||
|
|
fc01f7e7f9 | ||
|
|
3b0dca51b0 | ||
|
|
da415d54bf | ||
|
|
b4608c0455 | ||
|
|
d5a0b50c6f | ||
|
|
87858c89ca | ||
|
|
a6f816d697 | ||
|
|
0ad041d476 | ||
|
|
1eb20527c8 | ||
|
|
e3e86d56c4 | ||
|
|
1df912cf9e | ||
|
|
4351832355 | ||
|
|
59faf6d6a6 | ||
|
|
725af7d460 | ||
|
|
a363e34cc5 | ||
|
|
ea041c0e33 | ||
|
|
83479e770d | ||
|
|
e2f2289897 | ||
|
|
844c72eccc | ||
|
|
6b1534cc67 | ||
|
|
e8cd23de30 | ||
|
|
7c2d6a781c | ||
|
|
f1510b2cc3 | ||
|
|
357a94326c | ||
|
|
0824d6fc67 | ||
|
|
6c0372d30b | ||
|
|
92ccca6aa8 | ||
|
|
dd3587f38e | ||
|
|
7d83131cc5 | ||
|
|
66e85a21c7 | ||
|
|
90a9fdae1f | ||
|
|
3fb2ded1d5 | ||
|
|
f76af4b3f3 | ||
|
|
717fc2ad8d | ||
|
|
c05bab779e | ||
|
|
a52c757c9f | ||
|
|
970a87a6bb | ||
|
|
d8bc1fd0ae | ||
|
|
7501267e22 | ||
|
|
13b55754af | ||
|
|
972ddf7840 | ||
|
|
322d0c6657 | ||
|
|
2054396a04 | ||
|
|
039de852ec | ||
|
|
144c345daf | ||
|
|
de83cd02e0 | ||
|
|
6380ab5e26 | ||
|
|
b346ff468e | ||
|
|
5a9fdfec7e | ||
|
|
d19893dab5 | ||
|
|
2521d69883 | ||
|
|
2ab83ea784 | ||
|
|
2437490100 | ||
|
|
e4533c7a8c | ||
|
|
1e5ffbedde | ||
|
|
79638566e5 | ||
|
|
03daf0e361 | ||
|
|
d219f7e7ed | ||
|
|
95cbfc643d | ||
|
|
5898e81684 | ||
|
|
394411ac74 | ||
|
|
ea76864009 | ||
|
|
43ce4dfe9e | ||
|
|
ebc06f87ca | ||
|
|
5bbe92995c | ||
|
|
411bffc41c | ||
|
|
ff1f20a3ee | ||
|
|
9c5d1246c7 | ||
|
|
8dd7cb0621 | ||
|
|
d30329297b | ||
|
|
a95c67907c | ||
|
|
0f533160c7 | ||
|
|
e163bca720 | ||
|
|
8c6939c0b0 | ||
|
|
2d0e9143e2 | ||
|
|
87f4827e1d | ||
|
|
4a585ccb2f | ||
|
|
aa0aa4fa31 | ||
|
|
84fa15d854 | ||
|
|
4add45b4f6 | ||
|
|
4f101ad7ff | ||
|
|
c1db2eb8c3 | ||
|
|
82d19dafe4 | ||
|
|
5286db75a8 | ||
|
|
917f95fd4d | ||
|
|
fe31975692 | ||
|
|
95f7652d65 | ||
|
|
3ec9c4fcc6 | ||
|
|
2f87c60799 | ||
|
|
03bfca946a | ||
|
|
ed2dcdf68e | ||
|
|
4304763ba2 | ||
|
|
c1e42a1397 | ||
|
|
d0a1ffc957 | ||
|
|
df0f11a03b | ||
|
|
2d92f0b8f0 | ||
|
|
aad13cd131 | ||
|
|
a513fe19ac | ||
|
|
f4beb510a4 | ||
|
|
d731dae8e3 | ||
|
|
c9087c2a60 | ||
|
|
14ae3ba7f9 | ||
|
|
5a91de8c90 | ||
|
|
e3b32540df | ||
|
|
a37904dd86 | ||
|
|
cf25629d1e | ||
|
|
0ca790b92e | ||
|
|
d1fe2b2459 | ||
|
|
d4e8164f7e | ||
|
|
08351fb37a | ||
|
|
85e53d4108 | ||
|
|
aa05ae6fec | ||
|
|
1565b7bcd7 | ||
|
|
b409186b8d | ||
|
|
418a97afa1 | ||
|
|
5132455efe | ||
|
|
c0ad5542a8 | ||
|
|
3a27ad0b57 | ||
|
|
2b413144dc | ||
|
|
3ebcc707d2 | ||
|
|
7775e9ecc2 | ||
|
|
03d843ddf2 | ||
|
|
eb51d102bb | ||
|
|
25eb44841e | ||
|
|
b333af0666 | ||
|
|
76c8b7710b | ||
|
|
70e198602b | ||
|
|
206f0fa759 | ||
|
|
fd6ce8f660 | ||
|
|
727d01d4f6 | ||
|
|
ae22853141 | ||
|
|
d418c81eff | ||
|
|
2a29ca73c9 | ||
|
|
54936004fd | ||
|
|
74c95119f2 | ||
|
|
366c1b8bfa | ||
|
|
a993ba85cf | ||
|
|
226c91327d | ||
|
|
b8bf3e3aac | ||
|
|
288426fe3c | ||
|
|
72cc388104 | ||
|
|
378180d8dc | ||
|
|
78c34e98cd | ||
|
|
2792c4f2af | ||
|
|
447db2139a | ||
|
|
564c8f9978 | ||
|
|
c50c0c3fbf | ||
|
|
cabb4d616d | ||
|
|
631271d716 | ||
|
|
9d27abd94f | ||
|
|
148dfc2a8b | ||
|
|
3acace1333 | ||
|
|
0221cfcd71 | ||
|
|
f351077efb | ||
|
|
e84be9dbca | ||
|
|
46ddf5511d | ||
|
|
89e957e7a2 | ||
|
|
982b431579 | ||
|
|
bf7c65bdf4 | ||
|
|
8e5a0667f8 | ||
|
|
19b84f3c35 | ||
|
|
08fc60898b | ||
|
|
082391983e | ||
|
|
504e56ebdc | ||
|
|
455b761956 | ||
|
|
b56dad1c7b | ||
|
|
9ba5695ce5 | ||
|
|
66099dd9af | ||
|
|
b689bc57d6 | ||
|
|
a69d83b60b | ||
|
|
86840ae241 | ||
|
|
3c51961e0e | ||
|
|
d014c98c8d | ||
|
|
a98fd896cd | ||
|
|
d6cdca958e | ||
|
|
efdea7bf19 | ||
|
|
0d3301964d | ||
|
|
fe1e3ce3e9 | ||
|
|
bb326a3749 | ||
|
|
27725c1d74 | ||
|
|
e026db5893 | ||
|
|
43f04c233c | ||
|
|
a8baa8c555 | ||
|
|
728584be27 | ||
|
|
b9adb4a6bc | ||
|
|
ae48a07313 | ||
|
|
956034d7e5 | ||
|
|
6cd9f35b9b | ||
|
|
689f936f7e | ||
|
|
6977fbfd8b | ||
|
|
77e4672d8d | ||
|
|
d34720fd7d | ||
|
|
d9c4d1cc1a | ||
|
|
f644caa51a | ||
|
|
1eb87257da | ||
|
|
32ce63371a | ||
|
|
ec86b0fb3a | ||
|
|
1d346ae63a | ||
|
|
74cd30b811 | ||
|
|
7fb9a24e39 | ||
|
|
afeb6ee377 | ||
|
|
f29042b531 | ||
|
|
09bfb054fb | ||
|
|
2677e107e6 | ||
|
|
66cd58461d | ||
|
|
bb0ebb1f2d |
No files matched your search
+111
-111
@@ -1,36 +1,14 @@
|
||||
------------------------------------------------------------------------------
|
||||
NOTE:
|
||||
Some code of the Twin package was modified for DOSEMU by the DOSEMU-team.
|
||||
The original is 'Copyright 1997 Willows Software, Inc.' and generously
|
||||
was put under the GNU Library General Public License.
|
||||
( for more information see http://www.willows.com/ )
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
We make use of section 3 of the GNU Library General Public License
|
||||
('...opt to apply the terms of the ordinary GNU General Public License...'),
|
||||
because the resulting product is an integrated part of DOSEMU and
|
||||
can not be considered to be a 'library' in the terms of Library License.
|
||||
|
||||
Therefore, the below GNU LIBRARY GENERAL PUBLIC LICENSE applies only to the
|
||||
_unchanged_ Twin package from Willows. For the DOSEMU-changed parts the normal
|
||||
GNU GENERAL PUBLIC LICENSE applies. This GPL (file COPYING) can be found in
|
||||
the root directory of the DOSEMU distribution.
|
||||
|
||||
The act of transformation to GPL was indicated to the maintainer of the Twin
|
||||
package (Rob Penrose <rob@Canopy.Com>) and he acknowledge agreement.
|
||||
|
||||
Nov. 1 1997, The DOSEMU team.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
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 library GPL. It is
|
||||
numbered 2 because it goes with version 2 of the ordinary GPL.]
|
||||
[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
|
||||
|
||||
@@ -39,97 +17,109 @@ 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 Library General Public License, applies to some
|
||||
specially designated Free Software Foundation software, and to any
|
||||
other libraries whose authors decide to use it. You can use it for
|
||||
your libraries, too.
|
||||
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, 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 or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
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
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if
|
||||
you distribute copies of the library, or if you modify it.
|
||||
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 a program 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
|
||||
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.
|
||||
|
||||
Our method of protecting your rights has two steps: (1) copyright
|
||||
the library, and (2) offer you this license which gives you legal
|
||||
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.
|
||||
|
||||
Also, for each distributor's protection, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
library. If the library is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original
|
||||
version, so that any problems introduced by others will not reflect on
|
||||
the original authors' reputations.
|
||||
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, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that companies distributing free
|
||||
software will individually obtain patent licenses, thus in effect
|
||||
transforming the program into proprietary software. To prevent this,
|
||||
we have made it clear that any patent must be licensed for everyone's
|
||||
free use or not licensed at all.
|
||||
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, which was designed for utility programs. This
|
||||
license, the GNU Library General Public License, applies to certain
|
||||
designated libraries. This license is quite different from the ordinary
|
||||
one; be sure to read it in full, and don't assume that anything in it is
|
||||
the same as in the ordinary 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.
|
||||
|
||||
The reason we have a separate public license for some libraries is that
|
||||
they blur the distinction we usually make between modifying or adding to a
|
||||
program and simply using it. Linking a program with a library, without
|
||||
changing the library, is in some sense simply using the library, and is
|
||||
analogous to running a utility program or application program. However, in
|
||||
a textual and legal sense, the linked executable is a combined work, a
|
||||
derivative of the original library, and the ordinary General Public License
|
||||
treats it as such.
|
||||
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.
|
||||
|
||||
Because of this blurred distinction, using the ordinary General
|
||||
Public License for libraries did not effectively promote software
|
||||
sharing, because most developers did not use the libraries. We
|
||||
concluded that weaker conditions might promote sharing better.
|
||||
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.
|
||||
|
||||
However, unrestricted linking of non-free programs would deprive the
|
||||
users of those programs of all benefit from the free status of the
|
||||
libraries themselves. This Library General Public License is intended to
|
||||
permit developers of non-free programs to use free libraries, while
|
||||
preserving your freedom as a user of such programs to change the free
|
||||
libraries that are incorporated in them. (We have not seen how to achieve
|
||||
this as regards changes in header files, but we have achieved it as regards
|
||||
changes in the actual functions of the Library.) The hope is that this
|
||||
will lead to faster development of free libraries.
|
||||
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, while the latter only
|
||||
works together with the library.
|
||||
|
||||
Note that it is possible for a library to be covered by the ordinary
|
||||
General Public License rather than by this special one.
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library which
|
||||
contains a notice placed by the copyright holder or other authorized
|
||||
party saying it may be distributed under the terms of this Library
|
||||
General Public License (also called "this License"). Each licensee is
|
||||
addressed as "you".
|
||||
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
|
||||
@@ -278,7 +268,7 @@ 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 compile or
|
||||
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
|
||||
@@ -305,23 +295,31 @@ of these things:
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Accompany the work with a written offer, valid for at
|
||||
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.
|
||||
|
||||
c) If distribution of the work is made by offering access to copy
|
||||
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.
|
||||
|
||||
d) Verify that the user has already received a copy of these
|
||||
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 source code distributed need not include anything that is normally
|
||||
distributed (in either source or binary form) with the major
|
||||
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.
|
||||
@@ -370,7 +368,7 @@ 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 to
|
||||
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
|
||||
@@ -413,7 +411,7 @@ 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 Library General Public License from time to time.
|
||||
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.
|
||||
|
||||
@@ -459,7 +457,7 @@ DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Libraries
|
||||
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
|
||||
@@ -476,18 +474,18 @@ convey the exclusion of warranty; and each file should have at least the
|
||||
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 Library General Public
|
||||
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
|
||||
Library General Public License for more details.
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
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.
|
||||
|
||||
@@ -502,3 +500,5 @@ necessary. Here is a sample; alter the names:
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
|
||||
@@ -1,3 +1,68 @@
|
||||
version 0.4.2:
|
||||
|
||||
- many exception handling fixes (can compile a Linux kernel inside vl)
|
||||
- IDE emulation support
|
||||
- initial GDB stub support
|
||||
- deferred update support for disk images (Rusty Russell)
|
||||
- accept user mode Linux Copy On Write disk images
|
||||
- SMP kernels can at least be booted
|
||||
|
||||
version 0.4.1:
|
||||
|
||||
- more accurate timer support in vl.
|
||||
- more reliable NE2000 probe in vl.
|
||||
- added 2.5.66 kernel in vl-test.
|
||||
- added VLTMPDIR environment variable in vl.
|
||||
|
||||
version 0.4:
|
||||
|
||||
- initial support for ring 0 x86 processor emulation
|
||||
- fixed signal handling for correct dosemu DPMI emulation
|
||||
- fast x86 MMU emulation with mmap()
|
||||
- fixed popl (%esp) case
|
||||
- Linux kernel can be executed by QEMU with the 'vl' command.
|
||||
|
||||
version 0.3:
|
||||
|
||||
- initial support for ARM emulation
|
||||
- added fnsave, frstor, fnstenv, fldenv FPU instructions
|
||||
- added FPU register save in signal emulation
|
||||
- initial ARM port
|
||||
- Sparc and Alpha ports work on the regression test
|
||||
- generic ioctl number conversion
|
||||
- fixed ioctl type conversion
|
||||
|
||||
version 0.2:
|
||||
|
||||
- PowerPC disassembly and ELF symbols output (Rusty Russell)
|
||||
- flock support (Rusty Russell)
|
||||
- ugetrlimit support (Rusty Russell)
|
||||
- fstat64 fix (Rusty Russell)
|
||||
- initial Alpha port (Falk Hueffner)
|
||||
- initial IA64 port (Matt Wilson)
|
||||
- initial Sparc and Sparc64 port (David S. Miller)
|
||||
- added HLT instruction
|
||||
- LRET instruction fix.
|
||||
- added GPF generation for I/Os.
|
||||
- added INT3 and TF flag support.
|
||||
- SHL instruction C flag fix.
|
||||
- mmap emulation for host page size > 4KB
|
||||
- self-modifying code support
|
||||
- better VM86 support (dosemu works on non trivial programs)
|
||||
- precise exception support (EIP is computed correctly in most cases)
|
||||
- more precise LDT/GDT/IDT emulation
|
||||
- faster segment load in vm86 mode
|
||||
- direct chaining of basic blocks (faster emulation)
|
||||
|
||||
version 0.1.6:
|
||||
|
||||
- automatic library search system. QEMU can now work with unpatched
|
||||
ELF dynamic loader and libc (Rusty Russell).
|
||||
- ISO C warning fixes (Alistair Strachan)
|
||||
- first self-virtualizable version (works only as long as the
|
||||
translation cache is not flushed)
|
||||
- RH9 fixes
|
||||
|
||||
version 0.1.5:
|
||||
|
||||
- ppc64 support + personality() patch (Rusty Russell)
|
||||
|
||||
@@ -4,20 +4,33 @@ CFLAGS=-Wall -O2 -g
|
||||
LDFLAGS=-g
|
||||
LIBS=
|
||||
DEFINES=-DHAVE_BYTESWAP_H
|
||||
HELPER_CFLAGS=$(CFLAGS)
|
||||
PROGS=qemu
|
||||
|
||||
ifdef CONFIG_STATIC
|
||||
LDFLAGS+=-static
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),i386)
|
||||
CFLAGS+=-fomit-frame-pointer
|
||||
OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2
|
||||
ifeq ($(GCC_MAJOR),3)
|
||||
ifeq ($(HAVE_GCC3_OPTIONS),yes)
|
||||
OP_CFLAGS+= -falign-functions=0
|
||||
else
|
||||
OP_CFLAGS+= -malign-functions=0
|
||||
endif
|
||||
ifdef TARGET_GPROF
|
||||
LDFLAGS+=-Wl,-T,i386.ld
|
||||
else
|
||||
# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object
|
||||
# that the kernel ELF loader considers as an executable. I think this
|
||||
# is the simplest way to make it self virtualizable!
|
||||
LDFLAGS+=-Wl,-shared
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
PROGS+=vl vlmkcow
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ppc)
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
@@ -29,7 +42,39 @@ OP_CFLAGS=$(CFLAGS)
|
||||
LDFLAGS+=-Wl,-T,s390.ld
|
||||
endif
|
||||
|
||||
ifeq ($(GCC_MAJOR),3)
|
||||
ifeq ($(ARCH),sparc)
|
||||
CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
|
||||
LDFLAGS+=-m32
|
||||
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
|
||||
HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
|
||||
LDFLAGS+=-Wl,-T,sparc.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),sparc64)
|
||||
CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
|
||||
LDFLAGS+=-m64
|
||||
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),alpha)
|
||||
# -msmall-data is not used because we want two-instruction relocations
|
||||
# for the constant constructions
|
||||
OP_CFLAGS=-Wall -O2 -g
|
||||
# Ensure there's only a single GP
|
||||
CFLAGS += -msmall-data
|
||||
LDFLAGS+=-Wl,-T,alpha.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ia64)
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
OP_CFLAGS=$(CFLAGS) -mno-sched-prolog
|
||||
LDFLAGS+=-Wl,-T,arm.ld
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_GCC3_OPTIONS),yes)
|
||||
# very important to generate a return at the end of every operation
|
||||
OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
|
||||
endif
|
||||
@@ -45,18 +90,61 @@ LDFLAGS+=-p
|
||||
main.o: CFLAGS+=-p
|
||||
endif
|
||||
|
||||
OBJS= elfload.o main.o syscall.o signal.o
|
||||
OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
OBJS+= vm86.o
|
||||
endif
|
||||
SRCS:= $(OBJS:.o=.c)
|
||||
OBJS+= libqemu.a
|
||||
|
||||
LIBOBJS+=thunk.o translate-i386.o op-i386.o exec-i386.o
|
||||
# NOTE: the disassembler code is only needed for debugging
|
||||
LIBOBJS+=i386-dis.o dis-buf.o
|
||||
# cpu emulator library
|
||||
LIBOBJS=thunk.o exec.o translate.o cpu-exec.o gdbstub.o
|
||||
|
||||
all: qemu qemu-doc.html
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
LIBOBJS+=translate-i386.o op-i386.o helper-i386.o
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), arm)
|
||||
LIBOBJS+=translate-arm.o op-arm.o
|
||||
endif
|
||||
|
||||
# NOTE: the disassembler code is only needed for debugging
|
||||
LIBOBJS+=disas.o
|
||||
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
|
||||
LIBOBJS+=i386-dis.o
|
||||
endif
|
||||
ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha)
|
||||
LIBOBJS+=alpha-dis.o
|
||||
endif
|
||||
ifeq ($(findstring ppc, $(TARGET_ARCH) $(ARCH)),ppc)
|
||||
LIBOBJS+=ppc-dis.o
|
||||
endif
|
||||
ifeq ($(findstring sparc, $(TARGET_ARCH) $(ARCH)),sparc)
|
||||
LIBOBJS+=sparc-dis.o
|
||||
endif
|
||||
ifeq ($(findstring arm, $(TARGET_ARCH) $(ARCH)),arm)
|
||||
LIBOBJS+=arm-dis.o
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ia64)
|
||||
OBJS += ia64-syscall.o
|
||||
endif
|
||||
|
||||
all: $(PROGS) qemu-doc.html
|
||||
|
||||
qemu: $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
ifeq ($(ARCH),alpha)
|
||||
# Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of
|
||||
# the address space (31 bit so sign extending doesn't matter)
|
||||
echo -ne '\001\000\000\000' | dd of=qemu bs=1 seek=48 count=4 conv=notrunc
|
||||
endif
|
||||
|
||||
# must use static linking to avoid leaving stuff in virtual address space
|
||||
vl: vl.o block.o libqemu.a
|
||||
$(CC) -static -Wl,-T,i386-vl.ld -o $@ $^ $(LIBS)
|
||||
|
||||
vlmkcow: vlmkcow.o
|
||||
$(CC) -o $@ $^ $(LIBS)
|
||||
|
||||
depend: $(SRCS)
|
||||
$(CC) -MM $(CFLAGS) $^ 1>.depend
|
||||
@@ -70,14 +158,29 @@ libqemu.a: $(LIBOBJS)
|
||||
dyngen: dyngen.c
|
||||
$(HOST_CC) -O2 -Wall -g $< -o $@
|
||||
|
||||
translate-i386.o: translate-i386.c op-i386.h cpu-i386.h
|
||||
translate-$(TARGET_ARCH).o: translate-$(TARGET_ARCH).c gen-op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h
|
||||
|
||||
op-i386.h: op-i386.o dyngen
|
||||
translate.o: translate.c op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h
|
||||
|
||||
op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen
|
||||
./dyngen -o $@ $<
|
||||
|
||||
op-i386.o: op-i386.c opreg_template.h ops_template.h
|
||||
opc-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen
|
||||
./dyngen -c -o $@ $<
|
||||
|
||||
gen-op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen
|
||||
./dyngen -g -o $@ $<
|
||||
|
||||
op-$(TARGET_ARCH).o: op-$(TARGET_ARCH).c
|
||||
$(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
helper-$(TARGET_ARCH).o: helper-$(TARGET_ARCH).c
|
||||
$(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
op-i386.o: op-i386.c opreg_template.h ops_template.h ops_template_mem.h
|
||||
|
||||
op-arm.o: op-arm.c op-arm-template.h
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
@@ -88,15 +191,16 @@ clean:
|
||||
distclean: clean
|
||||
rm -f config.mak config.h
|
||||
|
||||
install: qemu
|
||||
install -m 755 -s qemu $(prefix)/bin
|
||||
install: $(PROGS)
|
||||
mkdir -p $(prefix)/bin
|
||||
install -m 755 -s $(PROGS) $(prefix)/bin
|
||||
|
||||
# various test targets
|
||||
test speed: qemu
|
||||
make -C tests $@
|
||||
|
||||
TAGS:
|
||||
etags *.[ch] i386/*.[ch]
|
||||
etags *.[ch] tests/*.[ch]
|
||||
|
||||
# documentation
|
||||
qemu-doc.html: qemu-doc.texi
|
||||
@@ -104,19 +208,28 @@ qemu-doc.html: qemu-doc.texi
|
||||
|
||||
FILES= \
|
||||
README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \
|
||||
dyngen.c ioctls.h ops_template.h op_string.h syscall_types.h\
|
||||
Makefile elf.h linux_bin.h segment.h thunk.c\
|
||||
elfload.c main.c signal.c thunk.h\
|
||||
cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\
|
||||
dis-asm.h gen-i386.h syscall.c\
|
||||
dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\
|
||||
ppc.ld s390.ld exec-i386.h exec-i386.c configure \
|
||||
tests/Makefile\
|
||||
tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\
|
||||
tests/test-i386-muldiv.h tests/test-i386-code16.S\
|
||||
tests/hello.c tests/hello tests/sha1.c \
|
||||
configure \
|
||||
dyngen.c dyngen.h dyngen-exec.h ioctls.h syscall_types.h \
|
||||
Makefile elf.h elfload.c main.c signal.c qemu.h \
|
||||
syscall.c syscall_defs.h vm86.c path.c mmap.c \
|
||||
i386.ld ppc.ld alpha.ld s390.ld sparc.ld arm.ld\
|
||||
vl.c i386-vl.ld vl.h block.c vlmkcow.c\
|
||||
thunk.c cpu-exec.c translate.c cpu-all.h thunk.h exec.h\
|
||||
exec.c cpu-exec.c gdbstub.c\
|
||||
cpu-i386.h op-i386.c helper-i386.c syscall-i386.h translate-i386.c \
|
||||
exec-i386.h ops_template.h ops_template_mem.h op_string.h opreg_template.h \
|
||||
cpu-arm.h syscall-arm.h exec-arm.h op-arm.c translate-arm.c op-arm-template.h \
|
||||
dis-asm.h disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c sparc-dis.c \
|
||||
arm-dis.c \
|
||||
tests/Makefile \
|
||||
tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h \
|
||||
tests/test-i386-muldiv.h tests/test-i386-code16.S tests/test-i386-vm86.S \
|
||||
tests/hello-i386.c tests/hello-i386 \
|
||||
tests/hello-arm.c tests/hello-arm \
|
||||
tests/sha1.c \
|
||||
tests/testsig.c tests/testclone.c tests/testthread.c \
|
||||
tests/runcom.c tests/pi_10.com \
|
||||
tests/test_path.c \
|
||||
qemu-doc.texi qemu-doc.html
|
||||
|
||||
FILE=qemu-$(VERSION)
|
||||
@@ -132,10 +245,10 @@ tar:
|
||||
BINPATH=/usr/local/qemu-i386
|
||||
|
||||
tarbin:
|
||||
tar zcvf /tmp/qemu-i386-glibc21.tar.gz \
|
||||
$(BINPATH)/etc $(BINPATH)/lib $(BINPATH)/bin
|
||||
tar zcvf /tmp/qemu-i386-wine.tar.gz \
|
||||
$(BINPATH)/X11R6 $(BINPATH)/wine
|
||||
tar zcvf /tmp/qemu-$(VERSION)-i386-glibc21.tar.gz \
|
||||
$(BINPATH)/etc $(BINPATH)/lib $(BINPATH)/bin $(BINPATH)/usr
|
||||
tar zcvf /tmp/qemu-$(VERSION)-i386-wine.tar.gz \
|
||||
$(BINPATH)/wine
|
||||
|
||||
ifneq ($(wildcard .depend),)
|
||||
include .depend
|
||||
|
||||
@@ -6,7 +6,7 @@ INSTALLATION
|
||||
|
||||
Type
|
||||
|
||||
./configure
|
||||
./configure --interp-prefix=/usr/local/qemu-i386
|
||||
make
|
||||
|
||||
to build qemu and libqemu.a.
|
||||
@@ -23,7 +23,7 @@ libraries installed on your PC. For example:
|
||||
./qemu -L / /bin/ls
|
||||
|
||||
* On non x86 CPUs, you need first to download at least an x86 glibc
|
||||
(qemu-i386-glibc21.tar.gz on the qemu web page). Ensure that
|
||||
(qemu-XXX-i386-glibc21.tar.gz on the qemu web page). Ensure that
|
||||
LD_LIBRARY_PATH is not set:
|
||||
|
||||
unset LD_LIBRARY_PATH
|
||||
@@ -36,6 +36,35 @@ You can look at /usr/local/qemu-i386/bin/qemu-conf.sh so that QEMU is
|
||||
automatically launched by the Linux kernel when you try to launch x86
|
||||
executables.
|
||||
|
||||
Tested tool versions
|
||||
--------------------
|
||||
|
||||
In order to compile QEMU succesfully, it is very important that you
|
||||
have the right tools. The most important one is gcc. I cannot guaranty
|
||||
that QEMU works if you do not use a tested gcc version. Look at
|
||||
'configure' and 'Makefile' if you want to make a different gcc
|
||||
version work.
|
||||
|
||||
host gcc binutils glibc linux distribution
|
||||
----------------------------------------------------------------------
|
||||
x86 2.95.2 2.13.2 2.1.3 2.4.18
|
||||
3.2 2.13.2 2.1.3 2.4.18
|
||||
2.96 2.11.93.0.2 2.2.5 2.4.18 Red Hat 7.3
|
||||
|
||||
PowerPC 2.95.4 2.12.90.0.1 2.2.5 2.4.20-pre2 Debian 3.0
|
||||
|
||||
Alpha 3.3 [1] 2.14.90.0.4 2.2.5 2.2.20 [2] Debian 3.0
|
||||
|
||||
Sparc32 2.95.4 2.12.90.0.1 2.2.5 2.4.18 Debian 3.0
|
||||
|
||||
ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9 [3] Debian 3.0
|
||||
|
||||
[1] On Alpha, QEMU needs the gcc 'visibility' attribute only available
|
||||
for gcc version >= 3.3.
|
||||
[2] Linux >= 2.4.20 is necessary for precise exception support
|
||||
(untested).
|
||||
[3] 2.4.9-ac10-rmk2-np1-cerf2
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
Information about the various packages used to build the current qemu
|
||||
x86 binary distribution:
|
||||
|
||||
* gcc 2.95.2 was used for the build. A glibc 2.1.3 Debian distribution
|
||||
was used to get most of the binary packages.
|
||||
|
||||
* wine-20020411 tarball
|
||||
|
||||
./configure --prefix=/usr/local/qemu-i386/wine
|
||||
|
||||
All exe and libs were stripped. Some compile time tools and the
|
||||
includes were deleted.
|
||||
|
||||
* ldconfig was launched to build the library links:
|
||||
|
||||
./qemu /usr/local/qemu-i386/bin/ldconfig-i386 -C /usr/local/qemu-i386/etc/ld.so.cache
|
||||
@@ -1,11 +1,26 @@
|
||||
- fix thread locks
|
||||
- optimize translated cache chaining (DLL PLT-like system)
|
||||
- fix thread stack liberation (use kernel 2.5.xxx CLONE_CHILD_CLEARTID)
|
||||
- fix x86 stack allocation
|
||||
- fix iret/lret restarting
|
||||
- optimize FPU operations (evaluate x87 stack pointer statically) and
|
||||
fix cr0.TS emulation
|
||||
- fix CCOP optimisation
|
||||
- fix all remaining thread lock issues (must put TBs in a specific invalid
|
||||
state, find a solution for tb_flush()).
|
||||
- cpu loop optimisation (optimise ret case as the cpu state does not change)
|
||||
- fix arm fpu rounding (at least for float->integer conversions)
|
||||
- add IPC syscalls
|
||||
|
||||
lower priority:
|
||||
--------------
|
||||
- sysenter/sysexit emulation
|
||||
- SMP support
|
||||
- finish segment ops (call far, ret far, load_seg suppressed)
|
||||
- use -msoft-float on ARM
|
||||
- use kernel traps for unaligned accesses on ARM ?
|
||||
- handle rare page fault cases (in particular if page fault in heplers or
|
||||
in syscall emulation code).
|
||||
- fix thread stack freeing (use kernel 2.5.x CLONE_CHILD_CLEARTID)
|
||||
- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit
|
||||
issues, fix 16 bit uid issues)
|
||||
- finish signal handing (fp87 state, more siginfo conversions)
|
||||
- verify thread support (clone() and various locks)
|
||||
- make it self runnable (use same trick as ld.so : include its own relocator and libc)
|
||||
- fix FPU exceptions (in particular: gen_op_fpush not before mem load)
|
||||
- use page_unprotect_range in every suitable syscall to handle all
|
||||
cases of self modifying code.
|
||||
- use gcc as a backend to generate better code (easy to do by using
|
||||
op-i386.c operations as local inline functions).
|
||||
- add SSE2/MMX operations
|
||||
+1963
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,128 @@
|
||||
OUTPUT_FORMAT("elf64-alpha", "elf64-alpha",
|
||||
"elf64-alpha")
|
||||
OUTPUT_ARCH(alpha)
|
||||
ENTRY(__start)
|
||||
SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
|
||||
SECTIONS
|
||||
{
|
||||
/* Read-only sections, merged into text segment: */
|
||||
. = 0x60000000 + SIZEOF_HEADERS;
|
||||
.interp : { *(.interp) }
|
||||
.hash : { *(.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
.rel.text :
|
||||
{ *(.rel.text) *(.rel.gnu.linkonce.t*) }
|
||||
.rela.text :
|
||||
{ *(.rela.text) *(.rela.gnu.linkonce.t*) }
|
||||
.rel.data :
|
||||
{ *(.rel.data) *(.rel.gnu.linkonce.d*) }
|
||||
.rela.data :
|
||||
{ *(.rela.data) *(.rela.gnu.linkonce.d*) }
|
||||
.rel.rodata :
|
||||
{ *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
|
||||
.rela.rodata :
|
||||
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
|
||||
.rel.got : { *(.rel.got) }
|
||||
.rela.got : { *(.rela.got) }
|
||||
.rel.ctors : { *(.rel.ctors) }
|
||||
.rela.ctors : { *(.rela.ctors) }
|
||||
.rel.dtors : { *(.rel.dtors) }
|
||||
.rela.dtors : { *(.rela.dtors) }
|
||||
.rel.init : { *(.rel.init) }
|
||||
.rela.init : { *(.rela.init) }
|
||||
.rel.fini : { *(.rel.fini) }
|
||||
.rela.fini : { *(.rela.fini) }
|
||||
.rel.bss : { *(.rel.bss) }
|
||||
.rela.bss : { *(.rela.bss) }
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.init : { *(.init) } =0x47ff041f
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||
*(.gnu.warning)
|
||||
*(.gnu.linkonce.t*)
|
||||
} =0x47ff041f
|
||||
_etext = .;
|
||||
PROVIDE (etext = .);
|
||||
.fini : { *(.fini) } =0x47ff041f
|
||||
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.reginfo : { *(.reginfo) }
|
||||
/* Adjust the address for the data segment. We want to adjust up to
|
||||
the same address within the page on the next page up. */
|
||||
. = ALIGN(0x100000) + (. & (0x100000 - 1));
|
||||
.data :
|
||||
{
|
||||
*(.data)
|
||||
*(.gnu.linkonce.d*)
|
||||
CONSTRUCTORS
|
||||
}
|
||||
.data1 : { *(.data1) }
|
||||
.ctors :
|
||||
{
|
||||
*(.ctors)
|
||||
}
|
||||
.dtors :
|
||||
{
|
||||
*(.dtors)
|
||||
}
|
||||
.plt : { *(.plt) }
|
||||
.got : { *(.got.plt) *(.got) }
|
||||
.dynamic : { *(.dynamic) }
|
||||
/* We want the small data sections together, so single-instruction offsets
|
||||
can access them all, and initialized data all before uninitialized, so
|
||||
we can shorten the on-disk segment size. */
|
||||
.sdata : { *(.sdata) }
|
||||
_edata = .;
|
||||
PROVIDE (edata = .);
|
||||
__bss_start = .;
|
||||
.sbss : { *(.sbss) *(.scommon) }
|
||||
.bss :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
}
|
||||
_end = . ;
|
||||
PROVIDE (end = .);
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
/* These must appear regardless of . */
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm",
|
||||
"elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
ENTRY(_start)
|
||||
SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
|
||||
SECTIONS
|
||||
{
|
||||
/* Read-only sections, merged into text segment: */
|
||||
. = 0x60000000 + SIZEOF_HEADERS;
|
||||
.interp : { *(.interp) }
|
||||
.hash : { *(.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
.rel.text :
|
||||
{ *(.rel.text) *(.rel.gnu.linkonce.t*) }
|
||||
.rela.text :
|
||||
{ *(.rela.text) *(.rela.gnu.linkonce.t*) }
|
||||
.rel.data :
|
||||
{ *(.rel.data) *(.rel.gnu.linkonce.d*) }
|
||||
.rela.data :
|
||||
{ *(.rela.data) *(.rela.gnu.linkonce.d*) }
|
||||
.rel.rodata :
|
||||
{ *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
|
||||
.rela.rodata :
|
||||
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
|
||||
.rel.got : { *(.rel.got) }
|
||||
.rela.got : { *(.rela.got) }
|
||||
.rel.ctors : { *(.rel.ctors) }
|
||||
.rela.ctors : { *(.rela.ctors) }
|
||||
.rel.dtors : { *(.rel.dtors) }
|
||||
.rela.dtors : { *(.rela.dtors) }
|
||||
.rel.init : { *(.rel.init) }
|
||||
.rela.init : { *(.rela.init) }
|
||||
.rel.fini : { *(.rel.fini) }
|
||||
.rela.fini : { *(.rela.fini) }
|
||||
.rel.bss : { *(.rel.bss) }
|
||||
.rela.bss : { *(.rela.bss) }
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.init : { *(.init) } =0x47ff041f
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||
*(.gnu.warning)
|
||||
*(.gnu.linkonce.t*)
|
||||
} =0x47ff041f
|
||||
_etext = .;
|
||||
PROVIDE (etext = .);
|
||||
.fini : { *(.fini) } =0x47ff041f
|
||||
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.reginfo : { *(.reginfo) }
|
||||
/* Adjust the address for the data segment. We want to adjust up to
|
||||
the same address within the page on the next page up. */
|
||||
. = ALIGN(0x100000) + (. & (0x100000 - 1));
|
||||
.data :
|
||||
{
|
||||
*(.data)
|
||||
*(.gnu.linkonce.d*)
|
||||
CONSTRUCTORS
|
||||
}
|
||||
.data1 : { *(.data1) }
|
||||
.ctors :
|
||||
{
|
||||
*(.ctors)
|
||||
}
|
||||
.dtors :
|
||||
{
|
||||
*(.dtors)
|
||||
}
|
||||
.plt : { *(.plt) }
|
||||
.got : { *(.got.plt) *(.got) }
|
||||
.dynamic : { *(.dynamic) }
|
||||
/* We want the small data sections together, so single-instruction offsets
|
||||
can access them all, and initialized data all before uninitialized, so
|
||||
we can shorten the on-disk segment size. */
|
||||
.sdata : { *(.sdata) }
|
||||
_edata = .;
|
||||
PROVIDE (edata = .);
|
||||
__bss_start = .;
|
||||
.sbss : { *(.sbss) *(.scommon) }
|
||||
.bss :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
}
|
||||
_end = . ;
|
||||
PROVIDE (end = .);
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
/* These must appear regardless of . */
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* QEMU System Emulator block driver
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <malloc.h>
|
||||
#include <termios.h>
|
||||
#include <sys/poll.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
#define NO_THUNK_TYPE_SIZE
|
||||
#include "thunk.h"
|
||||
|
||||
struct BlockDriverState {
|
||||
int fd; /* if -1, only COW mappings */
|
||||
int64_t total_sectors;
|
||||
int read_only;
|
||||
|
||||
uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */
|
||||
uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */
|
||||
int cow_bitmap_size;
|
||||
int cow_fd;
|
||||
int64_t cow_sectors_offset;
|
||||
char filename[1024];
|
||||
};
|
||||
|
||||
BlockDriverState *bdrv_open(const char *filename, int snapshot)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
int fd, cow_fd;
|
||||
int64_t size;
|
||||
char template[] = "/tmp/vl.XXXXXX";
|
||||
struct cow_header_v2 cow_header;
|
||||
struct stat st;
|
||||
|
||||
bs = malloc(sizeof(BlockDriverState));
|
||||
if(!bs)
|
||||
return NULL;
|
||||
bs->read_only = 0;
|
||||
bs->fd = -1;
|
||||
bs->cow_fd = -1;
|
||||
bs->cow_bitmap = NULL;
|
||||
strcpy(bs->filename, filename);
|
||||
|
||||
/* open standard HD image */
|
||||
fd = open(filename, O_RDWR | O_LARGEFILE);
|
||||
if (fd < 0) {
|
||||
/* read only image on disk */
|
||||
fd = open(filename, O_RDONLY | O_LARGEFILE);
|
||||
if (fd < 0) {
|
||||
perror(filename);
|
||||
goto fail;
|
||||
}
|
||||
if (!snapshot)
|
||||
bs->read_only = 1;
|
||||
}
|
||||
bs->fd = fd;
|
||||
|
||||
/* see if it is a cow image */
|
||||
if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) {
|
||||
fprintf(stderr, "%s: could not read header\n", filename);
|
||||
goto fail;
|
||||
}
|
||||
if (cow_header.magic == htonl(COW_MAGIC) &&
|
||||
cow_header.version == htonl(COW_VERSION)) {
|
||||
/* cow image found */
|
||||
size = cow_header.size;
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
size = bswap64(size);
|
||||
#endif
|
||||
bs->total_sectors = size / 512;
|
||||
|
||||
bs->cow_fd = fd;
|
||||
bs->fd = -1;
|
||||
if (cow_header.backing_file[0] != '\0') {
|
||||
if (stat(cow_header.backing_file, &st) != 0) {
|
||||
fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
|
||||
goto fail;
|
||||
}
|
||||
if (st.st_mtime != htonl(cow_header.mtime)) {
|
||||
fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file);
|
||||
goto fail;
|
||||
}
|
||||
fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE);
|
||||
if (fd < 0)
|
||||
goto fail;
|
||||
bs->fd = fd;
|
||||
}
|
||||
/* mmap the bitmap */
|
||||
bs->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
|
||||
bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size),
|
||||
bs->cow_bitmap_size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, bs->cow_fd, 0);
|
||||
if (bs->cow_bitmap_addr == MAP_FAILED)
|
||||
goto fail;
|
||||
bs->cow_bitmap = bs->cow_bitmap_addr + sizeof(cow_header);
|
||||
bs->cow_sectors_offset = (bs->cow_bitmap_size + 511) & ~511;
|
||||
snapshot = 0;
|
||||
} else {
|
||||
/* standard raw image */
|
||||
size = lseek64(fd, 0, SEEK_END);
|
||||
bs->total_sectors = size / 512;
|
||||
bs->fd = fd;
|
||||
}
|
||||
|
||||
if (snapshot) {
|
||||
/* create a temporary COW file */
|
||||
cow_fd = mkstemp(template);
|
||||
if (cow_fd < 0)
|
||||
goto fail;
|
||||
bs->cow_fd = cow_fd;
|
||||
unlink(template);
|
||||
|
||||
/* just need to allocate bitmap */
|
||||
bs->cow_bitmap_size = (bs->total_sectors + 7) >> 3;
|
||||
bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size),
|
||||
bs->cow_bitmap_size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (bs->cow_bitmap_addr == MAP_FAILED)
|
||||
goto fail;
|
||||
bs->cow_bitmap = bs->cow_bitmap_addr;
|
||||
bs->cow_sectors_offset = 0;
|
||||
}
|
||||
|
||||
return bs;
|
||||
fail:
|
||||
bdrv_close(bs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void bdrv_close(BlockDriverState *bs)
|
||||
{
|
||||
/* we unmap the mapping so that it is written to the COW file */
|
||||
if (bs->cow_bitmap_addr)
|
||||
munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size);
|
||||
if (bs->cow_fd >= 0)
|
||||
close(bs->cow_fd);
|
||||
if (bs->fd >= 0)
|
||||
close(bs->fd);
|
||||
free(bs);
|
||||
}
|
||||
|
||||
static inline void set_bit(uint8_t *bitmap, int64_t bitnum)
|
||||
{
|
||||
bitmap[bitnum / 8] |= (1 << (bitnum%8));
|
||||
}
|
||||
|
||||
static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum)
|
||||
{
|
||||
return !!(bitmap[bitnum / 8] & (1 << (bitnum%8)));
|
||||
}
|
||||
|
||||
|
||||
/* Return true if first block has been changed (ie. current version is
|
||||
* in COW file). Set the number of continuous blocks for which that
|
||||
* is true. */
|
||||
static int is_changed(uint8_t *bitmap,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
int *num_same)
|
||||
{
|
||||
int changed;
|
||||
|
||||
if (!bitmap || nb_sectors == 0) {
|
||||
*num_same = nb_sectors;
|
||||
return 0;
|
||||
}
|
||||
|
||||
changed = is_bit_set(bitmap, sector_num);
|
||||
for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
|
||||
if (is_bit_set(bitmap, sector_num + *num_same) != changed)
|
||||
break;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/* commit COW file into the raw image */
|
||||
int bdrv_commit(BlockDriverState *bs)
|
||||
{
|
||||
int64_t i;
|
||||
uint8_t *cow_bitmap;
|
||||
|
||||
if (!bs->cow_bitmap) {
|
||||
fprintf(stderr, "Already committed to %s\n", bs->filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bs->read_only) {
|
||||
fprintf(stderr, "Can't commit to %s: read-only\n", bs->filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cow_bitmap = bs->cow_bitmap;
|
||||
for (i = 0; i < bs->total_sectors; i++) {
|
||||
if (is_bit_set(cow_bitmap, i)) {
|
||||
unsigned char sector[512];
|
||||
if (bdrv_read(bs, i, sector, 1) != 0) {
|
||||
fprintf(stderr, "Error reading sector %lli: aborting commit\n",
|
||||
(long long)i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Make bdrv_write write to real file for a moment. */
|
||||
bs->cow_bitmap = NULL;
|
||||
if (bdrv_write(bs, i, sector, 1) != 0) {
|
||||
fprintf(stderr, "Error writing sector %lli: aborting commit\n",
|
||||
(long long)i);
|
||||
bs->cow_bitmap = cow_bitmap;
|
||||
return -1;
|
||||
}
|
||||
bs->cow_bitmap = cow_bitmap;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "Committed snapshot to %s\n", bs->filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return -1 if error */
|
||||
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
int ret, n, fd;
|
||||
int64_t offset;
|
||||
|
||||
while (nb_sectors > 0) {
|
||||
if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) {
|
||||
fd = bs->cow_fd;
|
||||
offset = bs->cow_sectors_offset;
|
||||
} else {
|
||||
fd = bs->fd;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
/* no file, just return empty sectors */
|
||||
memset(buf, 0, n * 512);
|
||||
} else {
|
||||
offset += sector_num * 512;
|
||||
lseek64(fd, offset, SEEK_SET);
|
||||
ret = read(fd, buf, n * 512);
|
||||
if (ret != n * 512) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
nb_sectors -= n;
|
||||
sector_num += n;
|
||||
buf += n * 512;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return -1 if error */
|
||||
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
int ret, fd, i;
|
||||
int64_t offset, retl;
|
||||
|
||||
if (bs->read_only)
|
||||
return -1;
|
||||
|
||||
if (bs->cow_bitmap) {
|
||||
fd = bs->cow_fd;
|
||||
offset = bs->cow_sectors_offset;
|
||||
} else {
|
||||
fd = bs->fd;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
offset += sector_num * 512;
|
||||
retl = lseek64(fd, offset, SEEK_SET);
|
||||
if (retl == -1) {
|
||||
return -1;
|
||||
}
|
||||
ret = write(fd, buf, nb_sectors * 512);
|
||||
if (ret != nb_sectors * 512) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bs->cow_bitmap) {
|
||||
for (i = 0; i < nb_sectors; i++)
|
||||
set_bit(bs->cow_bitmap, sector_num + i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
|
||||
{
|
||||
*nb_sectors_ptr = bs->total_sectors;
|
||||
}
|
||||
@@ -19,12 +19,16 @@ TMPH="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.h"
|
||||
|
||||
# default parameters
|
||||
prefix="/usr/local"
|
||||
interp_prefix="/usr/gnemul/qemu-i386"
|
||||
static="no"
|
||||
cross_prefix=""
|
||||
cc="gcc"
|
||||
host_cc="gcc"
|
||||
ar="ar"
|
||||
make="make"
|
||||
strip="strip"
|
||||
target_cpu="x86"
|
||||
target_bigendian="default"
|
||||
cpu=`uname -m`
|
||||
case "$cpu" in
|
||||
i386|i486|i586|i686|i86pc|BePC)
|
||||
@@ -45,6 +49,15 @@ case "$cpu" in
|
||||
s390)
|
||||
cpu="s390"
|
||||
;;
|
||||
sparc)
|
||||
cpu="sparc"
|
||||
;;
|
||||
sparc64)
|
||||
cpu="sparc64"
|
||||
;;
|
||||
ia64)
|
||||
cpu="ia64"
|
||||
;;
|
||||
*)
|
||||
cpu="unknown"
|
||||
;;
|
||||
@@ -55,22 +68,6 @@ bigendian="no"
|
||||
# OS specific
|
||||
targetos=`uname -s`
|
||||
case $targetos in
|
||||
BeOS)
|
||||
prefix="/boot/home/config"
|
||||
# helps building libavcodec
|
||||
CFLAGS="-O2 -DPIC"
|
||||
# no need for libm, but the inet stuff
|
||||
# Check for BONE
|
||||
if (echo $BEINCLUDES|grep 'headers/be/bone' >/dev/null); then
|
||||
extralibs="-lbind -lsocket"
|
||||
else
|
||||
echo "Not sure building for net_server will succeed... good luck."
|
||||
extralibs="-lsocket"
|
||||
fi ;;
|
||||
BSD/OS)
|
||||
extralibs="-lpoll -lgnugetopt -lm"
|
||||
make="gmake"
|
||||
;;
|
||||
*) ;;
|
||||
esac
|
||||
|
||||
@@ -89,6 +86,8 @@ for opt do
|
||||
case "$opt" in
|
||||
--prefix=*) prefix=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--interp-prefix=*) interp_prefix=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--source-path=*) source_path=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2`
|
||||
@@ -105,8 +104,16 @@ for opt do
|
||||
;;
|
||||
--cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--target-cpu=*) target_cpu=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--target-big-endian) target_bigendian="yes"
|
||||
;;
|
||||
--target-little-endian) target_bigendian="no"
|
||||
;;
|
||||
--enable-gprof) gprof="yes"
|
||||
;;
|
||||
--static) static="yes"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -140,26 +147,31 @@ fi
|
||||
else
|
||||
|
||||
# if cross compiling, cannot launch a program, so make a static guess
|
||||
if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" ; then
|
||||
if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64"; then
|
||||
bigendian="yes"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# check gcc version
|
||||
# check gcc options support
|
||||
cat > $TMPC <<EOF
|
||||
int main(void) {
|
||||
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)
|
||||
return 0;
|
||||
#else
|
||||
#error gcc < 3.2
|
||||
#endif
|
||||
}
|
||||
EOF
|
||||
|
||||
gcc_major="2"
|
||||
if $cc -o $TMPO $TMPC 2> /dev/null ; then
|
||||
gcc_major="3"
|
||||
have_gcc3_options="no"
|
||||
if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/null ; then
|
||||
have_gcc3_options="yes"
|
||||
fi
|
||||
|
||||
if test "$target_bigendian" = "default" ; then
|
||||
if test "$target_cpu" = "x86" ; then
|
||||
target_bigendian="no"
|
||||
elif test "$target_cpu" = "arm" ; then
|
||||
target_bigendian="no"
|
||||
else
|
||||
target_bigendian="no"
|
||||
fi
|
||||
fi
|
||||
|
||||
if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
|
||||
@@ -172,25 +184,31 @@ EOF
|
||||
echo "Standard options:"
|
||||
echo " --help print this message"
|
||||
echo " --prefix=PREFIX install in PREFIX [$prefix]"
|
||||
echo " for audio/video/image support"
|
||||
echo " --interp-prefix=PREFIX where to find shared libraries, etc. [$interp_prefix]"
|
||||
echo " --target_cpu=CPU set target cpu (x86 or arm) [$target_cpu]"
|
||||
echo ""
|
||||
echo "Advanced options (experts only):"
|
||||
echo " --source-path=PATH path of source code [$source_path]"
|
||||
echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]"
|
||||
echo " --cc=CC use C compiler CC [$cc]"
|
||||
echo " --make=MAKE use specified make [$make]"
|
||||
echo " --static enable static build [$static]"
|
||||
echo ""
|
||||
echo "NOTE: The object files are build at the place where configure is launched"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Install prefix $prefix"
|
||||
echo "Source path $source_path"
|
||||
echo "C compiler $cc"
|
||||
echo "make $make"
|
||||
echo "CPU $cpu"
|
||||
echo "Big Endian $bigendian"
|
||||
echo "gprof enabled $gprof"
|
||||
echo "Install prefix $prefix"
|
||||
echo "Source path $source_path"
|
||||
echo "ELF interp prefix $interp_prefix"
|
||||
echo "C compiler $cc"
|
||||
echo "make $make"
|
||||
echo "host CPU $cpu"
|
||||
echo "host big endian $bigendian"
|
||||
echo "target CPU $target_cpu"
|
||||
echo "target big endian $target_bigendian"
|
||||
echo "gprof enabled $gprof"
|
||||
echo "static build $static"
|
||||
|
||||
echo "Creating config.mak and config.h"
|
||||
|
||||
@@ -198,10 +216,12 @@ echo "# Automatically generated by configure - do not modify" > config.mak
|
||||
echo "/* Automatically generated by configure - do not modify */" > $TMPH
|
||||
|
||||
echo "prefix=$prefix" >> config.mak
|
||||
echo "#define CONFIG_QEMU_PREFIX \"$prefix\"" >> $TMPH
|
||||
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix\"" >> $TMPH
|
||||
echo "MAKE=$make" >> config.mak
|
||||
echo "CC=$cc" >> config.mak
|
||||
echo "GCC_MAJOR=$gcc_major" >> config.mak
|
||||
if test "$have_gcc3_options" = "yes" ; then
|
||||
echo "HAVE_GCC3_OPTIONS=yes" >> config.mak
|
||||
fi
|
||||
echo "HOST_CC=$host_cc" >> config.mak
|
||||
echo "AR=$ar" >> config.mak
|
||||
echo "STRIP=$strip -s -R .comment -R .note" >> config.mak
|
||||
@@ -225,6 +245,15 @@ elif test "$cpu" = "s390" ; then
|
||||
elif test "$cpu" = "alpha" ; then
|
||||
echo "ARCH=alpha" >> config.mak
|
||||
echo "#define HOST_ALPHA 1" >> $TMPH
|
||||
elif test "$cpu" = "sparc" ; then
|
||||
echo "ARCH=sparc" >> config.mak
|
||||
echo "#define HOST_SPARC 1" >> $TMPH
|
||||
elif test "$cpu" = "sparc64" ; then
|
||||
echo "ARCH=sparc64" >> config.mak
|
||||
echo "#define HOST_SPARC64 1" >> $TMPH
|
||||
elif test "$cpu" = "ia64" ; then
|
||||
echo "ARCH=ia64" >> config.mak
|
||||
echo "#define HOST_IA64 1" >> $TMPH
|
||||
else
|
||||
echo "Unsupported CPU"
|
||||
exit 1
|
||||
@@ -233,20 +262,37 @@ if test "$bigendian" = "yes" ; then
|
||||
echo "WORDS_BIGENDIAN=yes" >> config.mak
|
||||
echo "#define WORDS_BIGENDIAN 1" >> $TMPH
|
||||
fi
|
||||
|
||||
if test "$target_cpu" = "x86" ; then
|
||||
echo "TARGET_ARCH=i386" >> config.mak
|
||||
echo "#define TARGET_ARCH \"i386\"" >> $TMPH
|
||||
echo "#define TARGET_I386 1" >> $TMPH
|
||||
elif test "$target_cpu" = "arm" ; then
|
||||
echo "TARGET_ARCH=arm" >> config.mak
|
||||
echo "#define TARGET_ARCH \"arm\"" >> $TMPH
|
||||
echo "#define TARGET_ARM 1" >> $TMPH
|
||||
else
|
||||
echo "Unsupported target CPU"
|
||||
exit 1
|
||||
fi
|
||||
if test "$target_bigendian" = "yes" ; then
|
||||
echo "TARGET_WORDS_BIGENDIAN=yes" >> config.mak
|
||||
echo "#define TARGET_WORDS_BIGENDIAN 1" >> $TMPH
|
||||
fi
|
||||
|
||||
if test "$gprof" = "yes" ; then
|
||||
echo "TARGET_GPROF=yes" >> config.mak
|
||||
echo "#define HAVE_GPROF 1" >> $TMPH
|
||||
fi
|
||||
if test "$static" = "yes" ; then
|
||||
echo "CONFIG_STATIC=yes" >> config.mak
|
||||
fi
|
||||
echo -n "VERSION=" >>config.mak
|
||||
head $source_path/VERSION >>config.mak
|
||||
echo "" >>config.mak
|
||||
echo -n "#define QEMU_VERSION \"" >> $TMPH
|
||||
head $source_path/VERSION >> $TMPH
|
||||
echo "\"" >> $TMPH
|
||||
if test "$network" = "yes" ; then
|
||||
echo "#define CONFIG_NETWORK 1" >> $TMPH
|
||||
echo "CONFIG_NETWORK=yes" >> config.mak
|
||||
fi
|
||||
|
||||
# build tree in object directory if source path is different from current one
|
||||
if test "$source_path_used" = "yes" ; then
|
||||
@@ -268,4 +314,4 @@ else
|
||||
echo "config.h is unchanged"
|
||||
fi
|
||||
|
||||
rm -f $TMPH
|
||||
rm -f $TMPO $TMPC $TMPE $TMPS $TMPH
|
||||
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
* defines common to all virtual CPUs
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef CPU_ALL_H
|
||||
#define CPU_ALL_H
|
||||
|
||||
/* all CPU memory access use these macros */
|
||||
static inline int ldub(void *ptr)
|
||||
{
|
||||
return *(uint8_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldsb(void *ptr)
|
||||
{
|
||||
return *(int8_t *)ptr;
|
||||
}
|
||||
|
||||
static inline void stb(void *ptr, int v)
|
||||
{
|
||||
*(uint8_t *)ptr = v;
|
||||
}
|
||||
|
||||
/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
|
||||
kernel handles unaligned load/stores may give better results, but
|
||||
it is a system wide setting : bad */
|
||||
#if defined(WORDS_BIGENDIAN) || defined(__arm__)
|
||||
|
||||
/* conservative code for little endian unaligned accesses */
|
||||
static inline int lduw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
||||
return val;
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
return p[0] | (p[1] << 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ldsw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
||||
return (int16_t)val;
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
return (int16_t)(p[0] | (p[1] << 8));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ldl(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
__asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
||||
return val;
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t ldq(void *ptr)
|
||||
{
|
||||
uint8_t *p = ptr;
|
||||
uint32_t v1, v2;
|
||||
v1 = ldl(p);
|
||||
v2 = ldl(p + 4);
|
||||
return v1 | ((uint64_t)v2 << 32);
|
||||
}
|
||||
|
||||
static inline void stw(void *ptr, int v)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
p[0] = v;
|
||||
p[1] = v >> 8;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void stl(void *ptr, int v)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
p[0] = v;
|
||||
p[1] = v >> 8;
|
||||
p[2] = v >> 16;
|
||||
p[3] = v >> 24;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void stq(void *ptr, uint64_t v)
|
||||
{
|
||||
uint8_t *p = ptr;
|
||||
stl(p, (uint32_t)v);
|
||||
stl(p + 4, v >> 32);
|
||||
}
|
||||
|
||||
/* float access */
|
||||
|
||||
static inline float ldfl(void *ptr)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.i = ldl(ptr);
|
||||
return u.f;
|
||||
}
|
||||
|
||||
static inline void stfl(void *ptr, float v)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.f = v;
|
||||
stl(ptr, u.i);
|
||||
}
|
||||
|
||||
#if defined(__arm__) && !defined(WORDS_BIGENDIAN)
|
||||
|
||||
/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */
|
||||
static inline double ldfq(void *ptr)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint32_t tab[2];
|
||||
} u;
|
||||
u.tab[1] = ldl(ptr);
|
||||
u.tab[0] = ldl(ptr + 4);
|
||||
return u.d;
|
||||
}
|
||||
|
||||
static inline void stfq(void *ptr, double v)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint32_t tab[2];
|
||||
} u;
|
||||
u.d = v;
|
||||
stl(ptr, u.tab[1]);
|
||||
stl(ptr + 4, u.tab[0]);
|
||||
}
|
||||
|
||||
#else
|
||||
static inline double ldfq(void *ptr)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
u.i = ldq(ptr);
|
||||
return u.d;
|
||||
}
|
||||
|
||||
static inline void stfq(void *ptr, double v)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
u.d = v;
|
||||
stq(ptr, u.i);
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
static inline int lduw(void *ptr)
|
||||
{
|
||||
return *(uint16_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldsw(void *ptr)
|
||||
{
|
||||
return *(int16_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldl(void *ptr)
|
||||
{
|
||||
return *(uint32_t *)ptr;
|
||||
}
|
||||
|
||||
static inline uint64_t ldq(void *ptr)
|
||||
{
|
||||
return *(uint64_t *)ptr;
|
||||
}
|
||||
|
||||
static inline void stw(void *ptr, int v)
|
||||
{
|
||||
*(uint16_t *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stl(void *ptr, int v)
|
||||
{
|
||||
*(uint32_t *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stq(void *ptr, uint64_t v)
|
||||
{
|
||||
*(uint64_t *)ptr = v;
|
||||
}
|
||||
|
||||
/* float access */
|
||||
|
||||
static inline float ldfl(void *ptr)
|
||||
{
|
||||
return *(float *)ptr;
|
||||
}
|
||||
|
||||
static inline double ldfq(void *ptr)
|
||||
{
|
||||
return *(double *)ptr;
|
||||
}
|
||||
|
||||
static inline void stfl(void *ptr, float v)
|
||||
{
|
||||
*(float *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stfq(void *ptr, double v)
|
||||
{
|
||||
*(double *)ptr = v;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* page related stuff */
|
||||
|
||||
#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS)
|
||||
#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1)
|
||||
#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK)
|
||||
|
||||
extern unsigned long real_host_page_size;
|
||||
extern unsigned long host_page_bits;
|
||||
extern unsigned long host_page_size;
|
||||
extern unsigned long host_page_mask;
|
||||
|
||||
#define HOST_PAGE_ALIGN(addr) (((addr) + host_page_size - 1) & host_page_mask)
|
||||
|
||||
/* same as PROT_xxx */
|
||||
#define PAGE_READ 0x0001
|
||||
#define PAGE_WRITE 0x0002
|
||||
#define PAGE_EXEC 0x0004
|
||||
#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC)
|
||||
#define PAGE_VALID 0x0008
|
||||
/* original state of the write flag (used when tracking self-modifying
|
||||
code */
|
||||
#define PAGE_WRITE_ORG 0x0010
|
||||
|
||||
void page_dump(FILE *f);
|
||||
int page_get_flags(unsigned long address);
|
||||
void page_set_flags(unsigned long start, unsigned long end, int flags);
|
||||
void page_unprotect_range(uint8_t *data, unsigned long data_size);
|
||||
|
||||
#define SINGLE_CPU_DEFINES
|
||||
#ifdef SINGLE_CPU_DEFINES
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
|
||||
#define CPUState CPUX86State
|
||||
#define cpu_init cpu_x86_init
|
||||
#define cpu_exec cpu_x86_exec
|
||||
#define cpu_gen_code cpu_x86_gen_code
|
||||
#define cpu_interrupt cpu_x86_interrupt
|
||||
#define cpu_signal_handler cpu_x86_signal_handler
|
||||
|
||||
#elif defined(TARGET_ARM)
|
||||
|
||||
#define CPUState CPUARMState
|
||||
#define cpu_init cpu_arm_init
|
||||
#define cpu_exec cpu_arm_exec
|
||||
#define cpu_gen_code cpu_arm_gen_code
|
||||
#define cpu_interrupt cpu_arm_interrupt
|
||||
#define cpu_signal_handler cpu_arm_signal_handler
|
||||
|
||||
#else
|
||||
|
||||
#error unsupported target CPU
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* SINGLE_CPU_DEFINES */
|
||||
|
||||
#define DEFAULT_GDBSTUB_PORT 1234
|
||||
|
||||
void cpu_abort(CPUState *env, const char *fmt, ...);
|
||||
extern CPUState *cpu_single_env;
|
||||
|
||||
#define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */
|
||||
#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */
|
||||
void cpu_interrupt(CPUState *s, int mask);
|
||||
|
||||
/* gdb stub API */
|
||||
extern int gdbstub_fd;
|
||||
CPUState *cpu_gdbstub_get_env(void *opaque);
|
||||
int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port);
|
||||
|
||||
#endif /* CPU_ALL_H */
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* ARM virtual CPU header
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef CPU_ARM_H
|
||||
#define CPU_ARM_H
|
||||
|
||||
#include "config.h"
|
||||
#include <setjmp.h>
|
||||
|
||||
#define EXCP_UDEF 1 /* undefined instruction */
|
||||
#define EXCP_SWI 2 /* software interrupt */
|
||||
#define EXCP_INTERRUPT 256 /* async interruption */
|
||||
|
||||
typedef struct CPUARMState {
|
||||
uint32_t regs[16];
|
||||
uint32_t cpsr;
|
||||
|
||||
/* cpsr flag cache for faster execution */
|
||||
uint32_t CF; /* 0 or 1 */
|
||||
uint32_t VF; /* V is the bit 31. All other bits are undefined */
|
||||
uint32_t NZF; /* N is bit 31. Z is computed from NZF */
|
||||
|
||||
/* exception/interrupt handling */
|
||||
jmp_buf jmp_env;
|
||||
int exception_index;
|
||||
int interrupt_request;
|
||||
struct TranslationBlock *current_tb;
|
||||
int user_mode_only;
|
||||
|
||||
/* user data */
|
||||
void *opaque;
|
||||
} CPUARMState;
|
||||
|
||||
CPUARMState *cpu_arm_init(void);
|
||||
int cpu_arm_exec(CPUARMState *s);
|
||||
void cpu_arm_close(CPUARMState *s);
|
||||
/* you can call this signal handler from your SIGBUS and SIGSEGV
|
||||
signal handlers to inform the virtual CPU of exceptions. non zero
|
||||
is returned if the signal was handled by the virtual CPU. */
|
||||
struct siginfo;
|
||||
int cpu_arm_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc);
|
||||
|
||||
void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags);
|
||||
|
||||
#define TARGET_PAGE_BITS 12
|
||||
#include "cpu-all.h"
|
||||
|
||||
#endif
|
||||
+642
@@ -0,0 +1,642 @@
|
||||
/*
|
||||
* i386 emulator main execution loop
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "config.h"
|
||||
#ifdef TARGET_I386
|
||||
#include "exec-i386.h"
|
||||
#endif
|
||||
#ifdef TARGET_ARM
|
||||
#include "exec-arm.h"
|
||||
#endif
|
||||
|
||||
#include "disas.h"
|
||||
|
||||
//#define DEBUG_EXEC
|
||||
//#define DEBUG_SIGNAL
|
||||
|
||||
#if defined(TARGET_ARM)
|
||||
/* XXX: unify with i386 target */
|
||||
void cpu_loop_exit(void)
|
||||
{
|
||||
longjmp(env->jmp_env, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* main execution loop */
|
||||
|
||||
int cpu_exec(CPUState *env1)
|
||||
{
|
||||
int saved_T0, saved_T1, saved_T2;
|
||||
CPUState *saved_env;
|
||||
#ifdef reg_EAX
|
||||
int saved_EAX;
|
||||
#endif
|
||||
#ifdef reg_ECX
|
||||
int saved_ECX;
|
||||
#endif
|
||||
#ifdef reg_EDX
|
||||
int saved_EDX;
|
||||
#endif
|
||||
#ifdef reg_EBX
|
||||
int saved_EBX;
|
||||
#endif
|
||||
#ifdef reg_ESP
|
||||
int saved_ESP;
|
||||
#endif
|
||||
#ifdef reg_EBP
|
||||
int saved_EBP;
|
||||
#endif
|
||||
#ifdef reg_ESI
|
||||
int saved_ESI;
|
||||
#endif
|
||||
#ifdef reg_EDI
|
||||
int saved_EDI;
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
int saved_i7, tmp_T0;
|
||||
#endif
|
||||
int code_gen_size, ret, interrupt_request;
|
||||
void (*gen_func)(void);
|
||||
TranslationBlock *tb, **ptb;
|
||||
uint8_t *tc_ptr, *cs_base, *pc;
|
||||
unsigned int flags;
|
||||
|
||||
/* first we save global registers */
|
||||
saved_T0 = T0;
|
||||
saved_T1 = T1;
|
||||
saved_T2 = T2;
|
||||
saved_env = env;
|
||||
env = env1;
|
||||
#ifdef __sparc__
|
||||
/* we also save i7 because longjmp may not restore it */
|
||||
asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
#ifdef reg_EAX
|
||||
saved_EAX = EAX;
|
||||
EAX = env->regs[R_EAX];
|
||||
#endif
|
||||
#ifdef reg_ECX
|
||||
saved_ECX = ECX;
|
||||
ECX = env->regs[R_ECX];
|
||||
#endif
|
||||
#ifdef reg_EDX
|
||||
saved_EDX = EDX;
|
||||
EDX = env->regs[R_EDX];
|
||||
#endif
|
||||
#ifdef reg_EBX
|
||||
saved_EBX = EBX;
|
||||
EBX = env->regs[R_EBX];
|
||||
#endif
|
||||
#ifdef reg_ESP
|
||||
saved_ESP = ESP;
|
||||
ESP = env->regs[R_ESP];
|
||||
#endif
|
||||
#ifdef reg_EBP
|
||||
saved_EBP = EBP;
|
||||
EBP = env->regs[R_EBP];
|
||||
#endif
|
||||
#ifdef reg_ESI
|
||||
saved_ESI = ESI;
|
||||
ESI = env->regs[R_ESI];
|
||||
#endif
|
||||
#ifdef reg_EDI
|
||||
saved_EDI = EDI;
|
||||
EDI = env->regs[R_EDI];
|
||||
#endif
|
||||
|
||||
/* put eflags in CPU temporary format */
|
||||
CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||
DF = 1 - (2 * ((env->eflags >> 10) & 1));
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||
#elif defined(TARGET_ARM)
|
||||
{
|
||||
unsigned int psr;
|
||||
psr = env->cpsr;
|
||||
env->CF = (psr >> 29) & 1;
|
||||
env->NZF = (psr & 0xc0000000) ^ 0x40000000;
|
||||
env->VF = (psr << 3) & 0x80000000;
|
||||
env->cpsr = psr & ~0xf0000000;
|
||||
}
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
env->exception_index = -1;
|
||||
|
||||
/* prepare setjmp context for exception handling */
|
||||
for(;;) {
|
||||
if (setjmp(env->jmp_env) == 0) {
|
||||
/* if an exception is pending, we execute it here */
|
||||
if (env->exception_index >= 0) {
|
||||
if (env->exception_index >= EXCP_INTERRUPT) {
|
||||
/* exit request from the cpu execution loop */
|
||||
ret = env->exception_index;
|
||||
break;
|
||||
} else if (env->user_mode_only) {
|
||||
/* if user mode only, we simulate a fake exception
|
||||
which will be hanlded outside the cpu execution
|
||||
loop */
|
||||
#if defined(TARGET_I386)
|
||||
do_interrupt_user(env->exception_index,
|
||||
env->exception_is_int,
|
||||
env->error_code,
|
||||
env->exception_next_eip);
|
||||
#endif
|
||||
ret = env->exception_index;
|
||||
break;
|
||||
} else {
|
||||
#if defined(TARGET_I386)
|
||||
/* simulate a real cpu exception. On i386, it can
|
||||
trigger new exceptions, but we do not handle
|
||||
double or triple faults yet. */
|
||||
do_interrupt(env->exception_index,
|
||||
env->exception_is_int,
|
||||
env->error_code,
|
||||
env->exception_next_eip);
|
||||
#endif
|
||||
}
|
||||
env->exception_index = -1;
|
||||
}
|
||||
T0 = 0; /* force lookup of first TB */
|
||||
for(;;) {
|
||||
#ifdef __sparc__
|
||||
/* g1 can be modified by some libc? functions */
|
||||
tmp_T0 = T0;
|
||||
#endif
|
||||
interrupt_request = env->interrupt_request;
|
||||
if (interrupt_request) {
|
||||
#if defined(TARGET_I386)
|
||||
/* if hardware interrupt pending, we execute it */
|
||||
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
|
||||
(env->eflags & IF_MASK)) {
|
||||
int intno;
|
||||
intno = cpu_x86_get_pic_interrupt(env);
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
|
||||
}
|
||||
do_interrupt(intno, 0, 0, 0);
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
|
||||
/* ensure that no TB jump will be modified as
|
||||
the program flow was changed */
|
||||
#ifdef __sparc__
|
||||
tmp_T0 = 0;
|
||||
#else
|
||||
T0 = 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
if (interrupt_request & CPU_INTERRUPT_EXIT) {
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
|
||||
env->exception_index = EXCP_INTERRUPT;
|
||||
cpu_loop_exit();
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_EXEC
|
||||
if (loglevel) {
|
||||
#if defined(TARGET_I386)
|
||||
/* restore flags in standard format */
|
||||
env->regs[R_EAX] = EAX;
|
||||
env->regs[R_EBX] = EBX;
|
||||
env->regs[R_ECX] = ECX;
|
||||
env->regs[R_EDX] = EDX;
|
||||
env->regs[R_ESI] = ESI;
|
||||
env->regs[R_EDI] = EDI;
|
||||
env->regs[R_EBP] = EBP;
|
||||
env->regs[R_ESP] = ESP;
|
||||
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
|
||||
cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
|
||||
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||
#elif defined(TARGET_ARM)
|
||||
cpu_arm_dump_state(env, logfile, 0);
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
/* we compute the CPU state. We assume it will not
|
||||
change during the whole generated block. */
|
||||
#if defined(TARGET_I386)
|
||||
flags = (env->segs[R_CS].flags & DESC_B_MASK)
|
||||
>> (DESC_B_SHIFT - GEN_FLAG_CODE32_SHIFT);
|
||||
flags |= (env->segs[R_SS].flags & DESC_B_MASK)
|
||||
>> (DESC_B_SHIFT - GEN_FLAG_SS32_SHIFT);
|
||||
flags |= (((unsigned long)env->segs[R_DS].base |
|
||||
(unsigned long)env->segs[R_ES].base |
|
||||
(unsigned long)env->segs[R_SS].base) != 0) <<
|
||||
GEN_FLAG_ADDSEG_SHIFT;
|
||||
if (!(env->eflags & VM_MASK)) {
|
||||
flags |= (env->segs[R_CS].selector & 3) << GEN_FLAG_CPL_SHIFT;
|
||||
} else {
|
||||
/* NOTE: a dummy CPL is kept */
|
||||
flags |= (1 << GEN_FLAG_VM_SHIFT);
|
||||
flags |= (3 << GEN_FLAG_CPL_SHIFT);
|
||||
}
|
||||
flags |= (env->eflags & (IOPL_MASK | TF_MASK));
|
||||
cs_base = env->segs[R_CS].base;
|
||||
pc = cs_base + env->eip;
|
||||
#elif defined(TARGET_ARM)
|
||||
flags = 0;
|
||||
cs_base = 0;
|
||||
pc = (uint8_t *)env->regs[15];
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
|
||||
flags);
|
||||
if (!tb) {
|
||||
spin_lock(&tb_lock);
|
||||
/* if no translated code available, then translate it now */
|
||||
tb = tb_alloc((unsigned long)pc);
|
||||
if (!tb) {
|
||||
/* flush must be done */
|
||||
tb_flush();
|
||||
/* cannot fail at this point */
|
||||
tb = tb_alloc((unsigned long)pc);
|
||||
/* don't forget to invalidate previous TB info */
|
||||
ptb = &tb_hash[tb_hash_func((unsigned long)pc)];
|
||||
T0 = 0;
|
||||
}
|
||||
tc_ptr = code_gen_ptr;
|
||||
tb->tc_ptr = tc_ptr;
|
||||
tb->cs_base = (unsigned long)cs_base;
|
||||
tb->flags = flags;
|
||||
ret = cpu_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size);
|
||||
#if defined(TARGET_I386)
|
||||
/* XXX: suppress that, this is incorrect */
|
||||
/* if invalid instruction, signal it */
|
||||
if (ret != 0) {
|
||||
/* NOTE: the tb is allocated but not linked, so we
|
||||
can leave it */
|
||||
spin_unlock(&tb_lock);
|
||||
raise_exception(EXCP06_ILLOP);
|
||||
}
|
||||
#endif
|
||||
*ptb = tb;
|
||||
tb->hash_next = NULL;
|
||||
tb_link(tb);
|
||||
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
|
||||
spin_unlock(&tb_lock);
|
||||
}
|
||||
#ifdef DEBUG_EXEC
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
|
||||
(long)tb->tc_ptr, (long)tb->pc,
|
||||
lookup_symbol((void *)tb->pc));
|
||||
}
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
T0 = tmp_T0;
|
||||
#endif
|
||||
/* see if we can patch the calling TB. XXX: remove TF test */
|
||||
if (T0 != 0
|
||||
#if defined(TARGET_I386)
|
||||
&& !(env->eflags & TF_MASK)
|
||||
#endif
|
||||
) {
|
||||
spin_lock(&tb_lock);
|
||||
tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
|
||||
spin_unlock(&tb_lock);
|
||||
}
|
||||
tc_ptr = tb->tc_ptr;
|
||||
env->current_tb = tb;
|
||||
/* execute the generated code */
|
||||
gen_func = (void *)tc_ptr;
|
||||
#if defined(__sparc__)
|
||||
__asm__ __volatile__("call %0\n\t"
|
||||
"mov %%o7,%%i0"
|
||||
: /* no outputs */
|
||||
: "r" (gen_func)
|
||||
: "i0", "i1", "i2", "i3", "i4", "i5");
|
||||
#elif defined(__arm__)
|
||||
asm volatile ("mov pc, %0\n\t"
|
||||
".global exec_loop\n\t"
|
||||
"exec_loop:\n\t"
|
||||
: /* no outputs */
|
||||
: "r" (gen_func)
|
||||
: "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
|
||||
#else
|
||||
gen_func();
|
||||
#endif
|
||||
env->current_tb = NULL;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
} /* for(;;) */
|
||||
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
/* restore flags in standard format */
|
||||
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
|
||||
|
||||
/* restore global registers */
|
||||
#ifdef reg_EAX
|
||||
EAX = saved_EAX;
|
||||
#endif
|
||||
#ifdef reg_ECX
|
||||
ECX = saved_ECX;
|
||||
#endif
|
||||
#ifdef reg_EDX
|
||||
EDX = saved_EDX;
|
||||
#endif
|
||||
#ifdef reg_EBX
|
||||
EBX = saved_EBX;
|
||||
#endif
|
||||
#ifdef reg_ESP
|
||||
ESP = saved_ESP;
|
||||
#endif
|
||||
#ifdef reg_EBP
|
||||
EBP = saved_EBP;
|
||||
#endif
|
||||
#ifdef reg_ESI
|
||||
ESI = saved_ESI;
|
||||
#endif
|
||||
#ifdef reg_EDI
|
||||
EDI = saved_EDI;
|
||||
#endif
|
||||
#elif defined(TARGET_ARM)
|
||||
{
|
||||
int ZF;
|
||||
ZF = (env->NZF == 0);
|
||||
env->cpsr = env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) |
|
||||
(env->CF << 29) | ((env->VF & 0x80000000) >> 3);
|
||||
}
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
|
||||
#endif
|
||||
T0 = saved_T0;
|
||||
T1 = saved_T1;
|
||||
T2 = saved_T2;
|
||||
env = saved_env;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
|
||||
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
|
||||
{
|
||||
CPUX86State *saved_env;
|
||||
|
||||
saved_env = env;
|
||||
env = s;
|
||||
if (env->eflags & VM_MASK) {
|
||||
SegmentCache *sc;
|
||||
selector &= 0xffff;
|
||||
sc = &env->segs[seg_reg];
|
||||
/* NOTE: in VM86 mode, limit and flags are never reloaded,
|
||||
so we must load them here */
|
||||
sc->base = (void *)(selector << 4);
|
||||
sc->limit = 0xffff;
|
||||
sc->flags = 0;
|
||||
sc->selector = selector;
|
||||
} else {
|
||||
load_seg(seg_reg, selector, 0);
|
||||
}
|
||||
env = saved_env;
|
||||
}
|
||||
|
||||
void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32)
|
||||
{
|
||||
CPUX86State *saved_env;
|
||||
|
||||
saved_env = env;
|
||||
env = s;
|
||||
|
||||
helper_fsave(ptr, data32);
|
||||
|
||||
env = saved_env;
|
||||
}
|
||||
|
||||
void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
|
||||
{
|
||||
CPUX86State *saved_env;
|
||||
|
||||
saved_env = env;
|
||||
env = s;
|
||||
|
||||
helper_frstor(ptr, data32);
|
||||
|
||||
env = saved_env;
|
||||
}
|
||||
|
||||
#endif /* TARGET_I386 */
|
||||
|
||||
#undef EAX
|
||||
#undef ECX
|
||||
#undef EDX
|
||||
#undef EBX
|
||||
#undef ESP
|
||||
#undef EBP
|
||||
#undef ESI
|
||||
#undef EDI
|
||||
#undef EIP
|
||||
#include <signal.h>
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
|
||||
/* 'pc' is the host PC at which the exception was raised. 'address' is
|
||||
the effective address of the memory exception. 'is_write' is 1 if a
|
||||
write caused the exception and otherwise 0'. 'old_set' is the
|
||||
signal set which should be restored */
|
||||
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
int is_write, sigset_t *old_set)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
int ret;
|
||||
|
||||
if (cpu_single_env)
|
||||
env = cpu_single_env; /* XXX: find a correct solution for multithread */
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
|
||||
pc, address, is_write, *(unsigned long *)old_set);
|
||||
#endif
|
||||
/* XXX: locking issue */
|
||||
if (is_write && page_unprotect(address)) {
|
||||
return 1;
|
||||
}
|
||||
/* see if it is an MMU fault */
|
||||
ret = cpu_x86_handle_mmu_fault(env, address, is_write);
|
||||
if (ret < 0)
|
||||
return 0; /* not an MMU fault */
|
||||
if (ret == 0)
|
||||
return 1; /* the MMU fault was handled without causing real CPU fault */
|
||||
/* now we have a real cpu fault */
|
||||
tb = tb_find_pc(pc);
|
||||
if (tb) {
|
||||
/* the PC is inside the translated code. It means that we have
|
||||
a virtual CPU fault */
|
||||
cpu_restore_state(tb, env, pc);
|
||||
}
|
||||
#if 0
|
||||
printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
|
||||
env->eip, env->cr[2], env->error_code);
|
||||
#endif
|
||||
/* we restore the process signal mask as the sigreturn should
|
||||
do it (XXX: use sigsetjmp) */
|
||||
sigprocmask(SIG_SETMASK, old_set, NULL);
|
||||
raise_exception_err(EXCP0E_PAGE, env->error_code);
|
||||
/* never comes here */
|
||||
return 1;
|
||||
}
|
||||
|
||||
#elif defined(TARGET_ARM)
|
||||
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
int is_write, sigset_t *old_set)
|
||||
{
|
||||
/* XXX: do more */
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc)
|
||||
{
|
||||
struct ucontext *uc = puc;
|
||||
unsigned long pc;
|
||||
|
||||
#ifndef REG_EIP
|
||||
/* for glibc 2.1 */
|
||||
#define REG_EIP EIP
|
||||
#define REG_ERR ERR
|
||||
#define REG_TRAPNO TRAPNO
|
||||
#endif
|
||||
pc = uc->uc_mcontext.gregs[REG_EIP];
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
|
||||
(uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
|
||||
&uc->uc_sigmask);
|
||||
}
|
||||
|
||||
#elif defined(__powerpc)
|
||||
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc)
|
||||
{
|
||||
struct ucontext *uc = puc;
|
||||
struct pt_regs *regs = uc->uc_mcontext.regs;
|
||||
unsigned long pc;
|
||||
int is_write;
|
||||
|
||||
pc = regs->nip;
|
||||
is_write = 0;
|
||||
#if 0
|
||||
/* ppc 4xx case */
|
||||
if (regs->dsisr & 0x00800000)
|
||||
is_write = 1;
|
||||
#else
|
||||
if (regs->trap != 0x400 && (regs->dsisr & 0x02000000))
|
||||
is_write = 1;
|
||||
#endif
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
is_write, &uc->uc_sigmask);
|
||||
}
|
||||
|
||||
#elif defined(__alpha__)
|
||||
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc)
|
||||
{
|
||||
struct ucontext *uc = puc;
|
||||
uint32_t *pc = uc->uc_mcontext.sc_pc;
|
||||
uint32_t insn = *pc;
|
||||
int is_write = 0;
|
||||
|
||||
/* XXX: need kernel patch to get write flag faster */
|
||||
switch (insn >> 26) {
|
||||
case 0x0d: // stw
|
||||
case 0x0e: // stb
|
||||
case 0x0f: // stq_u
|
||||
case 0x24: // stf
|
||||
case 0x25: // stg
|
||||
case 0x26: // sts
|
||||
case 0x27: // stt
|
||||
case 0x2c: // stl
|
||||
case 0x2d: // stq
|
||||
case 0x2e: // stl_c
|
||||
case 0x2f: // stq_c
|
||||
is_write = 1;
|
||||
}
|
||||
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
is_write, &uc->uc_sigmask);
|
||||
}
|
||||
#elif defined(__sparc__)
|
||||
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc)
|
||||
{
|
||||
uint32_t *regs = (uint32_t *)(info + 1);
|
||||
void *sigmask = (regs + 20);
|
||||
unsigned long pc;
|
||||
int is_write;
|
||||
uint32_t insn;
|
||||
|
||||
/* XXX: is there a standard glibc define ? */
|
||||
pc = regs[1];
|
||||
/* XXX: need kernel patch to get write flag faster */
|
||||
is_write = 0;
|
||||
insn = *(uint32_t *)pc;
|
||||
if ((insn >> 30) == 3) {
|
||||
switch((insn >> 19) & 0x3f) {
|
||||
case 0x05: // stb
|
||||
case 0x06: // sth
|
||||
case 0x04: // st
|
||||
case 0x07: // std
|
||||
case 0x24: // stf
|
||||
case 0x27: // stdf
|
||||
case 0x25: // stfsr
|
||||
is_write = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
is_write, sigmask);
|
||||
}
|
||||
|
||||
#elif defined(__arm__)
|
||||
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc)
|
||||
{
|
||||
struct ucontext *uc = puc;
|
||||
unsigned long pc;
|
||||
int is_write;
|
||||
|
||||
pc = uc->uc_mcontext.gregs[R15];
|
||||
/* XXX: compute is_write */
|
||||
is_write = 0;
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
is_write,
|
||||
&uc->uc_sigmask);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error host CPU specific signal handler needed
|
||||
|
||||
#endif
|
||||
+118
-232
@@ -48,6 +48,24 @@
|
||||
#define R_FS 4
|
||||
#define R_GS 5
|
||||
|
||||
/* segment descriptor fields */
|
||||
#define DESC_G_MASK (1 << 23)
|
||||
#define DESC_B_SHIFT 22
|
||||
#define DESC_B_MASK (1 << DESC_B_SHIFT)
|
||||
#define DESC_AVL_MASK (1 << 20)
|
||||
#define DESC_P_MASK (1 << 15)
|
||||
#define DESC_DPL_SHIFT 13
|
||||
#define DESC_S_MASK (1 << 12)
|
||||
#define DESC_TYPE_SHIFT 8
|
||||
#define DESC_A_MASK (1 << 8)
|
||||
|
||||
#define DESC_CS_MASK (1 << 11)
|
||||
#define DESC_C_MASK (1 << 10)
|
||||
#define DESC_R_MASK (1 << 9)
|
||||
|
||||
#define DESC_E_MASK (1 << 10)
|
||||
#define DESC_W_MASK (1 << 9)
|
||||
|
||||
/* eflags masks */
|
||||
#define CC_C 0x0001
|
||||
#define CC_P 0x0004
|
||||
@@ -68,6 +86,54 @@
|
||||
#define VIP_MASK 0x00100000
|
||||
#define ID_MASK 0x00200000
|
||||
|
||||
#define CR0_PE_MASK (1 << 0)
|
||||
#define CR0_TS_MASK (1 << 3)
|
||||
#define CR0_WP_MASK (1 << 16)
|
||||
#define CR0_AM_MASK (1 << 18)
|
||||
#define CR0_PG_MASK (1 << 31)
|
||||
|
||||
#define CR4_VME_MASK (1 << 0)
|
||||
#define CR4_PVI_MASK (1 << 1)
|
||||
#define CR4_TSD_MASK (1 << 2)
|
||||
#define CR4_DE_MASK (1 << 3)
|
||||
#define CR4_PSE_MASK (1 << 4)
|
||||
|
||||
#define PG_PRESENT_BIT 0
|
||||
#define PG_RW_BIT 1
|
||||
#define PG_USER_BIT 2
|
||||
#define PG_PWT_BIT 3
|
||||
#define PG_PCD_BIT 4
|
||||
#define PG_ACCESSED_BIT 5
|
||||
#define PG_DIRTY_BIT 6
|
||||
#define PG_PSE_BIT 7
|
||||
#define PG_GLOBAL_BIT 8
|
||||
|
||||
#define PG_PRESENT_MASK (1 << PG_PRESENT_BIT)
|
||||
#define PG_RW_MASK (1 << PG_RW_BIT)
|
||||
#define PG_USER_MASK (1 << PG_USER_BIT)
|
||||
#define PG_PWT_MASK (1 << PG_PWT_BIT)
|
||||
#define PG_PCD_MASK (1 << PG_PCD_BIT)
|
||||
#define PG_ACCESSED_MASK (1 << PG_ACCESSED_BIT)
|
||||
#define PG_DIRTY_MASK (1 << PG_DIRTY_BIT)
|
||||
#define PG_PSE_MASK (1 << PG_PSE_BIT)
|
||||
#define PG_GLOBAL_MASK (1 << PG_GLOBAL_BIT)
|
||||
|
||||
#define PG_ERROR_W_BIT 1
|
||||
|
||||
#define PG_ERROR_P_MASK 0x01
|
||||
#define PG_ERROR_W_MASK (1 << PG_ERROR_W_BIT)
|
||||
#define PG_ERROR_U_MASK 0x04
|
||||
#define PG_ERROR_RSVD_MASK 0x08
|
||||
|
||||
#define MSR_IA32_APICBASE 0x1b
|
||||
#define MSR_IA32_APICBASE_BSP (1<<8)
|
||||
#define MSR_IA32_APICBASE_ENABLE (1<<11)
|
||||
#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
|
||||
|
||||
#define MSR_IA32_SYSENTER_CS 0x174
|
||||
#define MSR_IA32_SYSENTER_ESP 0x175
|
||||
#define MSR_IA32_SYSENTER_EIP 0x176
|
||||
|
||||
#define EXCP00_DIVZ 0
|
||||
#define EXCP01_SSTP 1
|
||||
#define EXCP02_NMI 2
|
||||
@@ -88,6 +154,7 @@
|
||||
#define EXCP12_MCHK 18
|
||||
|
||||
#define EXCP_INTERRUPT 256 /* async interruption */
|
||||
#define EXCP_HLT 257 /* hlt instruction reached */
|
||||
|
||||
enum {
|
||||
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
|
||||
@@ -144,26 +211,19 @@ typedef double CPU86_LDouble;
|
||||
#endif
|
||||
|
||||
typedef struct SegmentCache {
|
||||
uint32_t selector;
|
||||
uint8_t *base;
|
||||
unsigned long limit;
|
||||
uint8_t seg_32bit;
|
||||
uint32_t limit;
|
||||
uint32_t flags;
|
||||
} SegmentCache;
|
||||
|
||||
typedef struct SegmentDescriptorTable {
|
||||
uint8_t *base;
|
||||
unsigned long limit;
|
||||
/* this is the returned base when reading the register, just to
|
||||
avoid that the emulated program modifies it */
|
||||
unsigned long emu_base;
|
||||
} SegmentDescriptorTable;
|
||||
|
||||
typedef struct CPUX86State {
|
||||
/* standard registers */
|
||||
uint32_t regs[8];
|
||||
uint32_t eip;
|
||||
uint32_t eflags; /* eflags register. During CPU emulation, CC
|
||||
flags and DF are set to zero because they are
|
||||
store elsewhere */
|
||||
stored elsewhere */
|
||||
|
||||
/* emulator internal eflags handling */
|
||||
uint32_t cc_src;
|
||||
@@ -180,237 +240,62 @@ typedef struct CPUX86State {
|
||||
|
||||
/* emulator internal variables */
|
||||
CPU86_LDouble ft0;
|
||||
union {
|
||||
float f;
|
||||
double d;
|
||||
int i32;
|
||||
int64_t i64;
|
||||
} fp_convert;
|
||||
|
||||
/* segments */
|
||||
uint32_t segs[6]; /* selector values */
|
||||
SegmentCache seg_cache[6]; /* info taken from LDT/GDT */
|
||||
SegmentDescriptorTable gdt;
|
||||
SegmentDescriptorTable ldt;
|
||||
SegmentDescriptorTable idt;
|
||||
SegmentCache segs[6]; /* selector values */
|
||||
SegmentCache ldt;
|
||||
SegmentCache tr;
|
||||
SegmentCache gdt; /* only base and limit are used */
|
||||
SegmentCache idt; /* only base and limit are used */
|
||||
|
||||
/* sysenter registers */
|
||||
uint32_t sysenter_cs;
|
||||
uint32_t sysenter_esp;
|
||||
uint32_t sysenter_eip;
|
||||
|
||||
/* exception/interrupt handling */
|
||||
jmp_buf jmp_env;
|
||||
int exception_index;
|
||||
int interrupt_request;
|
||||
|
||||
int error_code;
|
||||
int exception_is_int;
|
||||
int exception_next_eip;
|
||||
struct TranslationBlock *current_tb; /* currently executing TB */
|
||||
uint32_t cr[5]; /* NOTE: cr1 is unused */
|
||||
uint32_t dr[8]; /* debug registers */
|
||||
int interrupt_request;
|
||||
int user_mode_only; /* user mode only simulation */
|
||||
|
||||
/* user data */
|
||||
void *opaque;
|
||||
} CPUX86State;
|
||||
|
||||
/* all CPU memory access use these macros */
|
||||
static inline int ldub(void *ptr)
|
||||
{
|
||||
return *(uint8_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldsb(void *ptr)
|
||||
{
|
||||
return *(int8_t *)ptr;
|
||||
}
|
||||
|
||||
static inline void stb(void *ptr, int v)
|
||||
{
|
||||
*(uint8_t *)ptr = v;
|
||||
}
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
|
||||
/* conservative code for little endian unaligned accesses */
|
||||
static inline int lduw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
||||
return val;
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
return p[0] | (p[1] << 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ldsw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
||||
return (int16_t)val;
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
return (int16_t)(p[0] | (p[1] << 8));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ldl(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
__asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
||||
return val;
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t ldq(void *ptr)
|
||||
{
|
||||
uint8_t *p = ptr;
|
||||
uint32_t v1, v2;
|
||||
v1 = ldl(p);
|
||||
v2 = ldl(p + 4);
|
||||
return v1 | ((uint64_t)v2 << 32);
|
||||
}
|
||||
|
||||
static inline void stw(void *ptr, int v)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
p[0] = v;
|
||||
p[1] = v >> 8;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void stl(void *ptr, int v)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
p[0] = v;
|
||||
p[1] = v >> 8;
|
||||
p[2] = v >> 16;
|
||||
p[3] = v >> 24;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void stq(void *ptr, uint64_t v)
|
||||
{
|
||||
uint8_t *p = ptr;
|
||||
stl(p, (uint32_t)v);
|
||||
stl(p + 4, v >> 32);
|
||||
}
|
||||
|
||||
/* float access */
|
||||
|
||||
static inline float ldfl(void *ptr)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.i = ldl(ptr);
|
||||
return u.f;
|
||||
}
|
||||
|
||||
static inline double ldfq(void *ptr)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
u.i = ldq(ptr);
|
||||
return u.d;
|
||||
}
|
||||
|
||||
static inline void stfl(void *ptr, float v)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.f = v;
|
||||
stl(ptr, u.i);
|
||||
}
|
||||
|
||||
static inline void stfq(void *ptr, double v)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
u.d = v;
|
||||
stq(ptr, u.i);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline int lduw(void *ptr)
|
||||
{
|
||||
return *(uint16_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldsw(void *ptr)
|
||||
{
|
||||
return *(int16_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldl(void *ptr)
|
||||
{
|
||||
return *(uint32_t *)ptr;
|
||||
}
|
||||
|
||||
static inline uint64_t ldq(void *ptr)
|
||||
{
|
||||
return *(uint64_t *)ptr;
|
||||
}
|
||||
|
||||
static inline void stw(void *ptr, int v)
|
||||
{
|
||||
*(uint16_t *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stl(void *ptr, int v)
|
||||
{
|
||||
*(uint32_t *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stq(void *ptr, uint64_t v)
|
||||
{
|
||||
*(uint64_t *)ptr = v;
|
||||
}
|
||||
|
||||
/* float access */
|
||||
|
||||
static inline float ldfl(void *ptr)
|
||||
{
|
||||
return *(float *)ptr;
|
||||
}
|
||||
|
||||
static inline double ldfq(void *ptr)
|
||||
{
|
||||
return *(double *)ptr;
|
||||
}
|
||||
|
||||
static inline void stfl(void *ptr, float v)
|
||||
{
|
||||
*(float *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stfq(void *ptr, double v)
|
||||
{
|
||||
*(double *)ptr = v;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef IN_OP_I386
|
||||
void cpu_x86_outb(int addr, int val);
|
||||
void cpu_x86_outw(int addr, int val);
|
||||
void cpu_x86_outl(int addr, int val);
|
||||
int cpu_x86_inb(int addr);
|
||||
int cpu_x86_inw(int addr);
|
||||
int cpu_x86_inl(int addr);
|
||||
void cpu_x86_outb(CPUX86State *env, int addr, int val);
|
||||
void cpu_x86_outw(CPUX86State *env, int addr, int val);
|
||||
void cpu_x86_outl(CPUX86State *env, int addr, int val);
|
||||
int cpu_x86_inb(CPUX86State *env, int addr);
|
||||
int cpu_x86_inw(CPUX86State *env, int addr);
|
||||
int cpu_x86_inl(CPUX86State *env, int addr);
|
||||
#endif
|
||||
|
||||
CPUX86State *cpu_x86_init(void);
|
||||
int cpu_x86_exec(CPUX86State *s);
|
||||
void cpu_x86_interrupt(CPUX86State *s);
|
||||
void cpu_x86_close(CPUX86State *s);
|
||||
int cpu_x86_get_pic_interrupt(CPUX86State *s);
|
||||
|
||||
/* needed to load some predefinied segment registers */
|
||||
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector);
|
||||
|
||||
/* simulate fsave/frstor */
|
||||
void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32);
|
||||
void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32);
|
||||
|
||||
/* you can call this signal handler from your SIGBUS and SIGSEGV
|
||||
signal handlers to inform the virtual CPU of exceptions. non zero
|
||||
is returned if the signal was handled by the virtual CPU. */
|
||||
@@ -418,17 +303,18 @@ struct siginfo;
|
||||
int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc);
|
||||
|
||||
/* internal functions */
|
||||
/* MMU defines */
|
||||
void cpu_x86_init_mmu(CPUX86State *env);
|
||||
extern int phys_ram_size;
|
||||
extern int phys_ram_fd;
|
||||
extern uint8_t *phys_ram_base;
|
||||
|
||||
#define GEN_FLAG_CODE32_SHIFT 0
|
||||
#define GEN_FLAG_ADDSEG_SHIFT 1
|
||||
#define GEN_FLAG_SS32_SHIFT 2
|
||||
#define GEN_FLAG_VM_SHIFT 3
|
||||
#define GEN_FLAG_ST_SHIFT 4
|
||||
/* used to debug */
|
||||
#define X86_DUMP_FPU 0x0001 /* dump FPU state too */
|
||||
#define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */
|
||||
void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags);
|
||||
|
||||
int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
|
||||
int *gen_code_size_ptr,
|
||||
uint8_t *pc_start, uint8_t *cs_base, int flags);
|
||||
void cpu_x86_tblocks_init(void);
|
||||
#define TARGET_PAGE_BITS 12
|
||||
#include "cpu-all.h"
|
||||
|
||||
#endif /* CPU_I386_H */
|
||||
@@ -73,16 +73,20 @@ enum bfd_architecture
|
||||
bfd_arch_a29k, /* AMD 29000 */
|
||||
bfd_arch_sparc, /* SPARC */
|
||||
#define bfd_mach_sparc 1
|
||||
/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */
|
||||
/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */
|
||||
#define bfd_mach_sparc_sparclet 2
|
||||
#define bfd_mach_sparc_sparclite 3
|
||||
#define bfd_mach_sparc_v8plus 4
|
||||
#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns */
|
||||
#define bfd_mach_sparc_v9 6
|
||||
#define bfd_mach_sparc_v9a 7 /* with ultrasparc add'ns */
|
||||
/* Nonzero if MACH has the v9 instruction set. */
|
||||
#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns. */
|
||||
#define bfd_mach_sparc_sparclite_le 6
|
||||
#define bfd_mach_sparc_v9 7
|
||||
#define bfd_mach_sparc_v9a 8 /* with ultrasparc add'ns. */
|
||||
#define bfd_mach_sparc_v8plusb 9 /* with cheetah add'ns. */
|
||||
#define bfd_mach_sparc_v9b 10 /* with cheetah add'ns. */
|
||||
/* Nonzero if MACH has the v9 instruction set. */
|
||||
#define bfd_mach_sparc_v9_p(mach) \
|
||||
((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9a)
|
||||
((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \
|
||||
&& (mach) != bfd_mach_sparc_sparclite_le)
|
||||
bfd_arch_mips, /* MIPS Rxxxx */
|
||||
#define bfd_mach_mips3000 3000
|
||||
#define bfd_mach_mips3900 3900
|
||||
@@ -279,6 +283,9 @@ typedef struct disassemble_info {
|
||||
zero if unknown. */
|
||||
bfd_vma target2; /* Second target address for dref2 */
|
||||
|
||||
/* Command line options specific to the target disassembler. */
|
||||
char * disassembler_options;
|
||||
|
||||
} disassemble_info;
|
||||
|
||||
|
||||
@@ -299,8 +306,7 @@ extern int print_insn_h8300s PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_h8500 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern disassembler_ftype arc_get_disassembler PARAMS ((int, int));
|
||||
extern int print_insn_big_arm PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_little_arm PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_arm PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_sparc PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_big_a29k PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_little_a29k PARAMS ((bfd_vma, disassemble_info*));
|
||||
@@ -320,6 +326,7 @@ extern int print_insn_w65 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_d10v PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_v850 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_ppc PARAMS ((bfd_vma, disassemble_info*));
|
||||
|
||||
#if 0
|
||||
/* Fetch the disassembler for a given BFD, if that support is available. */
|
||||
@@ -380,6 +387,15 @@ extern int generic_symbol_at_address
|
||||
(INFO).bytes_per_line = 0, \
|
||||
(INFO).bytes_per_chunk = 0, \
|
||||
(INFO).display_endian = BFD_ENDIAN_UNKNOWN, \
|
||||
(INFO).disassembler_options = NULL, \
|
||||
(INFO).insn_info_valid = 0
|
||||
|
||||
#define _(x) x
|
||||
|
||||
/* from libbfd */
|
||||
|
||||
bfd_vma bfd_getl32 (const bfd_byte *addr);
|
||||
bfd_vma bfd_getb32 (const bfd_byte *addr);
|
||||
typedef enum bfd_boolean {false, true} boolean;
|
||||
|
||||
#endif /* ! defined (DIS_ASM_H) */
|
||||
@@ -1,79 +0,0 @@
|
||||
/* Disassemble from a buffer, for GNU.
|
||||
Copyright (C) 1993, 1994 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "dis-asm.h"
|
||||
#include <errno.h>
|
||||
|
||||
/* Get LENGTH bytes from info's buffer, at target address memaddr.
|
||||
Transfer them to myaddr. */
|
||||
int
|
||||
buffer_read_memory (memaddr, myaddr, length, info)
|
||||
bfd_vma memaddr;
|
||||
bfd_byte *myaddr;
|
||||
int length;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
if (memaddr < info->buffer_vma
|
||||
|| memaddr + length > info->buffer_vma + info->buffer_length)
|
||||
/* Out of bounds. Use EIO because GDB uses it. */
|
||||
return EIO;
|
||||
memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Print an error message. We can assume that this is in response to
|
||||
an error return from buffer_read_memory. */
|
||||
void
|
||||
perror_memory (status, memaddr, info)
|
||||
int status;
|
||||
bfd_vma memaddr;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
if (status != EIO)
|
||||
/* Can't happen. */
|
||||
(*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
|
||||
else
|
||||
/* Actually, address between memaddr and memaddr + len was
|
||||
out of bounds. */
|
||||
(*info->fprintf_func) (info->stream,
|
||||
"Address 0x%x is out of bounds.\n", memaddr);
|
||||
}
|
||||
|
||||
/* This could be in a separate file, to save miniscule amounts of space
|
||||
in statically linked executables. */
|
||||
|
||||
/* Just print the address is hex. This is included for completeness even
|
||||
though both GDB and objdump provide their own (to print symbolic
|
||||
addresses). */
|
||||
|
||||
void
|
||||
generic_print_address (addr, info)
|
||||
bfd_vma addr;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
(*info->fprintf_func) (info->stream, "0x%x", addr);
|
||||
}
|
||||
|
||||
/* Just return the given address. */
|
||||
|
||||
int
|
||||
generic_symbol_at_address (addr, info)
|
||||
bfd_vma addr;
|
||||
struct disassemble_info * info;
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/* General "disassemble this chunk" code. Used for debugging. */
|
||||
#include "config.h"
|
||||
#include "dis-asm.h"
|
||||
#include "disas.h"
|
||||
#include "elf.h"
|
||||
#include <errno.h>
|
||||
|
||||
/* Filled in by elfload.c. Simplistic, but will do for now. */
|
||||
unsigned int disas_num_syms;
|
||||
void *disas_symtab;
|
||||
const char *disas_strtab;
|
||||
|
||||
/* Get LENGTH bytes from info's buffer, at target address memaddr.
|
||||
Transfer them to myaddr. */
|
||||
int
|
||||
buffer_read_memory (memaddr, myaddr, length, info)
|
||||
bfd_vma memaddr;
|
||||
bfd_byte *myaddr;
|
||||
int length;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
if (memaddr < info->buffer_vma
|
||||
|| memaddr + length > info->buffer_vma + info->buffer_length)
|
||||
/* Out of bounds. Use EIO because GDB uses it. */
|
||||
return EIO;
|
||||
memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Print an error message. We can assume that this is in response to
|
||||
an error return from buffer_read_memory. */
|
||||
void
|
||||
perror_memory (status, memaddr, info)
|
||||
int status;
|
||||
bfd_vma memaddr;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
if (status != EIO)
|
||||
/* Can't happen. */
|
||||
(*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
|
||||
else
|
||||
/* Actually, address between memaddr and memaddr + len was
|
||||
out of bounds. */
|
||||
(*info->fprintf_func) (info->stream,
|
||||
"Address 0x%x is out of bounds.\n", memaddr);
|
||||
}
|
||||
|
||||
/* This could be in a separate file, to save miniscule amounts of space
|
||||
in statically linked executables. */
|
||||
|
||||
/* Just print the address is hex. This is included for completeness even
|
||||
though both GDB and objdump provide their own (to print symbolic
|
||||
addresses). */
|
||||
|
||||
void
|
||||
generic_print_address (addr, info)
|
||||
bfd_vma addr;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
(*info->fprintf_func) (info->stream, "0x%x", addr);
|
||||
}
|
||||
|
||||
/* Just return the given address. */
|
||||
|
||||
int
|
||||
generic_symbol_at_address (addr, info)
|
||||
bfd_vma addr;
|
||||
struct disassemble_info * info;
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
bfd_vma bfd_getl32 (const bfd_byte *addr)
|
||||
{
|
||||
unsigned long v;
|
||||
|
||||
v = (unsigned long) addr[0];
|
||||
v |= (unsigned long) addr[1] << 8;
|
||||
v |= (unsigned long) addr[2] << 16;
|
||||
v |= (unsigned long) addr[3] << 24;
|
||||
return (bfd_vma) v;
|
||||
}
|
||||
|
||||
bfd_vma bfd_getb32 (const bfd_byte *addr)
|
||||
{
|
||||
unsigned long v;
|
||||
|
||||
v = (unsigned long) addr[0] << 24;
|
||||
v |= (unsigned long) addr[1] << 16;
|
||||
v |= (unsigned long) addr[2] << 8;
|
||||
v |= (unsigned long) addr[3];
|
||||
return (bfd_vma) v;
|
||||
}
|
||||
|
||||
/* Disassemble this for me please... (debugging). 'flags' is only used
|
||||
for i386: non zero means 16 bit code */
|
||||
void disas(FILE *out, void *code, unsigned long size, int is_host, int flags)
|
||||
{
|
||||
uint8_t *pc;
|
||||
int count;
|
||||
struct disassemble_info disasm_info;
|
||||
int (*print_insn)(bfd_vma pc, disassemble_info *info);
|
||||
|
||||
INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
|
||||
|
||||
disasm_info.buffer = code;
|
||||
disasm_info.buffer_vma = (unsigned long)code;
|
||||
disasm_info.buffer_length = size;
|
||||
|
||||
if (is_host) {
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
disasm_info.endian = BFD_ENDIAN_BIG;
|
||||
#else
|
||||
disasm_info.endian = BFD_ENDIAN_LITTLE;
|
||||
#endif
|
||||
#ifdef __i386__
|
||||
disasm_info.mach = bfd_mach_i386_i386;
|
||||
print_insn = print_insn_i386;
|
||||
#elif defined(__powerpc__)
|
||||
print_insn = print_insn_ppc;
|
||||
#elif defined(__alpha__)
|
||||
print_insn = print_insn_alpha;
|
||||
#elif defined(__sparc__)
|
||||
print_insn = print_insn_sparc;
|
||||
#elif defined(__arm__)
|
||||
print_insn = print_insn_arm;
|
||||
#else
|
||||
fprintf(out, "Asm output not supported on this arch\n");
|
||||
return;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
disasm_info.endian = BFD_ENDIAN_BIG;
|
||||
#else
|
||||
disasm_info.endian = BFD_ENDIAN_LITTLE;
|
||||
#endif
|
||||
#if defined(TARGET_I386)
|
||||
if (!flags)
|
||||
disasm_info.mach = bfd_mach_i386_i386;
|
||||
else
|
||||
disasm_info.mach = bfd_mach_i386_i8086;
|
||||
print_insn = print_insn_i386;
|
||||
#elif defined(TARGET_ARM)
|
||||
print_insn = print_insn_arm;
|
||||
#else
|
||||
fprintf(out, "Asm output not supported on this arch\n");
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
for (pc = code; pc < (uint8_t *)code + size; pc += count) {
|
||||
fprintf(out, "0x%08lx: ", (long)pc);
|
||||
#ifdef __arm__
|
||||
/* since data are included in the code, it is better to
|
||||
display code data too */
|
||||
if (is_host) {
|
||||
fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc));
|
||||
}
|
||||
#endif
|
||||
count = print_insn((unsigned long)pc, &disasm_info);
|
||||
fprintf(out, "\n");
|
||||
if (count < 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Look up symbol for debugging purpose. Returns "" if unknown. */
|
||||
const char *lookup_symbol(void *orig_addr)
|
||||
{
|
||||
unsigned int i;
|
||||
/* Hack, because we know this is x86. */
|
||||
Elf32_Sym *sym = disas_symtab;
|
||||
|
||||
for (i = 0; i < disas_num_syms; i++) {
|
||||
if (sym[i].st_shndx == SHN_UNDEF
|
||||
|| sym[i].st_shndx >= SHN_LORESERVE)
|
||||
continue;
|
||||
|
||||
if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC)
|
||||
continue;
|
||||
|
||||
if ((long)orig_addr >= sym[i].st_value
|
||||
&& (long)orig_addr < sym[i].st_value + sym[i].st_size)
|
||||
return disas_strtab + sym[i].st_name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef _QEMU_DISAS_H
|
||||
#define _QEMU_DISAS_H
|
||||
|
||||
/* Disassemble this for me please... (debugging). */
|
||||
void disas(FILE *out, void *code, unsigned long size, int is_host, int flags);
|
||||
|
||||
/* Look up symbol for debugging purpose. Returns "" if unknown. */
|
||||
const char *lookup_symbol(void *orig_addr);
|
||||
|
||||
/* Filled in by elfload.c. Simplistic, but will do for now. */
|
||||
extern unsigned int disas_num_syms;
|
||||
extern void *disas_symtab; /* FIXME: includes are a mess --RR */
|
||||
extern const char *disas_strtab;
|
||||
#endif /* _QEMU_DISAS_H */
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* dyngen defines for micro operation code
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef signed long long int64_t;
|
||||
|
||||
#define bswap32(x) \
|
||||
({ \
|
||||
uint32_t __x = (x); \
|
||||
((uint32_t)( \
|
||||
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
|
||||
})
|
||||
|
||||
typedef struct FILE FILE;
|
||||
extern int fprintf(FILE *, const char *, ...);
|
||||
extern int printf(const char *, ...);
|
||||
#define NULL 0
|
||||
#include <fenv.h>
|
||||
|
||||
#ifdef __i386__
|
||||
#define AREG0 "ebp"
|
||||
#define AREG1 "ebx"
|
||||
#define AREG2 "esi"
|
||||
#define AREG3 "edi"
|
||||
#endif
|
||||
#ifdef __powerpc__
|
||||
#define AREG0 "r27"
|
||||
#define AREG1 "r24"
|
||||
#define AREG2 "r25"
|
||||
#define AREG3 "r26"
|
||||
#define AREG4 "r16"
|
||||
#define AREG5 "r17"
|
||||
#define AREG6 "r18"
|
||||
#define AREG7 "r19"
|
||||
#define AREG8 "r20"
|
||||
#define AREG9 "r21"
|
||||
#define AREG10 "r22"
|
||||
#define AREG11 "r23"
|
||||
#define USE_INT_TO_FLOAT_HELPERS
|
||||
#define BUGGY_GCC_DIV64
|
||||
#endif
|
||||
#ifdef __arm__
|
||||
#define AREG0 "r7"
|
||||
#define AREG1 "r4"
|
||||
#define AREG2 "r5"
|
||||
#define AREG3 "r6"
|
||||
#endif
|
||||
#ifdef __mips__
|
||||
#define AREG0 "s3"
|
||||
#define AREG1 "s0"
|
||||
#define AREG2 "s1"
|
||||
#define AREG3 "s2"
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
#define AREG0 "g6"
|
||||
#define AREG1 "g1"
|
||||
#define AREG2 "g2"
|
||||
#define AREG3 "g3"
|
||||
#define AREG4 "l0"
|
||||
#define AREG5 "l1"
|
||||
#define AREG6 "l2"
|
||||
#define AREG7 "l3"
|
||||
#define AREG8 "l4"
|
||||
#define AREG9 "l5"
|
||||
#define AREG10 "l6"
|
||||
#define AREG11 "l7"
|
||||
#define USE_FP_CONVERT
|
||||
#endif
|
||||
#ifdef __s390__
|
||||
#define AREG0 "r10"
|
||||
#define AREG1 "r7"
|
||||
#define AREG2 "r8"
|
||||
#define AREG3 "r9"
|
||||
#endif
|
||||
#ifdef __alpha__
|
||||
/* Note $15 is the frame pointer, so anything in op-i386.c that would
|
||||
require a frame pointer, like alloca, would probably loose. */
|
||||
#define AREG0 "$15"
|
||||
#define AREG1 "$9"
|
||||
#define AREG2 "$10"
|
||||
#define AREG3 "$11"
|
||||
#define AREG4 "$12"
|
||||
#define AREG5 "$13"
|
||||
#define AREG6 "$14"
|
||||
#endif
|
||||
#ifdef __ia64__
|
||||
#define AREG0 "r27"
|
||||
#define AREG1 "r24"
|
||||
#define AREG2 "r25"
|
||||
#define AREG3 "r26"
|
||||
#endif
|
||||
|
||||
/* force GCC to generate only one epilog at the end of the function */
|
||||
#define FORCE_RET() asm volatile ("");
|
||||
|
||||
#ifndef OPPROTO
|
||||
#define OPPROTO
|
||||
#endif
|
||||
|
||||
#define xglue(x, y) x ## y
|
||||
#define glue(x, y) xglue(x, y)
|
||||
|
||||
#ifdef __alpha__
|
||||
/* the symbols are considered non exported so a br immediate is generated */
|
||||
#define __hidden __attribute__((visibility("hidden")))
|
||||
#else
|
||||
#define __hidden
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
/* Suggested by Richard Henderson. This will result in code like
|
||||
ldah $0,__op_param1($29) !gprelhigh
|
||||
lda $0,__op_param1($0) !gprellow
|
||||
We can then conveniently change $29 to $31 and adapt the offsets to
|
||||
emit the appropriate constant. */
|
||||
extern int __op_param1 __hidden;
|
||||
extern int __op_param2 __hidden;
|
||||
extern int __op_param3 __hidden;
|
||||
#define PARAM1 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param1)); _r; })
|
||||
#define PARAM2 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param2)); _r; })
|
||||
#define PARAM3 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param3)); _r; })
|
||||
#else
|
||||
extern int __op_param1, __op_param2, __op_param3;
|
||||
#define PARAM1 ((long)(&__op_param1))
|
||||
#define PARAM2 ((long)(&__op_param2))
|
||||
#define PARAM3 ((long)(&__op_param3))
|
||||
#endif
|
||||
|
||||
extern int __op_jmp0, __op_jmp1;
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* dyngen helpers
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
int __op_param1, __op_param2, __op_param3;
|
||||
int __op_jmp0, __op_jmp1;
|
||||
|
||||
#ifdef __i386__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __s390__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __ia64__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __powerpc__
|
||||
|
||||
#define MIN_CACHE_LINE_SIZE 8 /* conservative value */
|
||||
|
||||
static void inline flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
unsigned long p;
|
||||
|
||||
p = start & ~(MIN_CACHE_LINE_SIZE - 1);
|
||||
stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1);
|
||||
|
||||
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
|
||||
asm volatile ("dcbst 0,%0" : : "r"(p) : "memory");
|
||||
}
|
||||
asm volatile ("sync" : : : "memory");
|
||||
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
|
||||
asm volatile ("icbi 0,%0" : : "r"(p) : "memory");
|
||||
}
|
||||
asm volatile ("sync" : : : "memory");
|
||||
asm volatile ("isync" : : : "memory");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
asm ("imb");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __sparc__
|
||||
|
||||
static void inline flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
unsigned long p;
|
||||
|
||||
p = start & ~(8UL - 1UL);
|
||||
stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL);
|
||||
|
||||
for (; p < stop; p += 8)
|
||||
__asm__ __volatile__("flush\t%0" : : "r" (p));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __arm__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
register unsigned long _beg __asm ("a1") = start;
|
||||
register unsigned long _end __asm ("a2") = stop;
|
||||
register unsigned long _flg __asm ("a3") = 0;
|
||||
__asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
|
||||
register int gp asm("$29");
|
||||
|
||||
static inline void immediate_ldah(void *p, int val) {
|
||||
uint32_t *dest = p;
|
||||
long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff;
|
||||
|
||||
*dest &= ~0xffff;
|
||||
*dest |= high;
|
||||
*dest |= 31 << 16;
|
||||
}
|
||||
static inline void immediate_lda(void *dest, int val) {
|
||||
*(uint16_t *) dest = val;
|
||||
}
|
||||
void fix_bsr(void *p, int offset) {
|
||||
uint32_t *dest = p;
|
||||
*dest &= ~((1 << 21) - 1);
|
||||
*dest |= (offset >> 2) & ((1 << 21) - 1);
|
||||
}
|
||||
|
||||
#endif /* __alpha__ */
|
||||
|
||||
#ifdef __arm__
|
||||
|
||||
#define MAX_OP_SIZE (128 * 4) /* in bytes */
|
||||
/* max size of the code that can be generated without calling arm_flush_ldr */
|
||||
#define MAX_FRAG_SIZE (1024 * 4)
|
||||
//#define MAX_FRAG_SIZE (135 * 4) /* for testing */
|
||||
|
||||
typedef struct LDREntry {
|
||||
uint8_t *ptr;
|
||||
uint32_t *data_ptr;
|
||||
} LDREntry;
|
||||
|
||||
static LDREntry arm_ldr_table[1024];
|
||||
static uint32_t arm_data_table[1024];
|
||||
|
||||
extern char exec_loop;
|
||||
|
||||
static inline void arm_reloc_pc24(uint32_t *ptr, uint32_t insn, int val)
|
||||
{
|
||||
*ptr = (insn & ~0xffffff) | ((insn + ((val - (int)ptr) >> 2)) & 0xffffff);
|
||||
}
|
||||
|
||||
static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
|
||||
LDREntry *ldr_start, LDREntry *ldr_end,
|
||||
uint32_t *data_start, uint32_t *data_end,
|
||||
int gen_jmp)
|
||||
{
|
||||
LDREntry *le;
|
||||
uint32_t *ptr;
|
||||
int offset, data_size, target;
|
||||
uint8_t *data_ptr;
|
||||
uint32_t insn;
|
||||
|
||||
data_size = (uint8_t *)data_end - (uint8_t *)data_start;
|
||||
|
||||
if (!gen_jmp) {
|
||||
/* b exec_loop */
|
||||
arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, (long)(&exec_loop));
|
||||
gen_code_ptr += 4;
|
||||
} else {
|
||||
/* generate branch to skip the data */
|
||||
if (data_size == 0)
|
||||
return gen_code_ptr;
|
||||
target = (long)gen_code_ptr + data_size + 4;
|
||||
arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, target);
|
||||
gen_code_ptr += 4;
|
||||
}
|
||||
|
||||
/* copy the data */
|
||||
data_ptr = gen_code_ptr;
|
||||
memcpy(gen_code_ptr, data_start, data_size);
|
||||
gen_code_ptr += data_size;
|
||||
|
||||
/* patch the ldr to point to the data */
|
||||
for(le = ldr_start; le < ldr_end; le++) {
|
||||
ptr = (uint32_t *)le->ptr;
|
||||
offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) +
|
||||
(unsigned long)data_ptr -
|
||||
(unsigned long)ptr - 8;
|
||||
insn = *ptr & ~(0xfff | 0x00800000);
|
||||
if (offset < 0) {
|
||||
offset = - offset;
|
||||
} else {
|
||||
insn |= 0x00800000;
|
||||
}
|
||||
if (offset > 0xfff) {
|
||||
fprintf(stderr, "Error ldr offset\n");
|
||||
abort();
|
||||
}
|
||||
insn |= offset;
|
||||
*ptr = insn;
|
||||
}
|
||||
return gen_code_ptr;
|
||||
}
|
||||
|
||||
#endif /* __arm__ */
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef _ELF_H
|
||||
#define _ELF_H
|
||||
#ifndef _QEMU_ELF_H
|
||||
#define _QEMU_ELF_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
@@ -767,6 +767,114 @@ typedef struct {
|
||||
#define PF_HP_LAZYSWAP 0x04000000
|
||||
#define PF_HP_SBP 0x08000000
|
||||
|
||||
/* IA-64 specific declarations. */
|
||||
|
||||
/* Processor specific flags for the Ehdr e_flags field. */
|
||||
#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */
|
||||
#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */
|
||||
#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */
|
||||
|
||||
/* Processor specific values for the Phdr p_type field. */
|
||||
#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */
|
||||
#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */
|
||||
|
||||
/* Processor specific flags for the Phdr p_flags field. */
|
||||
#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */
|
||||
|
||||
/* Processor specific values for the Shdr sh_type field. */
|
||||
#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */
|
||||
#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */
|
||||
|
||||
/* Processor specific flags for the Shdr sh_flags field. */
|
||||
#define SHF_IA_64_SHORT 0x10000000 /* section near gp */
|
||||
#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */
|
||||
|
||||
/* Processor specific values for the Dyn d_tag field. */
|
||||
#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0)
|
||||
#define DT_IA_64_NUM 1
|
||||
|
||||
/* IA-64 relocations. */
|
||||
#define R_IA64_NONE 0x00 /* none */
|
||||
#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */
|
||||
#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */
|
||||
#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */
|
||||
#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */
|
||||
#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */
|
||||
#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */
|
||||
#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */
|
||||
#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */
|
||||
#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */
|
||||
#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */
|
||||
#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */
|
||||
#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */
|
||||
#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */
|
||||
#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */
|
||||
#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */
|
||||
#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */
|
||||
#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */
|
||||
#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */
|
||||
#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */
|
||||
#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */
|
||||
#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */
|
||||
#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */
|
||||
#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */
|
||||
#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */
|
||||
#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */
|
||||
#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */
|
||||
#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */
|
||||
#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */
|
||||
#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */
|
||||
#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */
|
||||
#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */
|
||||
#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */
|
||||
#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */
|
||||
#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */
|
||||
#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */
|
||||
#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */
|
||||
#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */
|
||||
#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */
|
||||
#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */
|
||||
#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */
|
||||
#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */
|
||||
#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */
|
||||
#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */
|
||||
#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */
|
||||
#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */
|
||||
#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */
|
||||
#define R_IA64_REL32MSB 0x6c /* data 4 + REL */
|
||||
#define R_IA64_REL32LSB 0x6d /* data 4 + REL */
|
||||
#define R_IA64_REL64MSB 0x6e /* data 8 + REL */
|
||||
#define R_IA64_REL64LSB 0x6f /* data 8 + REL */
|
||||
#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */
|
||||
#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */
|
||||
#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */
|
||||
#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */
|
||||
#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */
|
||||
#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */
|
||||
#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */
|
||||
#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */
|
||||
#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */
|
||||
#define R_IA64_COPY 0x84 /* copy relocation */
|
||||
#define R_IA64_SUB 0x85 /* Addend and symbol difference */
|
||||
#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */
|
||||
#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */
|
||||
#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */
|
||||
#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */
|
||||
#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */
|
||||
#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */
|
||||
#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */
|
||||
#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */
|
||||
#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */
|
||||
#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */
|
||||
#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */
|
||||
#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */
|
||||
#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */
|
||||
#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */
|
||||
#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */
|
||||
#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */
|
||||
#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */
|
||||
#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */
|
||||
#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */
|
||||
|
||||
typedef struct elf32_rel {
|
||||
Elf32_Addr r_offset;
|
||||
@@ -996,6 +1104,7 @@ typedef struct elf64_note {
|
||||
#define elf_phdr elf32_phdr
|
||||
#define elf_note elf32_note
|
||||
#define elf_shdr elf32_shdr
|
||||
#define elf_sym elf32_sym
|
||||
|
||||
#ifdef ELF_USES_RELOCA
|
||||
# define ELF_RELOC Elf32_Rela
|
||||
@@ -1009,6 +1118,7 @@ typedef struct elf64_note {
|
||||
#define elf_phdr elf64_phdr
|
||||
#define elf_note elf64_note
|
||||
#define elf_shdr elf64_shdr
|
||||
#define elf_sym elf64_sym
|
||||
|
||||
#ifdef ELF_USES_RELOCA
|
||||
# define ELF_RELOC Elf64_Rela
|
||||
@@ -1029,4 +1139,4 @@ typedef struct elf64_note {
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _ELF_H */
|
||||
#endif /* _QEMU_ELF_H */
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* ARM execution defines
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "dyngen-exec.h"
|
||||
|
||||
register struct CPUARMState *env asm(AREG0);
|
||||
register uint32_t T0 asm(AREG1);
|
||||
register uint32_t T1 asm(AREG2);
|
||||
register uint32_t T2 asm(AREG3);
|
||||
|
||||
#include "cpu-arm.h"
|
||||
#include "exec.h"
|
||||
|
||||
void cpu_lock(void);
|
||||
void cpu_unlock(void);
|
||||
void cpu_loop_exit(void);
|
||||
-514
@@ -1,514 +0,0 @@
|
||||
/*
|
||||
* i386 emulator main execution loop
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "exec-i386.h"
|
||||
|
||||
//#define DEBUG_EXEC
|
||||
#define DEBUG_FLUSH
|
||||
//#define DEBUG_SIGNAL
|
||||
|
||||
/* main execution loop */
|
||||
|
||||
/* maximum total translate dcode allocated */
|
||||
#define CODE_GEN_BUFFER_SIZE (2048 * 1024)
|
||||
//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
|
||||
#define CODE_GEN_MAX_SIZE 65536
|
||||
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
|
||||
|
||||
/* threshold to flush the translated code buffer */
|
||||
#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
|
||||
|
||||
#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / 64)
|
||||
#define CODE_GEN_HASH_BITS 15
|
||||
#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS)
|
||||
|
||||
typedef struct TranslationBlock {
|
||||
unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */
|
||||
unsigned long cs_base; /* CS base for this block */
|
||||
unsigned int flags; /* flags defining in which context the code was generated */
|
||||
uint8_t *tc_ptr; /* pointer to the translated code */
|
||||
struct TranslationBlock *hash_next; /* next matching block */
|
||||
} TranslationBlock;
|
||||
|
||||
TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
|
||||
TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
|
||||
int nb_tbs;
|
||||
|
||||
uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
|
||||
uint8_t *code_gen_ptr;
|
||||
|
||||
/* thread support */
|
||||
|
||||
#ifdef __powerpc__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
"0: lwarx %0,0,%1 ;"
|
||||
" xor. %0,%3,%0;"
|
||||
" bne 1f;"
|
||||
" stwcx. %2,0,%1;"
|
||||
" bne- 0b;"
|
||||
"1: "
|
||||
: "=&r" (ret)
|
||||
: "r" (p), "r" (1), "r" (0)
|
||||
: "cr0", "memory");
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __i386__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
char ret;
|
||||
long int readval;
|
||||
|
||||
__asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
|
||||
: "=q" (ret), "=m" (*p), "=a" (readval)
|
||||
: "r" (1), "m" (*p), "a" (0)
|
||||
: "memory");
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __s390__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
|
||||
" jl 0b"
|
||||
: "=&d" (ret)
|
||||
: "r" (1), "a" (p), "0" (*p)
|
||||
: "cc", "memory" );
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
int global_cpu_lock = 0;
|
||||
|
||||
void cpu_lock(void)
|
||||
{
|
||||
while (testandset(&global_cpu_lock));
|
||||
}
|
||||
|
||||
void cpu_unlock(void)
|
||||
{
|
||||
global_cpu_lock = 0;
|
||||
}
|
||||
|
||||
/* exception support */
|
||||
/* NOTE: not static to force relocation generation by GCC */
|
||||
void raise_exception(int exception_index)
|
||||
{
|
||||
/* NOTE: the register at this point must be saved by hand because
|
||||
longjmp restore them */
|
||||
#ifdef reg_EAX
|
||||
env->regs[R_EAX] = EAX;
|
||||
#endif
|
||||
#ifdef reg_ECX
|
||||
env->regs[R_ECX] = ECX;
|
||||
#endif
|
||||
#ifdef reg_EDX
|
||||
env->regs[R_EDX] = EDX;
|
||||
#endif
|
||||
#ifdef reg_EBX
|
||||
env->regs[R_EBX] = EBX;
|
||||
#endif
|
||||
#ifdef reg_ESP
|
||||
env->regs[R_ESP] = ESP;
|
||||
#endif
|
||||
#ifdef reg_EBP
|
||||
env->regs[R_EBP] = EBP;
|
||||
#endif
|
||||
#ifdef reg_ESI
|
||||
env->regs[R_ESI] = ESI;
|
||||
#endif
|
||||
#ifdef reg_EDI
|
||||
env->regs[R_EDI] = EDI;
|
||||
#endif
|
||||
env->exception_index = exception_index;
|
||||
longjmp(env->jmp_env, 1);
|
||||
}
|
||||
|
||||
#if defined(DEBUG_EXEC)
|
||||
static const char *cc_op_str[] = {
|
||||
"DYNAMIC",
|
||||
"EFLAGS",
|
||||
"MUL",
|
||||
"ADDB",
|
||||
"ADDW",
|
||||
"ADDL",
|
||||
"ADCB",
|
||||
"ADCW",
|
||||
"ADCL",
|
||||
"SUBB",
|
||||
"SUBW",
|
||||
"SUBL",
|
||||
"SBBB",
|
||||
"SBBW",
|
||||
"SBBL",
|
||||
"LOGICB",
|
||||
"LOGICW",
|
||||
"LOGICL",
|
||||
"INCB",
|
||||
"INCW",
|
||||
"INCL",
|
||||
"DECB",
|
||||
"DECW",
|
||||
"DECL",
|
||||
"SHLB",
|
||||
"SHLW",
|
||||
"SHLL",
|
||||
"SARB",
|
||||
"SARW",
|
||||
"SARL",
|
||||
};
|
||||
|
||||
static void cpu_x86_dump_state(FILE *f)
|
||||
{
|
||||
int eflags;
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
eflags |= (DF & DIRECTION_FLAG);
|
||||
fprintf(f,
|
||||
"EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n"
|
||||
"ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n"
|
||||
"CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n"
|
||||
"EIP=%08x\n",
|
||||
env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX],
|
||||
env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP],
|
||||
env->cc_src, env->cc_dst, cc_op_str[env->cc_op],
|
||||
eflags & DIRECTION_FLAG ? 'D' : '-',
|
||||
eflags & CC_O ? 'O' : '-',
|
||||
eflags & CC_S ? 'S' : '-',
|
||||
eflags & CC_Z ? 'Z' : '-',
|
||||
eflags & CC_A ? 'A' : '-',
|
||||
eflags & CC_P ? 'P' : '-',
|
||||
eflags & CC_C ? 'C' : '-',
|
||||
env->eip);
|
||||
#if 1
|
||||
fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
|
||||
(double)ST0, (double)ST1, (double)ST(2), (double)ST(3));
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void cpu_x86_tblocks_init(void)
|
||||
{
|
||||
if (!code_gen_ptr) {
|
||||
code_gen_ptr = code_gen_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
/* flush all the translation blocks */
|
||||
static void tb_flush(void)
|
||||
{
|
||||
int i;
|
||||
#ifdef DEBUG_FLUSH
|
||||
printf("gemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
|
||||
code_gen_ptr - code_gen_buffer,
|
||||
nb_tbs,
|
||||
(code_gen_ptr - code_gen_buffer) / nb_tbs);
|
||||
#endif
|
||||
nb_tbs = 0;
|
||||
for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
|
||||
tb_hash[i] = NULL;
|
||||
code_gen_ptr = code_gen_buffer;
|
||||
/* XXX: flush processor icache at this point */
|
||||
}
|
||||
|
||||
/* find a translation block in the translation cache. If not found,
|
||||
return NULL and the pointer to the last element of the list in pptb */
|
||||
static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
|
||||
unsigned long pc,
|
||||
unsigned long cs_base,
|
||||
unsigned int flags)
|
||||
{
|
||||
TranslationBlock **ptb, *tb;
|
||||
unsigned int h;
|
||||
|
||||
h = pc & (CODE_GEN_HASH_SIZE - 1);
|
||||
ptb = &tb_hash[h];
|
||||
for(;;) {
|
||||
tb = *ptb;
|
||||
if (!tb)
|
||||
break;
|
||||
if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
|
||||
return tb;
|
||||
ptb = &tb->hash_next;
|
||||
}
|
||||
*pptb = ptb;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* allocate a new translation block. flush the translation buffer if
|
||||
too many translation blocks or too much generated code */
|
||||
static inline TranslationBlock *tb_alloc(void)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
|
||||
(code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
|
||||
tb_flush();
|
||||
tb = &tbs[nb_tbs++];
|
||||
return tb;
|
||||
}
|
||||
|
||||
int cpu_x86_exec(CPUX86State *env1)
|
||||
{
|
||||
int saved_T0, saved_T1, saved_A0;
|
||||
CPUX86State *saved_env;
|
||||
#ifdef reg_EAX
|
||||
int saved_EAX;
|
||||
#endif
|
||||
#ifdef reg_ECX
|
||||
int saved_ECX;
|
||||
#endif
|
||||
#ifdef reg_EDX
|
||||
int saved_EDX;
|
||||
#endif
|
||||
#ifdef reg_EBX
|
||||
int saved_EBX;
|
||||
#endif
|
||||
#ifdef reg_ESP
|
||||
int saved_ESP;
|
||||
#endif
|
||||
#ifdef reg_EBP
|
||||
int saved_EBP;
|
||||
#endif
|
||||
#ifdef reg_ESI
|
||||
int saved_ESI;
|
||||
#endif
|
||||
#ifdef reg_EDI
|
||||
int saved_EDI;
|
||||
#endif
|
||||
int code_gen_size, ret;
|
||||
void (*gen_func)(void);
|
||||
TranslationBlock *tb, **ptb;
|
||||
uint8_t *tc_ptr, *cs_base, *pc;
|
||||
unsigned int flags;
|
||||
|
||||
/* first we save global registers */
|
||||
saved_T0 = T0;
|
||||
saved_T1 = T1;
|
||||
saved_A0 = A0;
|
||||
saved_env = env;
|
||||
env = env1;
|
||||
#ifdef reg_EAX
|
||||
saved_EAX = EAX;
|
||||
EAX = env->regs[R_EAX];
|
||||
#endif
|
||||
#ifdef reg_ECX
|
||||
saved_ECX = ECX;
|
||||
ECX = env->regs[R_ECX];
|
||||
#endif
|
||||
#ifdef reg_EDX
|
||||
saved_EDX = EDX;
|
||||
EDX = env->regs[R_EDX];
|
||||
#endif
|
||||
#ifdef reg_EBX
|
||||
saved_EBX = EBX;
|
||||
EBX = env->regs[R_EBX];
|
||||
#endif
|
||||
#ifdef reg_ESP
|
||||
saved_ESP = ESP;
|
||||
ESP = env->regs[R_ESP];
|
||||
#endif
|
||||
#ifdef reg_EBP
|
||||
saved_EBP = EBP;
|
||||
EBP = env->regs[R_EBP];
|
||||
#endif
|
||||
#ifdef reg_ESI
|
||||
saved_ESI = ESI;
|
||||
ESI = env->regs[R_ESI];
|
||||
#endif
|
||||
#ifdef reg_EDI
|
||||
saved_EDI = EDI;
|
||||
EDI = env->regs[R_EDI];
|
||||
#endif
|
||||
|
||||
/* put eflags in CPU temporary format */
|
||||
CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||
DF = 1 - (2 * ((env->eflags >> 10) & 1));
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||
env->interrupt_request = 0;
|
||||
|
||||
/* prepare setjmp context for exception handling */
|
||||
if (setjmp(env->jmp_env) == 0) {
|
||||
for(;;) {
|
||||
if (env->interrupt_request) {
|
||||
raise_exception(EXCP_INTERRUPT);
|
||||
}
|
||||
#ifdef DEBUG_EXEC
|
||||
if (loglevel) {
|
||||
cpu_x86_dump_state(logfile);
|
||||
}
|
||||
#endif
|
||||
/* we compute the CPU state. We assume it will not
|
||||
change during the whole generated block. */
|
||||
flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
|
||||
flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
|
||||
flags |= (((unsigned long)env->seg_cache[R_DS].base |
|
||||
(unsigned long)env->seg_cache[R_ES].base |
|
||||
(unsigned long)env->seg_cache[R_SS].base) != 0) <<
|
||||
GEN_FLAG_ADDSEG_SHIFT;
|
||||
flags |= (env->eflags & VM_MASK) >> (17 - GEN_FLAG_VM_SHIFT);
|
||||
cs_base = env->seg_cache[R_CS].base;
|
||||
pc = cs_base + env->eip;
|
||||
tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
|
||||
flags);
|
||||
if (!tb) {
|
||||
/* if no translated code available, then translate it now */
|
||||
/* XXX: very inefficient: we lock all the cpus when
|
||||
generating code */
|
||||
cpu_lock();
|
||||
tc_ptr = code_gen_ptr;
|
||||
ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE,
|
||||
&code_gen_size, pc, cs_base, flags);
|
||||
/* if invalid instruction, signal it */
|
||||
if (ret != 0) {
|
||||
cpu_unlock();
|
||||
raise_exception(EXCP06_ILLOP);
|
||||
}
|
||||
tb = tb_alloc();
|
||||
*ptb = tb;
|
||||
tb->pc = (unsigned long)pc;
|
||||
tb->cs_base = (unsigned long)cs_base;
|
||||
tb->flags = flags;
|
||||
tb->tc_ptr = tc_ptr;
|
||||
tb->hash_next = NULL;
|
||||
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
|
||||
cpu_unlock();
|
||||
}
|
||||
/* execute the generated code */
|
||||
tc_ptr = tb->tc_ptr;
|
||||
gen_func = (void *)tc_ptr;
|
||||
gen_func();
|
||||
}
|
||||
}
|
||||
ret = env->exception_index;
|
||||
|
||||
/* restore flags in standard format */
|
||||
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
|
||||
|
||||
/* restore global registers */
|
||||
#ifdef reg_EAX
|
||||
EAX = saved_EAX;
|
||||
#endif
|
||||
#ifdef reg_ECX
|
||||
ECX = saved_ECX;
|
||||
#endif
|
||||
#ifdef reg_EDX
|
||||
EDX = saved_EDX;
|
||||
#endif
|
||||
#ifdef reg_EBX
|
||||
EBX = saved_EBX;
|
||||
#endif
|
||||
#ifdef reg_ESP
|
||||
ESP = saved_ESP;
|
||||
#endif
|
||||
#ifdef reg_EBP
|
||||
EBP = saved_EBP;
|
||||
#endif
|
||||
#ifdef reg_ESI
|
||||
ESI = saved_ESI;
|
||||
#endif
|
||||
#ifdef reg_EDI
|
||||
EDI = saved_EDI;
|
||||
#endif
|
||||
T0 = saved_T0;
|
||||
T1 = saved_T1;
|
||||
A0 = saved_A0;
|
||||
env = saved_env;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void cpu_x86_interrupt(CPUX86State *s)
|
||||
{
|
||||
s->interrupt_request = 1;
|
||||
}
|
||||
|
||||
|
||||
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
|
||||
{
|
||||
CPUX86State *saved_env;
|
||||
|
||||
saved_env = env;
|
||||
env = s;
|
||||
load_seg(seg_reg, selector);
|
||||
env = saved_env;
|
||||
}
|
||||
|
||||
#undef EAX
|
||||
#undef ECX
|
||||
#undef EDX
|
||||
#undef EBX
|
||||
#undef ESP
|
||||
#undef EBP
|
||||
#undef ESI
|
||||
#undef EDI
|
||||
#undef EIP
|
||||
#include <signal.h>
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
static inline int handle_cpu_signal(unsigned long pc,
|
||||
sigset_t *old_set)
|
||||
{
|
||||
#ifdef DEBUG_SIGNAL
|
||||
printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n",
|
||||
pc, *(unsigned long *)old_set);
|
||||
#endif
|
||||
if (pc >= (unsigned long)code_gen_buffer &&
|
||||
pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
|
||||
/* the PC is inside the translated code. It means that we have
|
||||
a virtual CPU fault */
|
||||
/* we restore the process signal mask as the sigreturn should
|
||||
do it */
|
||||
sigprocmask(SIG_SETMASK, old_set, NULL);
|
||||
/* XXX: need to compute virtual pc position by retranslating
|
||||
code. The rest of the CPU state should be correct. */
|
||||
raise_exception(EXCP0D_GPF);
|
||||
/* never comes here */
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc)
|
||||
{
|
||||
#if defined(__i386__)
|
||||
struct ucontext *uc = puc;
|
||||
unsigned long pc;
|
||||
sigset_t *pold_set;
|
||||
|
||||
#ifndef REG_EIP
|
||||
/* for glibc 2.1 */
|
||||
#define REG_EIP EIP
|
||||
#endif
|
||||
pc = uc->uc_mcontext.gregs[REG_EIP];
|
||||
pold_set = &uc->uc_sigmask;
|
||||
return handle_cpu_signal(pc, pold_set);
|
||||
#else
|
||||
#warning No CPU specific signal handler: cannot handle target SIGSEGV events
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
+281
-96
@@ -17,105 +17,59 @@
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
#include "dyngen-exec.h"
|
||||
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef signed long long int64_t;
|
||||
/* at least 4 register variables are defines */
|
||||
register struct CPUX86State *env asm(AREG0);
|
||||
register uint32_t T0 asm(AREG1);
|
||||
register uint32_t T1 asm(AREG2);
|
||||
register uint32_t T2 asm(AREG3);
|
||||
|
||||
#define bswap32(x) \
|
||||
({ \
|
||||
uint32_t __x = (x); \
|
||||
((uint32_t)( \
|
||||
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
|
||||
})
|
||||
#define A0 T2
|
||||
|
||||
#define NULL 0
|
||||
#include <fenv.h>
|
||||
|
||||
typedef struct FILE FILE;
|
||||
extern FILE *logfile;
|
||||
extern int loglevel;
|
||||
extern int fprintf(FILE *, const char *, ...);
|
||||
extern int printf(const char *, ...);
|
||||
|
||||
#ifdef __i386__
|
||||
register unsigned int T0 asm("ebx");
|
||||
register unsigned int T1 asm("esi");
|
||||
register unsigned int A0 asm("edi");
|
||||
register struct CPUX86State *env asm("ebp");
|
||||
#endif
|
||||
#ifdef __powerpc__
|
||||
register unsigned int EAX asm("r16");
|
||||
register unsigned int ECX asm("r17");
|
||||
register unsigned int EDX asm("r18");
|
||||
register unsigned int EBX asm("r19");
|
||||
register unsigned int ESP asm("r20");
|
||||
register unsigned int EBP asm("r21");
|
||||
register unsigned int ESI asm("r22");
|
||||
register unsigned int EDI asm("r23");
|
||||
register unsigned int T0 asm("r24");
|
||||
register unsigned int T1 asm("r25");
|
||||
register unsigned int A0 asm("r26");
|
||||
register struct CPUX86State *env asm("r27");
|
||||
#define USE_INT_TO_FLOAT_HELPERS
|
||||
#define BUGGY_GCC_DIV64
|
||||
/* if more registers are available, we define some registers too */
|
||||
#ifdef AREG4
|
||||
register uint32_t EAX asm(AREG4);
|
||||
#define reg_EAX
|
||||
#define reg_ECX
|
||||
#define reg_EDX
|
||||
#define reg_EBX
|
||||
#endif
|
||||
|
||||
#ifdef AREG5
|
||||
register uint32_t ESP asm(AREG5);
|
||||
#define reg_ESP
|
||||
#endif
|
||||
|
||||
#ifdef AREG6
|
||||
register uint32_t EBP asm(AREG6);
|
||||
#define reg_EBP
|
||||
#endif
|
||||
|
||||
#ifdef AREG7
|
||||
register uint32_t ECX asm(AREG7);
|
||||
#define reg_ECX
|
||||
#endif
|
||||
|
||||
#ifdef AREG8
|
||||
register uint32_t EDX asm(AREG8);
|
||||
#define reg_EDX
|
||||
#endif
|
||||
|
||||
#ifdef AREG9
|
||||
register uint32_t EBX asm(AREG9);
|
||||
#define reg_EBX
|
||||
#endif
|
||||
|
||||
#ifdef AREG10
|
||||
register uint32_t ESI asm(AREG10);
|
||||
#define reg_ESI
|
||||
#endif
|
||||
|
||||
#ifdef AREG11
|
||||
register uint32_t EDI asm(AREG11);
|
||||
#define reg_EDI
|
||||
#endif
|
||||
#ifdef __arm__
|
||||
register unsigned int T0 asm("r4");
|
||||
register unsigned int T1 asm("r5");
|
||||
register unsigned int A0 asm("r6");
|
||||
register struct CPUX86State *env asm("r7");
|
||||
#endif
|
||||
#ifdef __mips__
|
||||
register unsigned int T0 asm("s0");
|
||||
register unsigned int T1 asm("s1");
|
||||
register unsigned int A0 asm("s2");
|
||||
register struct CPUX86State *env asm("s3");
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
register unsigned int T0 asm("l0");
|
||||
register unsigned int T1 asm("l1");
|
||||
register unsigned int A0 asm("l2");
|
||||
register struct CPUX86State *env asm("l3");
|
||||
#endif
|
||||
#ifdef __s390__
|
||||
register unsigned int T0 asm("r7");
|
||||
register unsigned int T1 asm("r8");
|
||||
register unsigned int A0 asm("r9");
|
||||
register struct CPUX86State *env asm("r10");
|
||||
#endif
|
||||
#ifdef __alpha__
|
||||
register unsigned int T0 asm("$9");
|
||||
register unsigned int T1 asm("$10");
|
||||
register unsigned int A0 asm("$11");
|
||||
register struct CPUX86State *env asm("$12");
|
||||
#endif
|
||||
|
||||
/* force GCC to generate only one epilog at the end of the function */
|
||||
#define FORCE_RET() asm volatile ("");
|
||||
|
||||
#ifndef OPPROTO
|
||||
#define OPPROTO
|
||||
#endif
|
||||
|
||||
#define xglue(x, y) x ## y
|
||||
#define glue(x, y) xglue(x, y)
|
||||
extern FILE *logfile;
|
||||
extern int loglevel;
|
||||
|
||||
#ifndef reg_EAX
|
||||
#define EAX (env->regs[R_EAX])
|
||||
@@ -154,12 +108,12 @@ register struct CPUX86State *env asm("$12");
|
||||
#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7])
|
||||
#define ST1 ST(1)
|
||||
|
||||
extern int __op_param1, __op_param2, __op_param3;
|
||||
#define PARAM1 ((long)(&__op_param1))
|
||||
#define PARAM2 ((long)(&__op_param2))
|
||||
#define PARAM3 ((long)(&__op_param3))
|
||||
#ifdef USE_FP_CONVERT
|
||||
#define FP_CONVERT (env->fp_convert)
|
||||
#endif
|
||||
|
||||
#include "cpu-i386.h"
|
||||
#include "exec.h"
|
||||
|
||||
typedef struct CCTable {
|
||||
int (*compute_all)(void); /* return all the flags */
|
||||
@@ -168,10 +122,241 @@ typedef struct CCTable {
|
||||
|
||||
extern CCTable cc_table[];
|
||||
|
||||
void load_seg(int seg_reg, int selector);
|
||||
void cpu_lock(void);
|
||||
void cpu_unlock(void);
|
||||
void load_seg(int seg_reg, int selector, unsigned cur_eip);
|
||||
void jmp_seg(int selector, unsigned int new_eip);
|
||||
void helper_iret_protected(int shift);
|
||||
void helper_lldt_T0(void);
|
||||
void helper_ltr_T0(void);
|
||||
void helper_movl_crN_T0(int reg);
|
||||
void helper_movl_drN_T0(int reg);
|
||||
void helper_invlpg(unsigned int addr);
|
||||
void cpu_x86_update_cr0(CPUX86State *env);
|
||||
void cpu_x86_update_cr3(CPUX86State *env);
|
||||
void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr);
|
||||
int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write);
|
||||
void __hidden cpu_lock(void);
|
||||
void __hidden cpu_unlock(void);
|
||||
void do_interrupt(int intno, int is_int, int error_code,
|
||||
unsigned int next_eip);
|
||||
void do_interrupt_user(int intno, int is_int, int error_code,
|
||||
unsigned int next_eip);
|
||||
void raise_interrupt(int intno, int is_int, int error_code,
|
||||
unsigned int next_eip);
|
||||
void raise_exception_err(int exception_index, int error_code);
|
||||
void raise_exception(int exception_index);
|
||||
void __hidden cpu_loop_exit(void);
|
||||
void helper_fsave(uint8_t *ptr, int data32);
|
||||
void helper_frstor(uint8_t *ptr, int data32);
|
||||
|
||||
void OPPROTO op_movl_eflags_T0(void);
|
||||
void OPPROTO op_movl_T0_eflags(void);
|
||||
void raise_interrupt(int intno, int is_int, int error_code,
|
||||
unsigned int next_eip);
|
||||
void raise_exception_err(int exception_index, int error_code);
|
||||
void raise_exception(int exception_index);
|
||||
void helper_divl_EAX_T0(uint32_t eip);
|
||||
void helper_idivl_EAX_T0(uint32_t eip);
|
||||
void helper_cmpxchg8b(void);
|
||||
void helper_cpuid(void);
|
||||
void helper_rdtsc(void);
|
||||
void helper_rdmsr(void);
|
||||
void helper_wrmsr(void);
|
||||
void helper_lsl(void);
|
||||
void helper_lar(void);
|
||||
|
||||
#ifdef USE_X86LDOUBLE
|
||||
/* use long double functions */
|
||||
#define lrint lrintl
|
||||
#define llrint llrintl
|
||||
#define fabs fabsl
|
||||
#define sin sinl
|
||||
#define cos cosl
|
||||
#define sqrt sqrtl
|
||||
#define pow powl
|
||||
#define log logl
|
||||
#define tan tanl
|
||||
#define atan2 atan2l
|
||||
#define floor floorl
|
||||
#define ceil ceill
|
||||
#define rint rintl
|
||||
#endif
|
||||
|
||||
extern int lrint(CPU86_LDouble x);
|
||||
extern int64_t llrint(CPU86_LDouble x);
|
||||
extern CPU86_LDouble fabs(CPU86_LDouble x);
|
||||
extern CPU86_LDouble sin(CPU86_LDouble x);
|
||||
extern CPU86_LDouble cos(CPU86_LDouble x);
|
||||
extern CPU86_LDouble sqrt(CPU86_LDouble x);
|
||||
extern CPU86_LDouble pow(CPU86_LDouble, CPU86_LDouble);
|
||||
extern CPU86_LDouble log(CPU86_LDouble x);
|
||||
extern CPU86_LDouble tan(CPU86_LDouble x);
|
||||
extern CPU86_LDouble atan2(CPU86_LDouble, CPU86_LDouble);
|
||||
extern CPU86_LDouble floor(CPU86_LDouble x);
|
||||
extern CPU86_LDouble ceil(CPU86_LDouble x);
|
||||
extern CPU86_LDouble rint(CPU86_LDouble x);
|
||||
|
||||
#define RC_MASK 0xc00
|
||||
#define RC_NEAR 0x000
|
||||
#define RC_DOWN 0x400
|
||||
#define RC_UP 0x800
|
||||
#define RC_CHOP 0xc00
|
||||
|
||||
#define MAXTAN 9223372036854775808.0
|
||||
|
||||
#ifdef __arm__
|
||||
/* we have no way to do correct rounding - a FPU emulator is needed */
|
||||
#define FE_DOWNWARD FE_TONEAREST
|
||||
#define FE_UPWARD FE_TONEAREST
|
||||
#define FE_TOWARDZERO FE_TONEAREST
|
||||
#endif
|
||||
|
||||
#ifdef USE_X86LDOUBLE
|
||||
|
||||
/* only for x86 */
|
||||
typedef union {
|
||||
long double d;
|
||||
struct {
|
||||
unsigned long long lower;
|
||||
unsigned short upper;
|
||||
} l;
|
||||
} CPU86_LDoubleU;
|
||||
|
||||
/* the following deal with x86 long double-precision numbers */
|
||||
#define MAXEXPD 0x7fff
|
||||
#define EXPBIAS 16383
|
||||
#define EXPD(fp) (fp.l.upper & 0x7fff)
|
||||
#define SIGND(fp) ((fp.l.upper) & 0x8000)
|
||||
#define MANTD(fp) (fp.l.lower)
|
||||
#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS
|
||||
|
||||
#else
|
||||
|
||||
/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */
|
||||
typedef union {
|
||||
double d;
|
||||
#if !defined(WORDS_BIGENDIAN) && !defined(__arm__)
|
||||
struct {
|
||||
uint32_t lower;
|
||||
int32_t upper;
|
||||
} l;
|
||||
#else
|
||||
struct {
|
||||
int32_t upper;
|
||||
uint32_t lower;
|
||||
} l;
|
||||
#endif
|
||||
#ifndef __arm__
|
||||
int64_t ll;
|
||||
#endif
|
||||
} CPU86_LDoubleU;
|
||||
|
||||
/* the following deal with IEEE double-precision numbers */
|
||||
#define MAXEXPD 0x7ff
|
||||
#define EXPBIAS 1023
|
||||
#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF)
|
||||
#define SIGND(fp) ((fp.l.upper) & 0x80000000)
|
||||
#ifdef __arm__
|
||||
#define MANTD(fp) (fp.l.lower | ((uint64_t)(fp.l.upper & ((1 << 20) - 1)) << 32))
|
||||
#else
|
||||
#define MANTD(fp) (fp.ll & ((1LL << 52) - 1))
|
||||
#endif
|
||||
#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7ff << 20)) | (EXPBIAS << 20)
|
||||
#endif
|
||||
|
||||
static inline void fpush(void)
|
||||
{
|
||||
env->fpstt = (env->fpstt - 1) & 7;
|
||||
env->fptags[env->fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
|
||||
static inline void fpop(void)
|
||||
{
|
||||
env->fptags[env->fpstt] = 1; /* invvalidate stack entry */
|
||||
env->fpstt = (env->fpstt + 1) & 7;
|
||||
}
|
||||
|
||||
#ifndef USE_X86LDOUBLE
|
||||
static inline CPU86_LDouble helper_fldt(uint8_t *ptr)
|
||||
{
|
||||
CPU86_LDoubleU temp;
|
||||
int upper, e;
|
||||
uint64_t ll;
|
||||
|
||||
/* mantissa */
|
||||
upper = lduw(ptr + 8);
|
||||
/* XXX: handle overflow ? */
|
||||
e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
|
||||
e |= (upper >> 4) & 0x800; /* sign */
|
||||
ll = (ldq(ptr) >> 11) & ((1LL << 52) - 1);
|
||||
#ifdef __arm__
|
||||
temp.l.upper = (e << 20) | (ll >> 32);
|
||||
temp.l.lower = ll;
|
||||
#else
|
||||
temp.ll = ll | ((uint64_t)e << 52);
|
||||
#endif
|
||||
return temp.d;
|
||||
}
|
||||
|
||||
static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr)
|
||||
{
|
||||
CPU86_LDoubleU temp;
|
||||
int e;
|
||||
|
||||
temp.d = f;
|
||||
/* mantissa */
|
||||
stq(ptr, (MANTD(temp) << 11) | (1LL << 63));
|
||||
/* exponent + sign */
|
||||
e = EXPD(temp) - EXPBIAS + 16383;
|
||||
e |= SIGND(temp) >> 16;
|
||||
stw(ptr + 8, e);
|
||||
}
|
||||
#endif
|
||||
|
||||
const CPU86_LDouble f15rk[7];
|
||||
|
||||
void helper_fldt_ST0_A0(void);
|
||||
void helper_fstt_ST0_A0(void);
|
||||
void helper_fbld_ST0_A0(void);
|
||||
void helper_fbst_ST0_A0(void);
|
||||
void helper_f2xm1(void);
|
||||
void helper_fyl2x(void);
|
||||
void helper_fptan(void);
|
||||
void helper_fpatan(void);
|
||||
void helper_fxtract(void);
|
||||
void helper_fprem1(void);
|
||||
void helper_fprem(void);
|
||||
void helper_fyl2xp1(void);
|
||||
void helper_fsqrt(void);
|
||||
void helper_fsincos(void);
|
||||
void helper_frndint(void);
|
||||
void helper_fscale(void);
|
||||
void helper_fsin(void);
|
||||
void helper_fcos(void);
|
||||
void helper_fxam_ST0(void);
|
||||
void helper_fstenv(uint8_t *ptr, int data32);
|
||||
void helper_fldenv(uint8_t *ptr, int data32);
|
||||
void helper_fsave(uint8_t *ptr, int data32);
|
||||
void helper_frstor(uint8_t *ptr, int data32);
|
||||
|
||||
const uint8_t parity_table[256];
|
||||
const uint8_t rclw_table[32];
|
||||
const uint8_t rclb_table[32];
|
||||
|
||||
static inline uint32_t compute_eflags(void)
|
||||
{
|
||||
return env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
|
||||
}
|
||||
|
||||
#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK)
|
||||
|
||||
#define FL_UPDATE_CPL0_MASK (TF_MASK | IF_MASK | IOPL_MASK | NT_MASK | \
|
||||
RF_MASK | AC_MASK | ID_MASK)
|
||||
|
||||
/* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */
|
||||
static inline void load_eflags(int eflags, int update_mask)
|
||||
{
|
||||
CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||
DF = 1 - (2 * ((eflags >> 10) & 1));
|
||||
env->eflags = (env->eflags & ~update_mask) |
|
||||
(eflags & update_mask);
|
||||
}
|
||||
@@ -0,0 +1,689 @@
|
||||
/*
|
||||
* virtual page mapping and translated block handling
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "config.h"
|
||||
#ifdef TARGET_I386
|
||||
#include "cpu-i386.h"
|
||||
#endif
|
||||
#ifdef TARGET_ARM
|
||||
#include "cpu-arm.h"
|
||||
#endif
|
||||
#include "exec.h"
|
||||
|
||||
//#define DEBUG_TB_INVALIDATE
|
||||
//#define DEBUG_FLUSH
|
||||
|
||||
/* make various TB consistency checks */
|
||||
//#define DEBUG_TB_CHECK
|
||||
|
||||
/* threshold to flush the translated code buffer */
|
||||
#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
|
||||
|
||||
#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / 64)
|
||||
|
||||
TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
|
||||
TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
|
||||
int nb_tbs;
|
||||
/* any access to the tbs or the page table must use this lock */
|
||||
spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
|
||||
uint8_t *code_gen_ptr;
|
||||
|
||||
/* XXX: pack the flags in the low bits of the pointer ? */
|
||||
typedef struct PageDesc {
|
||||
unsigned long flags;
|
||||
TranslationBlock *first_tb;
|
||||
} PageDesc;
|
||||
|
||||
#define L2_BITS 10
|
||||
#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
|
||||
|
||||
#define L1_SIZE (1 << L1_BITS)
|
||||
#define L2_SIZE (1 << L2_BITS)
|
||||
|
||||
static void tb_invalidate_page(unsigned long address);
|
||||
|
||||
unsigned long real_host_page_size;
|
||||
unsigned long host_page_bits;
|
||||
unsigned long host_page_size;
|
||||
unsigned long host_page_mask;
|
||||
|
||||
static PageDesc *l1_map[L1_SIZE];
|
||||
|
||||
static void page_init(void)
|
||||
{
|
||||
/* NOTE: we can always suppose that host_page_size >=
|
||||
TARGET_PAGE_SIZE */
|
||||
real_host_page_size = getpagesize();
|
||||
if (host_page_size == 0)
|
||||
host_page_size = real_host_page_size;
|
||||
if (host_page_size < TARGET_PAGE_SIZE)
|
||||
host_page_size = TARGET_PAGE_SIZE;
|
||||
host_page_bits = 0;
|
||||
while ((1 << host_page_bits) < host_page_size)
|
||||
host_page_bits++;
|
||||
host_page_mask = ~(host_page_size - 1);
|
||||
}
|
||||
|
||||
/* dump memory mappings */
|
||||
void page_dump(FILE *f)
|
||||
{
|
||||
unsigned long start, end;
|
||||
int i, j, prot, prot1;
|
||||
PageDesc *p;
|
||||
|
||||
fprintf(f, "%-8s %-8s %-8s %s\n",
|
||||
"start", "end", "size", "prot");
|
||||
start = -1;
|
||||
end = -1;
|
||||
prot = 0;
|
||||
for(i = 0; i <= L1_SIZE; i++) {
|
||||
if (i < L1_SIZE)
|
||||
p = l1_map[i];
|
||||
else
|
||||
p = NULL;
|
||||
for(j = 0;j < L2_SIZE; j++) {
|
||||
if (!p)
|
||||
prot1 = 0;
|
||||
else
|
||||
prot1 = p[j].flags;
|
||||
if (prot1 != prot) {
|
||||
end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
|
||||
if (start != -1) {
|
||||
fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
|
||||
start, end, end - start,
|
||||
prot & PAGE_READ ? 'r' : '-',
|
||||
prot & PAGE_WRITE ? 'w' : '-',
|
||||
prot & PAGE_EXEC ? 'x' : '-');
|
||||
}
|
||||
if (prot1 != 0)
|
||||
start = end;
|
||||
else
|
||||
start = -1;
|
||||
prot = prot1;
|
||||
}
|
||||
if (!p)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline PageDesc *page_find_alloc(unsigned int index)
|
||||
{
|
||||
PageDesc **lp, *p;
|
||||
|
||||
lp = &l1_map[index >> L2_BITS];
|
||||
p = *lp;
|
||||
if (!p) {
|
||||
/* allocate if not found */
|
||||
p = malloc(sizeof(PageDesc) * L2_SIZE);
|
||||
memset(p, 0, sizeof(PageDesc) * L2_SIZE);
|
||||
*lp = p;
|
||||
}
|
||||
return p + (index & (L2_SIZE - 1));
|
||||
}
|
||||
|
||||
static inline PageDesc *page_find(unsigned int index)
|
||||
{
|
||||
PageDesc *p;
|
||||
|
||||
p = l1_map[index >> L2_BITS];
|
||||
if (!p)
|
||||
return 0;
|
||||
return p + (index & (L2_SIZE - 1));
|
||||
}
|
||||
|
||||
int page_get_flags(unsigned long address)
|
||||
{
|
||||
PageDesc *p;
|
||||
|
||||
p = page_find(address >> TARGET_PAGE_BITS);
|
||||
if (!p)
|
||||
return 0;
|
||||
return p->flags;
|
||||
}
|
||||
|
||||
/* modify the flags of a page and invalidate the code if
|
||||
necessary. The flag PAGE_WRITE_ORG is positionned automatically
|
||||
depending on PAGE_WRITE */
|
||||
void page_set_flags(unsigned long start, unsigned long end, int flags)
|
||||
{
|
||||
PageDesc *p;
|
||||
unsigned long addr;
|
||||
|
||||
start = start & TARGET_PAGE_MASK;
|
||||
end = TARGET_PAGE_ALIGN(end);
|
||||
if (flags & PAGE_WRITE)
|
||||
flags |= PAGE_WRITE_ORG;
|
||||
spin_lock(&tb_lock);
|
||||
for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
|
||||
p = page_find_alloc(addr >> TARGET_PAGE_BITS);
|
||||
/* if the write protection is set, then we invalidate the code
|
||||
inside */
|
||||
if (!(p->flags & PAGE_WRITE) &&
|
||||
(flags & PAGE_WRITE) &&
|
||||
p->first_tb) {
|
||||
tb_invalidate_page(addr);
|
||||
}
|
||||
p->flags = flags;
|
||||
}
|
||||
spin_unlock(&tb_lock);
|
||||
}
|
||||
|
||||
void cpu_exec_init(void)
|
||||
{
|
||||
if (!code_gen_ptr) {
|
||||
code_gen_ptr = code_gen_buffer;
|
||||
page_init();
|
||||
}
|
||||
}
|
||||
|
||||
/* set to NULL all the 'first_tb' fields in all PageDescs */
|
||||
static void page_flush_tb(void)
|
||||
{
|
||||
int i, j;
|
||||
PageDesc *p;
|
||||
|
||||
for(i = 0; i < L1_SIZE; i++) {
|
||||
p = l1_map[i];
|
||||
if (p) {
|
||||
for(j = 0; j < L2_SIZE; j++)
|
||||
p[j].first_tb = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* flush all the translation blocks */
|
||||
/* XXX: tb_flush is currently not thread safe */
|
||||
void tb_flush(void)
|
||||
{
|
||||
int i;
|
||||
#ifdef DEBUG_FLUSH
|
||||
printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
|
||||
code_gen_ptr - code_gen_buffer,
|
||||
nb_tbs,
|
||||
(code_gen_ptr - code_gen_buffer) / nb_tbs);
|
||||
#endif
|
||||
nb_tbs = 0;
|
||||
for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
|
||||
tb_hash[i] = NULL;
|
||||
page_flush_tb();
|
||||
code_gen_ptr = code_gen_buffer;
|
||||
/* XXX: flush processor icache at this point if cache flush is
|
||||
expensive */
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TB_CHECK
|
||||
|
||||
static void tb_invalidate_check(unsigned long address)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
int i;
|
||||
address &= TARGET_PAGE_MASK;
|
||||
for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
|
||||
for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
|
||||
if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
|
||||
address >= tb->pc + tb->size)) {
|
||||
printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
|
||||
address, tb->pc, tb->size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* verify that all the pages have correct rights for code */
|
||||
static void tb_page_check(void)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
int i, flags1, flags2;
|
||||
|
||||
for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
|
||||
for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
|
||||
flags1 = page_get_flags(tb->pc);
|
||||
flags2 = page_get_flags(tb->pc + tb->size - 1);
|
||||
if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
|
||||
printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
|
||||
tb->pc, tb->size, flags1, flags2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tb_jmp_check(TranslationBlock *tb)
|
||||
{
|
||||
TranslationBlock *tb1;
|
||||
unsigned int n1;
|
||||
|
||||
/* suppress any remaining jumps to this TB */
|
||||
tb1 = tb->jmp_first;
|
||||
for(;;) {
|
||||
n1 = (long)tb1 & 3;
|
||||
tb1 = (TranslationBlock *)((long)tb1 & ~3);
|
||||
if (n1 == 2)
|
||||
break;
|
||||
tb1 = tb1->jmp_next[n1];
|
||||
}
|
||||
/* check end of list */
|
||||
if (tb1 != tb) {
|
||||
printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* invalidate one TB */
|
||||
static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
|
||||
int next_offset)
|
||||
{
|
||||
TranslationBlock *tb1;
|
||||
for(;;) {
|
||||
tb1 = *ptb;
|
||||
if (tb1 == tb) {
|
||||
*ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
|
||||
break;
|
||||
}
|
||||
ptb = (TranslationBlock **)((char *)tb1 + next_offset);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void tb_jmp_remove(TranslationBlock *tb, int n)
|
||||
{
|
||||
TranslationBlock *tb1, **ptb;
|
||||
unsigned int n1;
|
||||
|
||||
ptb = &tb->jmp_next[n];
|
||||
tb1 = *ptb;
|
||||
if (tb1) {
|
||||
/* find tb(n) in circular list */
|
||||
for(;;) {
|
||||
tb1 = *ptb;
|
||||
n1 = (long)tb1 & 3;
|
||||
tb1 = (TranslationBlock *)((long)tb1 & ~3);
|
||||
if (n1 == n && tb1 == tb)
|
||||
break;
|
||||
if (n1 == 2) {
|
||||
ptb = &tb1->jmp_first;
|
||||
} else {
|
||||
ptb = &tb1->jmp_next[n1];
|
||||
}
|
||||
}
|
||||
/* now we can suppress tb(n) from the list */
|
||||
*ptb = tb->jmp_next[n];
|
||||
|
||||
tb->jmp_next[n] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* reset the jump entry 'n' of a TB so that it is not chained to
|
||||
another TB */
|
||||
static inline void tb_reset_jump(TranslationBlock *tb, int n)
|
||||
{
|
||||
tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
|
||||
}
|
||||
|
||||
static inline void tb_invalidate(TranslationBlock *tb, int parity)
|
||||
{
|
||||
PageDesc *p;
|
||||
unsigned int page_index1, page_index2;
|
||||
unsigned int h, n1;
|
||||
TranslationBlock *tb1, *tb2;
|
||||
|
||||
/* remove the TB from the hash list */
|
||||
h = tb_hash_func(tb->pc);
|
||||
tb_remove(&tb_hash[h], tb,
|
||||
offsetof(TranslationBlock, hash_next));
|
||||
/* remove the TB from the page list */
|
||||
page_index1 = tb->pc >> TARGET_PAGE_BITS;
|
||||
if ((page_index1 & 1) == parity) {
|
||||
p = page_find(page_index1);
|
||||
tb_remove(&p->first_tb, tb,
|
||||
offsetof(TranslationBlock, page_next[page_index1 & 1]));
|
||||
}
|
||||
page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS;
|
||||
if ((page_index2 & 1) == parity) {
|
||||
p = page_find(page_index2);
|
||||
tb_remove(&p->first_tb, tb,
|
||||
offsetof(TranslationBlock, page_next[page_index2 & 1]));
|
||||
}
|
||||
|
||||
/* suppress this TB from the two jump lists */
|
||||
tb_jmp_remove(tb, 0);
|
||||
tb_jmp_remove(tb, 1);
|
||||
|
||||
/* suppress any remaining jumps to this TB */
|
||||
tb1 = tb->jmp_first;
|
||||
for(;;) {
|
||||
n1 = (long)tb1 & 3;
|
||||
if (n1 == 2)
|
||||
break;
|
||||
tb1 = (TranslationBlock *)((long)tb1 & ~3);
|
||||
tb2 = tb1->jmp_next[n1];
|
||||
tb_reset_jump(tb1, n1);
|
||||
tb1->jmp_next[n1] = NULL;
|
||||
tb1 = tb2;
|
||||
}
|
||||
tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
|
||||
}
|
||||
|
||||
/* invalidate all TBs which intersect with the target page starting at addr */
|
||||
static void tb_invalidate_page(unsigned long address)
|
||||
{
|
||||
TranslationBlock *tb_next, *tb;
|
||||
unsigned int page_index;
|
||||
int parity1, parity2;
|
||||
PageDesc *p;
|
||||
#ifdef DEBUG_TB_INVALIDATE
|
||||
printf("tb_invalidate_page: %lx\n", address);
|
||||
#endif
|
||||
|
||||
page_index = address >> TARGET_PAGE_BITS;
|
||||
p = page_find(page_index);
|
||||
if (!p)
|
||||
return;
|
||||
tb = p->first_tb;
|
||||
parity1 = page_index & 1;
|
||||
parity2 = parity1 ^ 1;
|
||||
while (tb != NULL) {
|
||||
tb_next = tb->page_next[parity1];
|
||||
tb_invalidate(tb, parity2);
|
||||
tb = tb_next;
|
||||
}
|
||||
p->first_tb = NULL;
|
||||
}
|
||||
|
||||
/* add the tb in the target page and protect it if necessary */
|
||||
static inline void tb_alloc_page(TranslationBlock *tb, unsigned int page_index)
|
||||
{
|
||||
PageDesc *p;
|
||||
unsigned long host_start, host_end, addr, page_addr;
|
||||
int prot;
|
||||
|
||||
p = page_find_alloc(page_index);
|
||||
tb->page_next[page_index & 1] = p->first_tb;
|
||||
p->first_tb = tb;
|
||||
if (p->flags & PAGE_WRITE) {
|
||||
/* force the host page as non writable (writes will have a
|
||||
page fault + mprotect overhead) */
|
||||
page_addr = (page_index << TARGET_PAGE_BITS);
|
||||
host_start = page_addr & host_page_mask;
|
||||
host_end = host_start + host_page_size;
|
||||
prot = 0;
|
||||
for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
|
||||
prot |= page_get_flags(addr);
|
||||
mprotect((void *)host_start, host_page_size,
|
||||
(prot & PAGE_BITS) & ~PAGE_WRITE);
|
||||
#ifdef DEBUG_TB_INVALIDATE
|
||||
printf("protecting code page: 0x%08lx\n",
|
||||
host_start);
|
||||
#endif
|
||||
p->flags &= ~PAGE_WRITE;
|
||||
#ifdef DEBUG_TB_CHECK
|
||||
tb_page_check();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate a new translation block. Flush the translation buffer if
|
||||
too many translation blocks or too much generated code. */
|
||||
TranslationBlock *tb_alloc(unsigned long pc)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
|
||||
if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
|
||||
(code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
|
||||
return NULL;
|
||||
tb = &tbs[nb_tbs++];
|
||||
tb->pc = pc;
|
||||
return tb;
|
||||
}
|
||||
|
||||
/* link the tb with the other TBs */
|
||||
void tb_link(TranslationBlock *tb)
|
||||
{
|
||||
unsigned int page_index1, page_index2;
|
||||
|
||||
/* add in the page list */
|
||||
page_index1 = tb->pc >> TARGET_PAGE_BITS;
|
||||
tb_alloc_page(tb, page_index1);
|
||||
page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS;
|
||||
if (page_index2 != page_index1) {
|
||||
tb_alloc_page(tb, page_index2);
|
||||
}
|
||||
tb->jmp_first = (TranslationBlock *)((long)tb | 2);
|
||||
tb->jmp_next[0] = NULL;
|
||||
tb->jmp_next[1] = NULL;
|
||||
|
||||
/* init original jump addresses */
|
||||
if (tb->tb_next_offset[0] != 0xffff)
|
||||
tb_reset_jump(tb, 0);
|
||||
if (tb->tb_next_offset[1] != 0xffff)
|
||||
tb_reset_jump(tb, 1);
|
||||
}
|
||||
|
||||
/* called from signal handler: invalidate the code and unprotect the
|
||||
page. Return TRUE if the fault was succesfully handled. */
|
||||
int page_unprotect(unsigned long address)
|
||||
{
|
||||
unsigned int page_index, prot, pindex;
|
||||
PageDesc *p, *p1;
|
||||
unsigned long host_start, host_end, addr;
|
||||
|
||||
host_start = address & host_page_mask;
|
||||
page_index = host_start >> TARGET_PAGE_BITS;
|
||||
p1 = page_find(page_index);
|
||||
if (!p1)
|
||||
return 0;
|
||||
host_end = host_start + host_page_size;
|
||||
p = p1;
|
||||
prot = 0;
|
||||
for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
|
||||
prot |= p->flags;
|
||||
p++;
|
||||
}
|
||||
/* if the page was really writable, then we change its
|
||||
protection back to writable */
|
||||
if (prot & PAGE_WRITE_ORG) {
|
||||
mprotect((void *)host_start, host_page_size,
|
||||
(prot & PAGE_BITS) | PAGE_WRITE);
|
||||
pindex = (address - host_start) >> TARGET_PAGE_BITS;
|
||||
p1[pindex].flags |= PAGE_WRITE;
|
||||
/* and since the content will be modified, we must invalidate
|
||||
the corresponding translated code. */
|
||||
tb_invalidate_page(address);
|
||||
#ifdef DEBUG_TB_CHECK
|
||||
tb_invalidate_check(address);
|
||||
#endif
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* call this function when system calls directly modify a memory area */
|
||||
void page_unprotect_range(uint8_t *data, unsigned long data_size)
|
||||
{
|
||||
unsigned long start, end, addr;
|
||||
|
||||
start = (unsigned long)data;
|
||||
end = start + data_size;
|
||||
start &= TARGET_PAGE_MASK;
|
||||
end = TARGET_PAGE_ALIGN(end);
|
||||
for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
|
||||
page_unprotect(addr);
|
||||
}
|
||||
}
|
||||
|
||||
/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
|
||||
tb[1].tc_ptr. Return NULL if not found */
|
||||
TranslationBlock *tb_find_pc(unsigned long tc_ptr)
|
||||
{
|
||||
int m_min, m_max, m;
|
||||
unsigned long v;
|
||||
TranslationBlock *tb;
|
||||
|
||||
if (nb_tbs <= 0)
|
||||
return NULL;
|
||||
if (tc_ptr < (unsigned long)code_gen_buffer ||
|
||||
tc_ptr >= (unsigned long)code_gen_ptr)
|
||||
return NULL;
|
||||
/* binary search (cf Knuth) */
|
||||
m_min = 0;
|
||||
m_max = nb_tbs - 1;
|
||||
while (m_min <= m_max) {
|
||||
m = (m_min + m_max) >> 1;
|
||||
tb = &tbs[m];
|
||||
v = (unsigned long)tb->tc_ptr;
|
||||
if (v == tc_ptr)
|
||||
return tb;
|
||||
else if (tc_ptr < v) {
|
||||
m_max = m - 1;
|
||||
} else {
|
||||
m_min = m + 1;
|
||||
}
|
||||
}
|
||||
return &tbs[m_max];
|
||||
}
|
||||
|
||||
static void tb_reset_jump_recursive(TranslationBlock *tb);
|
||||
|
||||
static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
|
||||
{
|
||||
TranslationBlock *tb1, *tb_next, **ptb;
|
||||
unsigned int n1;
|
||||
|
||||
tb1 = tb->jmp_next[n];
|
||||
if (tb1 != NULL) {
|
||||
/* find head of list */
|
||||
for(;;) {
|
||||
n1 = (long)tb1 & 3;
|
||||
tb1 = (TranslationBlock *)((long)tb1 & ~3);
|
||||
if (n1 == 2)
|
||||
break;
|
||||
tb1 = tb1->jmp_next[n1];
|
||||
}
|
||||
/* we are now sure now that tb jumps to tb1 */
|
||||
tb_next = tb1;
|
||||
|
||||
/* remove tb from the jmp_first list */
|
||||
ptb = &tb_next->jmp_first;
|
||||
for(;;) {
|
||||
tb1 = *ptb;
|
||||
n1 = (long)tb1 & 3;
|
||||
tb1 = (TranslationBlock *)((long)tb1 & ~3);
|
||||
if (n1 == n && tb1 == tb)
|
||||
break;
|
||||
ptb = &tb1->jmp_next[n1];
|
||||
}
|
||||
*ptb = tb->jmp_next[n];
|
||||
tb->jmp_next[n] = NULL;
|
||||
|
||||
/* suppress the jump to next tb in generated code */
|
||||
tb_reset_jump(tb, n);
|
||||
|
||||
/* suppress jumps in the tb on which we could have jump */
|
||||
tb_reset_jump_recursive(tb_next);
|
||||
}
|
||||
}
|
||||
|
||||
static void tb_reset_jump_recursive(TranslationBlock *tb)
|
||||
{
|
||||
tb_reset_jump_recursive2(tb, 0);
|
||||
tb_reset_jump_recursive2(tb, 1);
|
||||
}
|
||||
|
||||
/* mask must never be zero */
|
||||
void cpu_interrupt(CPUState *env, int mask)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
|
||||
env->interrupt_request |= mask;
|
||||
/* if the cpu is currently executing code, we must unlink it and
|
||||
all the potentially executing TB */
|
||||
tb = env->current_tb;
|
||||
if (tb) {
|
||||
tb_reset_jump_recursive(tb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void cpu_abort(CPUState *env, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "qemu: fatal: ");
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
#ifdef TARGET_I386
|
||||
cpu_x86_dump_state(env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP);
|
||||
#endif
|
||||
va_end(ap);
|
||||
abort();
|
||||
}
|
||||
|
||||
#ifdef TARGET_I386
|
||||
/* unmap all maped pages and flush all associated code */
|
||||
void page_unmap(void)
|
||||
{
|
||||
PageDesc *p, *pmap;
|
||||
unsigned long addr;
|
||||
int i, j, ret, j1;
|
||||
|
||||
for(i = 0; i < L1_SIZE; i++) {
|
||||
pmap = l1_map[i];
|
||||
if (pmap) {
|
||||
p = pmap;
|
||||
for(j = 0;j < L2_SIZE;) {
|
||||
if (p->flags & PAGE_VALID) {
|
||||
addr = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
|
||||
/* we try to find a range to make less syscalls */
|
||||
j1 = j;
|
||||
p++;
|
||||
j++;
|
||||
while (j < L2_SIZE && (p->flags & PAGE_VALID)) {
|
||||
p++;
|
||||
j++;
|
||||
}
|
||||
ret = munmap((void *)addr, (j - j1) << TARGET_PAGE_BITS);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Could not unmap page 0x%08lx\n", addr);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
p++;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
free(pmap);
|
||||
l1_map[i] = NULL;
|
||||
}
|
||||
}
|
||||
tb_flush();
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
* internal execution defines for qemu
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* allow to see translation results - the slowdown should be negligible, so we leave it */
|
||||
#define DEBUG_DISAS
|
||||
|
||||
/* is_jmp field values */
|
||||
#define DISAS_NEXT 0 /* next instruction can be analyzed */
|
||||
#define DISAS_JUMP 1 /* only pc was modified dynamically */
|
||||
#define DISAS_UPDATE 2 /* cpu state was modified dynamically */
|
||||
#define DISAS_TB_JUMP 3 /* only pc was modified statically */
|
||||
|
||||
struct TranslationBlock;
|
||||
|
||||
/* XXX: make safe guess about sizes */
|
||||
#define MAX_OP_PER_INSTR 32
|
||||
#define OPC_BUF_SIZE 512
|
||||
#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR)
|
||||
|
||||
#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * 3)
|
||||
|
||||
extern uint16_t gen_opc_buf[OPC_BUF_SIZE];
|
||||
extern uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
|
||||
extern uint32_t gen_opc_pc[OPC_BUF_SIZE];
|
||||
extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
|
||||
extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
|
||||
#define GEN_FLAG_CODE32_SHIFT 0
|
||||
#define GEN_FLAG_ADDSEG_SHIFT 1
|
||||
#define GEN_FLAG_SS32_SHIFT 2
|
||||
#define GEN_FLAG_VM_SHIFT 3
|
||||
#define GEN_FLAG_ST_SHIFT 4
|
||||
#define GEN_FLAG_TF_SHIFT 8 /* same position as eflags */
|
||||
#define GEN_FLAG_CPL_SHIFT 9
|
||||
#define GEN_FLAG_IOPL_SHIFT 12 /* same position as eflags */
|
||||
|
||||
#endif
|
||||
|
||||
extern FILE *logfile;
|
||||
extern int loglevel;
|
||||
|
||||
int gen_intermediate_code(struct TranslationBlock *tb);
|
||||
int gen_intermediate_code_pc(struct TranslationBlock *tb);
|
||||
void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf);
|
||||
int cpu_gen_code(struct TranslationBlock *tb,
|
||||
int max_code_size, int *gen_code_size_ptr);
|
||||
int cpu_restore_state(struct TranslationBlock *tb,
|
||||
CPUState *env, unsigned long searched_pc);
|
||||
void cpu_exec_init(void);
|
||||
int page_unprotect(unsigned long address);
|
||||
void page_unmap(void);
|
||||
|
||||
#define CODE_GEN_MAX_SIZE 65536
|
||||
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
|
||||
|
||||
#define CODE_GEN_HASH_BITS 15
|
||||
#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS)
|
||||
|
||||
/* maximum total translate dcode allocated */
|
||||
#define CODE_GEN_BUFFER_SIZE (2048 * 1024)
|
||||
//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
|
||||
|
||||
#if defined(__powerpc__)
|
||||
#define USE_DIRECT_JUMP
|
||||
#endif
|
||||
|
||||
typedef struct TranslationBlock {
|
||||
unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */
|
||||
unsigned long cs_base; /* CS base for this block */
|
||||
unsigned int flags; /* flags defining in which context the code was generated */
|
||||
uint16_t size; /* size of target code for this block (1 <=
|
||||
size <= TARGET_PAGE_SIZE) */
|
||||
uint8_t *tc_ptr; /* pointer to the translated code */
|
||||
struct TranslationBlock *hash_next; /* next matching block */
|
||||
struct TranslationBlock *page_next[2]; /* next blocks in even/odd page */
|
||||
/* the following data are used to directly call another TB from
|
||||
the code of this one. */
|
||||
uint16_t tb_next_offset[2]; /* offset of original jump target */
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
uint16_t tb_jmp_offset[2]; /* offset of jump instruction */
|
||||
#else
|
||||
uint32_t tb_next[2]; /* address of jump generated code */
|
||||
#endif
|
||||
/* list of TBs jumping to this one. This is a circular list using
|
||||
the two least significant bits of the pointers to tell what is
|
||||
the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 =
|
||||
jmp_first */
|
||||
struct TranslationBlock *jmp_next[2];
|
||||
struct TranslationBlock *jmp_first;
|
||||
} TranslationBlock;
|
||||
|
||||
static inline unsigned int tb_hash_func(unsigned long pc)
|
||||
{
|
||||
return pc & (CODE_GEN_HASH_SIZE - 1);
|
||||
}
|
||||
|
||||
TranslationBlock *tb_alloc(unsigned long pc);
|
||||
void tb_flush(void);
|
||||
void tb_link(TranslationBlock *tb);
|
||||
|
||||
extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
|
||||
|
||||
extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
|
||||
extern uint8_t *code_gen_ptr;
|
||||
|
||||
/* find a translation block in the translation cache. If not found,
|
||||
return NULL and the pointer to the last element of the list in pptb */
|
||||
static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
|
||||
unsigned long pc,
|
||||
unsigned long cs_base,
|
||||
unsigned int flags)
|
||||
{
|
||||
TranslationBlock **ptb, *tb;
|
||||
unsigned int h;
|
||||
|
||||
h = tb_hash_func(pc);
|
||||
ptb = &tb_hash[h];
|
||||
for(;;) {
|
||||
tb = *ptb;
|
||||
if (!tb)
|
||||
break;
|
||||
if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
|
||||
return tb;
|
||||
ptb = &tb->hash_next;
|
||||
}
|
||||
*pptb = ptb;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(__powerpc__)
|
||||
|
||||
static inline void tb_set_jmp_target(TranslationBlock *tb,
|
||||
int n, unsigned long addr)
|
||||
{
|
||||
uint32_t val, *ptr;
|
||||
unsigned long offset;
|
||||
|
||||
offset = (unsigned long)(tb->tc_ptr + tb->tb_jmp_offset[n]);
|
||||
|
||||
/* patch the branch destination */
|
||||
ptr = (uint32_t *)offset;
|
||||
val = *ptr;
|
||||
val = (val & ~0x03fffffc) | ((addr - offset) & 0x03fffffc);
|
||||
*ptr = val;
|
||||
/* flush icache */
|
||||
asm volatile ("dcbst 0,%0" : : "r"(ptr) : "memory");
|
||||
asm volatile ("sync" : : : "memory");
|
||||
asm volatile ("icbi 0,%0" : : "r"(ptr) : "memory");
|
||||
asm volatile ("sync" : : : "memory");
|
||||
asm volatile ("isync" : : : "memory");
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* set the jump target */
|
||||
static inline void tb_set_jmp_target(TranslationBlock *tb,
|
||||
int n, unsigned long addr)
|
||||
{
|
||||
tb->tb_next[n] = addr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline void tb_add_jump(TranslationBlock *tb, int n,
|
||||
TranslationBlock *tb_next)
|
||||
{
|
||||
/* NOTE: this test is only needed for thread safety */
|
||||
if (!tb->jmp_next[n]) {
|
||||
/* patch the native jump address */
|
||||
tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr);
|
||||
|
||||
/* add in TB jmp circular list */
|
||||
tb->jmp_next[n] = tb_next->jmp_first;
|
||||
tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n));
|
||||
}
|
||||
}
|
||||
|
||||
TranslationBlock *tb_find_pc(unsigned long pc_ptr);
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||
#endif
|
||||
|
||||
#if defined(__powerpc__)
|
||||
|
||||
/* on PowerPC we patch the jump instruction directly */
|
||||
#define JUMP_TB(tbparam, n, eip)\
|
||||
do {\
|
||||
static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
|
||||
asm volatile ("b %0" : : "i" (&__op_jmp ## n));\
|
||||
label ## n:\
|
||||
T0 = (long)(tbparam) + (n);\
|
||||
EIP = eip;\
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
||||
/* jump to next block operations (more portable code, does not need
|
||||
cache flushing, but slower because of indirect jump) */
|
||||
#define JUMP_TB(tbparam, n, eip)\
|
||||
do {\
|
||||
static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
|
||||
static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\
|
||||
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
|
||||
label ## n:\
|
||||
T0 = (long)(tbparam) + (n);\
|
||||
EIP = eip;\
|
||||
dummy_label ## n:\
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __powerpc__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
"0: lwarx %0,0,%1 ;"
|
||||
" xor. %0,%3,%0;"
|
||||
" bne 1f;"
|
||||
" stwcx. %2,0,%1;"
|
||||
" bne- 0b;"
|
||||
"1: "
|
||||
: "=&r" (ret)
|
||||
: "r" (p), "r" (1), "r" (0)
|
||||
: "cr0", "memory");
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __i386__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
char ret;
|
||||
long int readval;
|
||||
|
||||
__asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
|
||||
: "=q" (ret), "=m" (*p), "=a" (readval)
|
||||
: "r" (1), "m" (*p), "a" (0)
|
||||
: "memory");
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __s390__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
|
||||
" jl 0b"
|
||||
: "=&d" (ret)
|
||||
: "r" (1), "a" (p), "0" (*p)
|
||||
: "cc", "memory" );
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
unsigned long one;
|
||||
|
||||
__asm__ __volatile__ ("0: mov 1,%2\n"
|
||||
" ldl_l %0,%1\n"
|
||||
" stl_c %2,%1\n"
|
||||
" beq %2,1f\n"
|
||||
".subsection 2\n"
|
||||
"1: br 0b\n"
|
||||
".previous"
|
||||
: "=r" (ret), "=m" (*p), "=r" (one)
|
||||
: "m" (*p));
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __sparc__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm__ __volatile__("ldstub [%1], %0"
|
||||
: "=r" (ret)
|
||||
: "r" (p)
|
||||
: "memory");
|
||||
|
||||
return (ret ? 1 : 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __arm__
|
||||
static inline int testandset (int *spinlock)
|
||||
{
|
||||
register unsigned int ret;
|
||||
__asm__ __volatile__("swp %0, %1, [%2]"
|
||||
: "=r"(ret)
|
||||
: "0"(1), "r"(spinlock));
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef int spinlock_t;
|
||||
|
||||
#define SPIN_LOCK_UNLOCKED 0
|
||||
|
||||
#if 1
|
||||
static inline void spin_lock(spinlock_t *lock)
|
||||
{
|
||||
while (testandset(lock));
|
||||
}
|
||||
|
||||
static inline void spin_unlock(spinlock_t *lock)
|
||||
{
|
||||
*lock = 0;
|
||||
}
|
||||
|
||||
static inline int spin_trylock(spinlock_t *lock)
|
||||
{
|
||||
return !testandset(lock);
|
||||
}
|
||||
#else
|
||||
static inline void spin_lock(spinlock_t *lock)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void spin_unlock(spinlock_t *lock)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int spin_trylock(spinlock_t *lock)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern spinlock_t tb_lock;
|
||||
|
||||
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
* gdb server stub
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "config.h"
|
||||
#ifdef TARGET_I386
|
||||
#include "cpu-i386.h"
|
||||
#endif
|
||||
#ifdef TARGET_ARM
|
||||
#include "cpu-arm.h"
|
||||
#endif
|
||||
#include "thunk.h"
|
||||
#include "exec.h"
|
||||
|
||||
//#define DEBUG_GDB
|
||||
|
||||
int gdbstub_fd = -1;
|
||||
|
||||
/* return 0 if OK */
|
||||
static int gdbstub_open(int port)
|
||||
{
|
||||
struct sockaddr_in sockaddr;
|
||||
socklen_t len;
|
||||
int fd, val, ret;
|
||||
|
||||
fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* allow fast reuse */
|
||||
val = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
|
||||
|
||||
sockaddr.sin_family = AF_INET;
|
||||
sockaddr.sin_port = htons(port);
|
||||
sockaddr.sin_addr.s_addr = 0;
|
||||
ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
|
||||
if (ret < 0) {
|
||||
perror("bind");
|
||||
return -1;
|
||||
}
|
||||
ret = listen(fd, 0);
|
||||
if (ret < 0) {
|
||||
perror("listen");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* now wait for one connection */
|
||||
for(;;) {
|
||||
len = sizeof(sockaddr);
|
||||
gdbstub_fd = accept(fd, (struct sockaddr *)&sockaddr, &len);
|
||||
if (gdbstub_fd < 0 && errno != EINTR) {
|
||||
perror("accept");
|
||||
return -1;
|
||||
} else if (gdbstub_fd >= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* set short latency */
|
||||
val = 1;
|
||||
setsockopt(gdbstub_fd, SOL_TCP, TCP_NODELAY, &val, sizeof(val));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_char(void)
|
||||
{
|
||||
uint8_t ch;
|
||||
int ret;
|
||||
|
||||
for(;;) {
|
||||
ret = read(gdbstub_fd, &ch, 1);
|
||||
if (ret < 0) {
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
return -1;
|
||||
} else if (ret == 0) {
|
||||
return -1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
static void put_buffer(const uint8_t *buf, int len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
while (len > 0) {
|
||||
ret = write(gdbstub_fd, buf, len);
|
||||
if (ret < 0) {
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
return;
|
||||
} else {
|
||||
buf += ret;
|
||||
len -= ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline int fromhex(int v)
|
||||
{
|
||||
if (v >= '0' && v <= '9')
|
||||
return v - '0';
|
||||
else if (v >= 'A' && v <= 'F')
|
||||
return v - 'A' + 10;
|
||||
else if (v >= 'a' && v <= 'f')
|
||||
return v - 'a' + 10;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int tohex(int v)
|
||||
{
|
||||
if (v < 10)
|
||||
return v + '0';
|
||||
else
|
||||
return v - 10 + 'a';
|
||||
}
|
||||
|
||||
static void memtohex(char *buf, const uint8_t *mem, int len)
|
||||
{
|
||||
int i, c;
|
||||
char *q;
|
||||
q = buf;
|
||||
for(i = 0; i < len; i++) {
|
||||
c = mem[i];
|
||||
*q++ = tohex(c >> 4);
|
||||
*q++ = tohex(c & 0xf);
|
||||
}
|
||||
*q = '\0';
|
||||
}
|
||||
|
||||
static void hextomem(uint8_t *mem, const char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < len; i++) {
|
||||
mem[i] = (fromhex(buf[0]) << 4) | fromhex(buf[1]);
|
||||
buf += 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* return -1 if error or EOF */
|
||||
static int get_packet(char *buf, int buf_size)
|
||||
{
|
||||
int ch, len, csum, csum1;
|
||||
char reply[1];
|
||||
|
||||
for(;;) {
|
||||
for(;;) {
|
||||
ch = get_char();
|
||||
if (ch < 0)
|
||||
return -1;
|
||||
if (ch == '$')
|
||||
break;
|
||||
}
|
||||
len = 0;
|
||||
csum = 0;
|
||||
for(;;) {
|
||||
ch = get_char();
|
||||
if (ch < 0)
|
||||
return -1;
|
||||
if (ch == '#')
|
||||
break;
|
||||
if (len > buf_size - 1)
|
||||
return -1;
|
||||
buf[len++] = ch;
|
||||
csum += ch;
|
||||
}
|
||||
buf[len] = '\0';
|
||||
ch = get_char();
|
||||
if (ch < 0)
|
||||
return -1;
|
||||
csum1 = fromhex(ch) << 4;
|
||||
ch = get_char();
|
||||
if (ch < 0)
|
||||
return -1;
|
||||
csum1 |= fromhex(ch);
|
||||
if ((csum & 0xff) != csum1) {
|
||||
reply[0] = '-';
|
||||
put_buffer(reply, 1);
|
||||
} else {
|
||||
reply[0] = '+';
|
||||
put_buffer(reply, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_GDB
|
||||
printf("command='%s'\n", buf);
|
||||
#endif
|
||||
return len;
|
||||
}
|
||||
|
||||
/* return -1 if error, 0 if OK */
|
||||
static int put_packet(char *buf)
|
||||
{
|
||||
char buf1[3];
|
||||
int len, csum, ch, i;
|
||||
|
||||
#ifdef DEBUG_GDB
|
||||
printf("reply='%s'\n", buf);
|
||||
#endif
|
||||
|
||||
for(;;) {
|
||||
buf1[0] = '$';
|
||||
put_buffer(buf1, 1);
|
||||
len = strlen(buf);
|
||||
put_buffer(buf, len);
|
||||
csum = 0;
|
||||
for(i = 0; i < len; i++) {
|
||||
csum += buf[i];
|
||||
}
|
||||
buf1[0] = '#';
|
||||
buf1[1] = tohex((csum >> 4) & 0xf);
|
||||
buf1[2] = tohex((csum) & 0xf);
|
||||
|
||||
put_buffer(buf1, 3);
|
||||
|
||||
ch = get_char();
|
||||
if (ch < 0)
|
||||
return -1;
|
||||
if (ch == '+')
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write)
|
||||
{
|
||||
int l, flags;
|
||||
uint32_t page;
|
||||
|
||||
while (len > 0) {
|
||||
page = addr & TARGET_PAGE_MASK;
|
||||
l = (page + TARGET_PAGE_SIZE) - addr;
|
||||
if (l > len)
|
||||
l = len;
|
||||
flags = page_get_flags(page);
|
||||
if (!(flags & PAGE_VALID))
|
||||
return -1;
|
||||
if (is_write) {
|
||||
if (!(flags & PAGE_WRITE))
|
||||
return -1;
|
||||
memcpy((uint8_t *)addr, buf, l);
|
||||
} else {
|
||||
if (!(flags & PAGE_READ))
|
||||
return -1;
|
||||
memcpy(buf, (uint8_t *)addr, l);
|
||||
}
|
||||
len -= l;
|
||||
buf += l;
|
||||
addr += l;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* port = 0 means default port */
|
||||
int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port)
|
||||
{
|
||||
CPUState *env;
|
||||
const char *p;
|
||||
int ret, ch, nb_regs, i;
|
||||
char buf[4096];
|
||||
uint8_t mem_buf[2000];
|
||||
uint32_t *registers;
|
||||
uint32_t addr, len;
|
||||
|
||||
printf("Waiting gdb connection on port %d\n", port);
|
||||
if (gdbstub_open(port) < 0)
|
||||
return -1;
|
||||
printf("Connected\n");
|
||||
for(;;) {
|
||||
ret = get_packet(buf, sizeof(buf));
|
||||
if (ret < 0)
|
||||
break;
|
||||
p = buf;
|
||||
ch = *p++;
|
||||
switch(ch) {
|
||||
case '?':
|
||||
snprintf(buf, sizeof(buf), "S%02x", SIGTRAP);
|
||||
put_packet(buf);
|
||||
break;
|
||||
case 'c':
|
||||
main_loop(opaque);
|
||||
snprintf(buf, sizeof(buf), "S%02x", 0);
|
||||
put_packet(buf);
|
||||
break;
|
||||
case 'g':
|
||||
env = cpu_gdbstub_get_env(opaque);
|
||||
registers = (void *)mem_buf;
|
||||
#if defined(TARGET_I386)
|
||||
for(i = 0; i < 8; i++) {
|
||||
registers[i] = tswapl(env->regs[i]);
|
||||
}
|
||||
registers[8] = env->eip;
|
||||
registers[9] = env->eflags;
|
||||
registers[10] = env->segs[R_CS].selector;
|
||||
registers[11] = env->segs[R_SS].selector;
|
||||
registers[12] = env->segs[R_DS].selector;
|
||||
registers[13] = env->segs[R_ES].selector;
|
||||
registers[14] = env->segs[R_FS].selector;
|
||||
registers[15] = env->segs[R_GS].selector;
|
||||
nb_regs = 16;
|
||||
#endif
|
||||
memtohex(buf, (const uint8_t *)registers,
|
||||
sizeof(registers[0]) * nb_regs);
|
||||
put_packet(buf);
|
||||
break;
|
||||
case 'G':
|
||||
env = cpu_gdbstub_get_env(opaque);
|
||||
registers = (void *)mem_buf;
|
||||
#if defined(TARGET_I386)
|
||||
hextomem((uint8_t *)registers, p, 16 * 4);
|
||||
for(i = 0; i < 8; i++) {
|
||||
env->regs[i] = tswapl(registers[i]);
|
||||
}
|
||||
env->eip = registers[8];
|
||||
env->eflags = registers[9];
|
||||
#define LOAD_SEG(index, sreg)\
|
||||
if (tswapl(registers[index]) != env->segs[sreg].selector)\
|
||||
cpu_x86_load_seg(env, sreg, tswapl(registers[index]));
|
||||
LOAD_SEG(10, R_CS);
|
||||
LOAD_SEG(11, R_SS);
|
||||
LOAD_SEG(12, R_DS);
|
||||
LOAD_SEG(13, R_ES);
|
||||
LOAD_SEG(14, R_FS);
|
||||
LOAD_SEG(15, R_GS);
|
||||
#endif
|
||||
put_packet("OK");
|
||||
break;
|
||||
case 'm':
|
||||
addr = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
len = strtoul(p, NULL, 16);
|
||||
if (memory_rw(mem_buf, addr, len, 0) != 0)
|
||||
memset(mem_buf, 0, len);
|
||||
memtohex(buf, mem_buf, len);
|
||||
put_packet(buf);
|
||||
break;
|
||||
case 'M':
|
||||
addr = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
len = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
hextomem(mem_buf, p, len);
|
||||
if (memory_rw(mem_buf, addr, len, 1) != 0)
|
||||
put_packet("ENN");
|
||||
else
|
||||
put_packet("OK");
|
||||
break;
|
||||
default:
|
||||
/* put empty packet */
|
||||
buf[0] = '\0';
|
||||
put_packet(buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Whitespace-only changes.
+1471
File diff suppressed because it is too large.
Load diff
+5
-4
@@ -33,12 +33,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
* the Intel manual for details.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "dis-asm.h"
|
||||
|
||||
#define MAXLEN 20
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *));
|
||||
|
||||
struct dis_private
|
||||
@@ -1163,8 +1164,8 @@ int
|
||||
print_insn_x86 (pc, info, aflag, dflag)
|
||||
bfd_vma pc;
|
||||
disassemble_info *info;
|
||||
int aflag;
|
||||
int dflag;
|
||||
int volatile aflag;
|
||||
int volatile dflag;
|
||||
{
|
||||
struct dis386 *dp;
|
||||
int i;
|
||||
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
/* ld script to make i386 Linux kernel
|
||||
* Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
|
||||
*/
|
||||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
/* Read-only sections, merged into text segment: */
|
||||
. = 0xa8000000 + SIZEOF_HEADERS;
|
||||
.interp : { *(.interp) }
|
||||
.hash : { *(.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
.rel.text :
|
||||
{ *(.rel.text) *(.rel.gnu.linkonce.t*) }
|
||||
.rela.text :
|
||||
{ *(.rela.text) *(.rela.gnu.linkonce.t*) }
|
||||
.rel.data :
|
||||
{ *(.rel.data) *(.rel.gnu.linkonce.d*) }
|
||||
.rela.data :
|
||||
{ *(.rela.data) *(.rela.gnu.linkonce.d*) }
|
||||
.rel.rodata :
|
||||
{ *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
|
||||
.rela.rodata :
|
||||
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
|
||||
.rel.got : { *(.rel.got) }
|
||||
.rela.got : { *(.rela.got) }
|
||||
.rel.ctors : { *(.rel.ctors) }
|
||||
.rela.ctors : { *(.rela.ctors) }
|
||||
.rel.dtors : { *(.rel.dtors) }
|
||||
.rela.dtors : { *(.rela.dtors) }
|
||||
.rel.init : { *(.rel.init) }
|
||||
.rela.init : { *(.rela.init) }
|
||||
.rel.fini : { *(.rel.fini) }
|
||||
.rela.fini : { *(.rela.fini) }
|
||||
.rel.bss : { *(.rel.bss) }
|
||||
.rela.bss : { *(.rela.bss) }
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.init : { *(.init) } =0x47ff041f
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||
*(.gnu.warning)
|
||||
*(.gnu.linkonce.t*)
|
||||
} =0x47ff041f
|
||||
_etext = .;
|
||||
PROVIDE (etext = .);
|
||||
.fini : { *(.fini) } =0x47ff041f
|
||||
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.reginfo : { *(.reginfo) }
|
||||
__preinit_array_start = .;
|
||||
.preinit_array : { *(.preinit_array) }
|
||||
__preinit_array_end = .;
|
||||
__init_array_start = .;
|
||||
.init_array : { *(.init_array) }
|
||||
__init_array_end = .;
|
||||
__fini_array_start = .;
|
||||
.fini_array : { *(.fini_array) }
|
||||
__fini_array_end = .;
|
||||
|
||||
/* Adjust the address for the data segment. We want to adjust up to
|
||||
the same address within the page on the next page up. */
|
||||
. = ALIGN(0x100000) + (. & (0x100000 - 1));
|
||||
.data :
|
||||
{
|
||||
*(.data)
|
||||
*(.gnu.linkonce.d*)
|
||||
CONSTRUCTORS
|
||||
}
|
||||
.data1 : { *(.data1) }
|
||||
.ctors :
|
||||
{
|
||||
*(.ctors)
|
||||
}
|
||||
.dtors :
|
||||
{
|
||||
*(.dtors)
|
||||
}
|
||||
.plt : { *(.plt) }
|
||||
.got : { *(.got.plt) *(.got) }
|
||||
.dynamic : { *(.dynamic) }
|
||||
/* We want the small data sections together, so single-instruction offsets
|
||||
can access them all, and initialized data all before uninitialized, so
|
||||
we can shorten the on-disk segment size. */
|
||||
.sdata : { *(.sdata) }
|
||||
_edata = .;
|
||||
PROVIDE (edata = .);
|
||||
__bss_start = .;
|
||||
.sbss : { *(.sbss) *(.scommon) }
|
||||
.bss :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
}
|
||||
_end = . ;
|
||||
PROVIDE (end = .);
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
/* These must appear regardless of . */
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/* derived from glibc sysdeps/unix/sysv/linux/ia64/sysdep.S */
|
||||
|
||||
#define __ASSEMBLY__
|
||||
|
||||
#include <asm/asmmacro.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
ENTRY(__syscall_error)
|
||||
.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(0)
|
||||
alloc r33=ar.pfs, 0, 4, 0, 0
|
||||
mov r32=rp
|
||||
.body
|
||||
mov r35=r8
|
||||
mov r34=r1
|
||||
;;
|
||||
br.call.sptk.many b0 = __errno_location
|
||||
.Lret0: /* force new bundle */
|
||||
st4 [r8]=r35
|
||||
mov r1=r34
|
||||
mov rp=r32
|
||||
mov r8=-1
|
||||
mov ar.pfs=r33
|
||||
br.ret.sptk.few b0
|
||||
END(__syscall_error)
|
||||
|
||||
GLOBAL_ENTRY(__ia64_syscall)
|
||||
mov r15=r37 /* syscall number */
|
||||
break __BREAK_SYSCALL
|
||||
cmp.eq p6,p0=-1,r10 /* r10 = -1 on error */
|
||||
(p6) br.cond.spnt.few __syscall_error
|
||||
br.ret.sptk.few b0
|
||||
.endp __ia64_syscall
|
||||
+358
-166
@@ -11,18 +11,12 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "qemu.h"
|
||||
#include "disas.h"
|
||||
|
||||
#ifdef TARGET_I386
|
||||
|
||||
#define ELF_START_MMAP 0x80000000
|
||||
|
||||
typedef uint32_t elf_greg_t;
|
||||
|
||||
#define ELF_NGREG (sizeof (struct target_pt_regs) / sizeof(elf_greg_t))
|
||||
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
|
||||
|
||||
typedef struct user_i387_struct elf_fpregset_t;
|
||||
|
||||
/*
|
||||
* This is used to ensure we don't load something for the wrong architecture.
|
||||
*/
|
||||
@@ -44,33 +38,126 @@ typedef struct user_i387_struct elf_fpregset_t;
|
||||
A value of 0 tells we have no such handler. */
|
||||
#define ELF_PLAT_INIT(_r) _r->edx = 0
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
regs->esp = infop->start_stack;
|
||||
regs->eip = infop->entry;
|
||||
}
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_ARM
|
||||
|
||||
#define ELF_START_MMAP 0x80000000
|
||||
|
||||
#define elf_check_arch(x) ( (x) == EM_ARM )
|
||||
|
||||
#define ELF_CLASS ELFCLASS32
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
#define ELF_DATA ELFDATA2MSB
|
||||
#else
|
||||
#define ELF_DATA ELFDATA2LSB
|
||||
#endif
|
||||
#define ELF_ARCH EM_ARM
|
||||
|
||||
#define ELF_PLAT_INIT(_r) _r->ARM_r0 = 0
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
target_long *stack = (void *)infop->start_stack;
|
||||
memset(regs, 0, sizeof(*regs));
|
||||
regs->ARM_cpsr = 0x10;
|
||||
regs->ARM_pc = infop->entry;
|
||||
regs->ARM_sp = infop->start_stack;
|
||||
regs->ARM_r2 = tswapl(stack[2]); /* envp */
|
||||
regs->ARM_r1 = tswapl(stack[1]); /* argv */
|
||||
regs->ARM_r0 = tswapl(stack[0]); /* argc */
|
||||
}
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
|
||||
#endif
|
||||
|
||||
#include "linux_bin.h"
|
||||
#include "elf.h"
|
||||
#include "segment.h"
|
||||
|
||||
/*
|
||||
* MAX_ARG_PAGES defines the number of pages allocated for arguments
|
||||
* and envelope for the new program. 32 should suffice, this gives
|
||||
* a maximum env+arg of 128kB w/4KB pages!
|
||||
*/
|
||||
#define MAX_ARG_PAGES 32
|
||||
|
||||
/*
|
||||
* This structure is used to hold the arguments that are
|
||||
* used when loading binaries.
|
||||
*/
|
||||
struct linux_binprm {
|
||||
char buf[128];
|
||||
unsigned long page[MAX_ARG_PAGES];
|
||||
unsigned long p;
|
||||
int sh_bang;
|
||||
int fd;
|
||||
int e_uid, e_gid;
|
||||
int argc, envc;
|
||||
char * filename; /* Name of binary */
|
||||
unsigned long loader, exec;
|
||||
int dont_iput; /* binfmt handler has put inode */
|
||||
};
|
||||
|
||||
struct exec
|
||||
{
|
||||
unsigned int a_info; /* Use macros N_MAGIC, etc for access */
|
||||
unsigned int a_text; /* length of text, in bytes */
|
||||
unsigned int a_data; /* length of data, in bytes */
|
||||
unsigned int a_bss; /* length of uninitialized data area, in bytes */
|
||||
unsigned int a_syms; /* length of symbol table data in file, in bytes */
|
||||
unsigned int a_entry; /* start address */
|
||||
unsigned int a_trsize; /* length of relocation info for text, in bytes */
|
||||
unsigned int a_drsize; /* length of relocation info for data, in bytes */
|
||||
};
|
||||
|
||||
|
||||
#define N_MAGIC(exec) ((exec).a_info & 0xffff)
|
||||
#define OMAGIC 0407
|
||||
#define NMAGIC 0410
|
||||
#define ZMAGIC 0413
|
||||
#define QMAGIC 0314
|
||||
|
||||
/* max code+data+bss space allocated to elf interpreter */
|
||||
#define INTERP_MAP_SIZE (32 * 1024 * 1024)
|
||||
|
||||
/* max code+data+bss+brk space allocated to ET_DYN executables */
|
||||
#define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
|
||||
|
||||
/* from personality.h */
|
||||
|
||||
/* Flags for bug emulation. These occupy the top three bytes. */
|
||||
#define STICKY_TIMEOUTS 0x4000000
|
||||
#define WHOLE_SECONDS 0x2000000
|
||||
|
||||
/* Personality types. These go in the low byte. Avoid using the top bit,
|
||||
* it will conflict with error returns.
|
||||
*/
|
||||
#define PER_MASK (0x00ff)
|
||||
#define PER_LINUX (0x0000)
|
||||
#define PER_SVR4 (0x0001 | STICKY_TIMEOUTS)
|
||||
#define PER_SVR3 (0x0002 | STICKY_TIMEOUTS)
|
||||
#define PER_SCOSVR3 (0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS)
|
||||
#define PER_WYSEV386 (0x0004 | STICKY_TIMEOUTS)
|
||||
#define PER_ISCR4 (0x0005 | STICKY_TIMEOUTS)
|
||||
#define PER_BSD (0x0006)
|
||||
#define PER_XENIX (0x0007 | STICKY_TIMEOUTS)
|
||||
|
||||
/* Necessary parameters */
|
||||
#define ALPHA_PAGE_SIZE 4096
|
||||
#define X86_PAGE_SIZE 4096
|
||||
|
||||
#define ALPHA_PAGE_MASK (~(ALPHA_PAGE_SIZE-1))
|
||||
#define X86_PAGE_MASK (~(X86_PAGE_SIZE-1))
|
||||
|
||||
#define ALPHA_PAGE_ALIGN(addr) ((((addr)+ALPHA_PAGE_SIZE)-1)&ALPHA_PAGE_MASK)
|
||||
#define X86_PAGE_ALIGN(addr) ((((addr)+X86_PAGE_SIZE)-1)&X86_PAGE_MASK)
|
||||
|
||||
#define NGROUPS 32
|
||||
|
||||
#define X86_ELF_EXEC_PAGESIZE X86_PAGE_SIZE
|
||||
#define X86_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(X86_ELF_EXEC_PAGESIZE-1))
|
||||
#define X86_ELF_PAGEOFFSET(_v) ((_v) & (X86_ELF_EXEC_PAGESIZE-1))
|
||||
|
||||
#define ALPHA_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ALPHA_PAGE_SIZE-1))
|
||||
#define ALPHA_ELF_PAGEOFFSET(_v) ((_v) & (ALPHA_PAGE_SIZE-1))
|
||||
#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
|
||||
#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
|
||||
#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
|
||||
|
||||
#define INTERPRETER_NONE 0
|
||||
#define INTERPRETER_AOUT 1
|
||||
@@ -78,11 +165,18 @@ typedef struct user_i387_struct elf_fpregset_t;
|
||||
|
||||
#define DLINFO_ITEMS 12
|
||||
|
||||
/* Where we find X86 libraries... */
|
||||
#define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x))
|
||||
#define get_user(ptr) (typeof(*ptr))(*(ptr))
|
||||
|
||||
static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
|
||||
{
|
||||
memcpy(to, from, n);
|
||||
}
|
||||
|
||||
//extern void * mmap4k();
|
||||
#define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f)
|
||||
static inline void memcpy_tofs(void * to, const void * from, unsigned long n)
|
||||
{
|
||||
memcpy(to, from, n);
|
||||
}
|
||||
|
||||
extern unsigned long x86_stack_size;
|
||||
|
||||
@@ -117,6 +211,28 @@ static void bswap_phdr(Elf32_Phdr *phdr)
|
||||
bswap32s(&phdr->p_flags); /* Segment flags */
|
||||
bswap32s(&phdr->p_align); /* Segment alignment */
|
||||
}
|
||||
|
||||
static void bswap_shdr(Elf32_Shdr *shdr)
|
||||
{
|
||||
bswap32s(&shdr->sh_name);
|
||||
bswap32s(&shdr->sh_type);
|
||||
bswap32s(&shdr->sh_flags);
|
||||
bswap32s(&shdr->sh_addr);
|
||||
bswap32s(&shdr->sh_offset);
|
||||
bswap32s(&shdr->sh_size);
|
||||
bswap32s(&shdr->sh_link);
|
||||
bswap32s(&shdr->sh_info);
|
||||
bswap32s(&shdr->sh_addralign);
|
||||
bswap32s(&shdr->sh_entsize);
|
||||
}
|
||||
|
||||
static void bswap_sym(Elf32_Sym *sym)
|
||||
{
|
||||
bswap32s(&sym->st_name);
|
||||
bswap32s(&sym->st_value);
|
||||
bswap32s(&sym->st_size);
|
||||
bswap16s(&sym->st_shndx);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void * get_free_page(void)
|
||||
@@ -126,8 +242,8 @@ static void * get_free_page(void)
|
||||
/* User-space version of kernel get_free_page. Returns a page-aligned
|
||||
* page-sized chunk of memory.
|
||||
*/
|
||||
retval = mmap4k(0, ALPHA_PAGE_SIZE, PROT_READ|PROT_WRITE,
|
||||
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
retval = (void *)target_mmap(0, host_page_size, PROT_READ|PROT_WRITE,
|
||||
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
if((long)retval == -1) {
|
||||
perror("get_free_page");
|
||||
@@ -140,7 +256,7 @@ static void * get_free_page(void)
|
||||
|
||||
static void free_page(void * pageaddr)
|
||||
{
|
||||
(void)munmap(pageaddr, ALPHA_PAGE_SIZE);
|
||||
target_munmap((unsigned long)pageaddr, host_page_size);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -171,9 +287,9 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
|
||||
while (len) {
|
||||
--p; --tmp; --len;
|
||||
if (--offset < 0) {
|
||||
offset = p % X86_PAGE_SIZE;
|
||||
if (!(pag = (char *) page[p/X86_PAGE_SIZE]) &&
|
||||
!(pag = (char *) page[p/X86_PAGE_SIZE] =
|
||||
offset = p % TARGET_PAGE_SIZE;
|
||||
if (!(pag = (char *) page[p/TARGET_PAGE_SIZE]) &&
|
||||
!(pag = (char *) page[p/TARGET_PAGE_SIZE] =
|
||||
(unsigned long *) get_free_page())) {
|
||||
return 0;
|
||||
}
|
||||
@@ -282,51 +398,43 @@ static int prepare_binprm(struct linux_binprm *bprm)
|
||||
unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
|
||||
struct image_info * info)
|
||||
{
|
||||
unsigned long stack_base;
|
||||
unsigned long stack_base, size, error;
|
||||
int i;
|
||||
extern unsigned long stktop;
|
||||
|
||||
stack_base = X86_STACK_TOP - MAX_ARG_PAGES*X86_PAGE_SIZE;
|
||||
/* Create enough stack to hold everything. If we don't use
|
||||
* it for args, we'll use it for something else...
|
||||
*/
|
||||
size = x86_stack_size;
|
||||
if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
|
||||
size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
|
||||
error = target_mmap(0,
|
||||
size + host_page_size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
if (error == -1) {
|
||||
perror("stk mmap");
|
||||
exit(-1);
|
||||
}
|
||||
/* we reserve one extra page at the top of the stack as guard */
|
||||
target_mprotect(error + size, host_page_size, PROT_NONE);
|
||||
|
||||
stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
|
||||
p += stack_base;
|
||||
|
||||
if (bprm->loader) {
|
||||
bprm->loader += stack_base;
|
||||
}
|
||||
bprm->exec += stack_base;
|
||||
|
||||
/* Create enough stack to hold everything. If we don't use
|
||||
* it for args, we'll use it for something else...
|
||||
*/
|
||||
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
|
||||
we allocate a bigger stack. Need a better solution, for example
|
||||
by remapping the process stack directly at the right place */
|
||||
if(x86_stack_size > MAX_ARG_PAGES*X86_PAGE_SIZE) {
|
||||
if((long)mmap4k((void *)(X86_STACK_TOP-x86_stack_size), x86_stack_size + X86_PAGE_SIZE,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
|
||||
perror("stk mmap");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if((long)mmap4k((void *)stack_base, (MAX_ARG_PAGES+1)*X86_PAGE_SIZE,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
|
||||
perror("stk mmap");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
stktop = stack_base;
|
||||
|
||||
for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
|
||||
if (bprm->page[i]) {
|
||||
info->rss++;
|
||||
|
||||
memcpy((void *)stack_base, (void *)bprm->page[i], X86_PAGE_SIZE);
|
||||
memcpy((void *)stack_base, (void *)bprm->page[i], TARGET_PAGE_SIZE);
|
||||
free_page((void *)bprm->page[i]);
|
||||
}
|
||||
stack_base += X86_PAGE_SIZE;
|
||||
stack_base += TARGET_PAGE_SIZE;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
@@ -334,13 +442,13 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
|
||||
static void set_brk(unsigned long start, unsigned long end)
|
||||
{
|
||||
/* page-align the start and end addresses... */
|
||||
start = ALPHA_PAGE_ALIGN(start);
|
||||
end = ALPHA_PAGE_ALIGN(end);
|
||||
start = HOST_PAGE_ALIGN(start);
|
||||
end = HOST_PAGE_ALIGN(end);
|
||||
if (end <= start)
|
||||
return;
|
||||
if((long)mmap4k(start, end - start,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
|
||||
if(target_mmap(start, end - start,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
|
||||
perror("cannot mmap brk");
|
||||
exit(-1);
|
||||
}
|
||||
@@ -358,9 +466,9 @@ static void padzero(unsigned long elf_bss)
|
||||
unsigned long nbyte;
|
||||
char * fpnt;
|
||||
|
||||
nbyte = elf_bss & (ALPHA_PAGE_SIZE-1); /* was X86_PAGE_SIZE - JRP */
|
||||
nbyte = elf_bss & (host_page_size-1); /* was TARGET_PAGE_SIZE - JRP */
|
||||
if (nbyte) {
|
||||
nbyte = ALPHA_PAGE_SIZE - nbyte;
|
||||
nbyte = host_page_size - nbyte;
|
||||
fpnt = (char *) elf_bss;
|
||||
do {
|
||||
*fpnt++ = 0;
|
||||
@@ -369,10 +477,11 @@ static void padzero(unsigned long elf_bss)
|
||||
}
|
||||
|
||||
static unsigned int * create_elf_tables(char *p, int argc, int envc,
|
||||
struct elfhdr * exec,
|
||||
unsigned long load_addr,
|
||||
unsigned long interp_load_addr, int ibcs,
|
||||
struct image_info *info)
|
||||
struct elfhdr * exec,
|
||||
unsigned long load_addr,
|
||||
unsigned long load_bias,
|
||||
unsigned long interp_load_addr, int ibcs,
|
||||
struct image_info *info)
|
||||
{
|
||||
target_ulong *argv, *envp, *dlinfo;
|
||||
target_ulong *sp;
|
||||
@@ -397,17 +506,17 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
|
||||
put_user (tswapl(val), dlinfo++)
|
||||
|
||||
if (exec) { /* Put this here for an ELF program interpreter */
|
||||
NEW_AUX_ENT (AT_PHDR, (unsigned int)(load_addr + exec->e_phoff));
|
||||
NEW_AUX_ENT (AT_PHENT, (unsigned int)(sizeof (struct elf_phdr)));
|
||||
NEW_AUX_ENT (AT_PHNUM, (unsigned int)(exec->e_phnum));
|
||||
NEW_AUX_ENT (AT_PAGESZ, (unsigned int)(ALPHA_PAGE_SIZE));
|
||||
NEW_AUX_ENT (AT_BASE, (unsigned int)(interp_load_addr));
|
||||
NEW_AUX_ENT (AT_FLAGS, (unsigned int)0);
|
||||
NEW_AUX_ENT (AT_ENTRY, (unsigned int) exec->e_entry);
|
||||
NEW_AUX_ENT (AT_UID, (unsigned int) getuid());
|
||||
NEW_AUX_ENT (AT_EUID, (unsigned int) geteuid());
|
||||
NEW_AUX_ENT (AT_GID, (unsigned int) getgid());
|
||||
NEW_AUX_ENT (AT_EGID, (unsigned int) getegid());
|
||||
NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
|
||||
NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
|
||||
NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum));
|
||||
NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
|
||||
NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr));
|
||||
NEW_AUX_ENT (AT_FLAGS, (target_ulong)0);
|
||||
NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry);
|
||||
NEW_AUX_ENT (AT_UID, (target_ulong) getuid());
|
||||
NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid());
|
||||
NEW_AUX_ENT (AT_GID, (target_ulong) getgid());
|
||||
NEW_AUX_ENT (AT_EGID, (target_ulong) getegid());
|
||||
}
|
||||
NEW_AUX_ENT (AT_NULL, 0);
|
||||
#undef NEW_AUX_ENT
|
||||
@@ -436,7 +545,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
|
||||
{
|
||||
struct elf_phdr *elf_phdata = NULL;
|
||||
struct elf_phdr *eppnt;
|
||||
unsigned long load_addr;
|
||||
unsigned long load_addr = 0;
|
||||
int load_addr_set = 0;
|
||||
int retval;
|
||||
unsigned long last_bss, elf_bss;
|
||||
@@ -447,17 +556,12 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
|
||||
last_bss = 0;
|
||||
error = 0;
|
||||
|
||||
/* We put this here so that mmap will search for the *first*
|
||||
* available memory...
|
||||
*/
|
||||
load_addr = INTERP_LOADADDR;
|
||||
|
||||
#ifdef BSWAP_NEEDED
|
||||
bswap_ehdr(interp_elf_ex);
|
||||
#endif
|
||||
/* First of all, some simple consistency checks */
|
||||
if ((interp_elf_ex->e_type != ET_EXEC &&
|
||||
interp_elf_ex->e_type != ET_DYN) ||
|
||||
interp_elf_ex->e_type != ET_DYN) ||
|
||||
!elf_check_arch(interp_elf_ex->e_machine)) {
|
||||
return ~0UL;
|
||||
}
|
||||
@@ -465,7 +569,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
|
||||
|
||||
/* Now read in all of the header information */
|
||||
|
||||
if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > X86_PAGE_SIZE)
|
||||
if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
|
||||
return ~0UL;
|
||||
|
||||
elf_phdata = (struct elf_phdr *)
|
||||
@@ -478,11 +582,10 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
|
||||
* If the size of this structure has changed, then punt, since
|
||||
* we will be doing the wrong thing.
|
||||
*/
|
||||
if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr))
|
||||
{
|
||||
if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
|
||||
free(elf_phdata);
|
||||
return ~0UL;
|
||||
}
|
||||
}
|
||||
|
||||
retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
|
||||
if(retval >= 0) {
|
||||
@@ -502,6 +605,21 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
|
||||
bswap_phdr(eppnt);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (interp_elf_ex->e_type == ET_DYN) {
|
||||
/* in order to avoid harcoding the interpreter load
|
||||
address in qemu, we allocate a big enough memory zone */
|
||||
error = target_mmap(0, INTERP_MAP_SIZE,
|
||||
PROT_NONE, MAP_PRIVATE | MAP_ANON,
|
||||
-1, 0);
|
||||
if (error == -1) {
|
||||
perror("mmap");
|
||||
exit(-1);
|
||||
}
|
||||
load_addr = error;
|
||||
load_addr_set = 1;
|
||||
}
|
||||
|
||||
eppnt = elf_phdata;
|
||||
for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
|
||||
if (eppnt->p_type == PT_LOAD) {
|
||||
@@ -517,12 +635,12 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
|
||||
elf_type |= MAP_FIXED;
|
||||
vaddr = eppnt->p_vaddr;
|
||||
}
|
||||
error = (unsigned long)mmap4k(load_addr+X86_ELF_PAGESTART(vaddr),
|
||||
eppnt->p_filesz + X86_ELF_PAGEOFFSET(eppnt->p_vaddr),
|
||||
error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
|
||||
eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
|
||||
elf_prot,
|
||||
elf_type,
|
||||
interpreter_fd,
|
||||
eppnt->p_offset - X86_ELF_PAGEOFFSET(eppnt->p_vaddr));
|
||||
eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
|
||||
|
||||
if (error > -1024UL) {
|
||||
/* Real error */
|
||||
@@ -562,13 +680,13 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
|
||||
* bss page.
|
||||
*/
|
||||
padzero(elf_bss);
|
||||
elf_bss = X86_ELF_PAGESTART(elf_bss + ALPHA_PAGE_SIZE - 1); /* What we have mapped so far */
|
||||
elf_bss = TARGET_ELF_PAGESTART(elf_bss + host_page_size - 1); /* What we have mapped so far */
|
||||
|
||||
/* Map the last of the bss segment */
|
||||
if (last_bss > elf_bss) {
|
||||
mmap4k(elf_bss, last_bss-elf_bss,
|
||||
PROT_READ|PROT_WRITE|PROT_EXEC,
|
||||
MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
target_mmap(elf_bss, last_bss-elf_bss,
|
||||
PROT_READ|PROT_WRITE|PROT_EXEC,
|
||||
MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
}
|
||||
free(elf_phdata);
|
||||
|
||||
@@ -576,7 +694,56 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
|
||||
return ((unsigned long) interp_elf_ex->e_entry) + load_addr;
|
||||
}
|
||||
|
||||
/* Best attempt to load symbols from this ELF object. */
|
||||
static void load_symbols(struct elfhdr *hdr, int fd)
|
||||
{
|
||||
unsigned int i;
|
||||
struct elf_shdr sechdr, symtab, strtab;
|
||||
char *strings;
|
||||
|
||||
lseek(fd, hdr->e_shoff, SEEK_SET);
|
||||
for (i = 0; i < hdr->e_shnum; i++) {
|
||||
if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
|
||||
return;
|
||||
#ifdef BSWAP_NEEDED
|
||||
bswap_shdr(&sechdr);
|
||||
#endif
|
||||
if (sechdr.sh_type == SHT_SYMTAB) {
|
||||
symtab = sechdr;
|
||||
lseek(fd, hdr->e_shoff
|
||||
+ sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
|
||||
if (read(fd, &strtab, sizeof(strtab))
|
||||
!= sizeof(strtab))
|
||||
return;
|
||||
#ifdef BSWAP_NEEDED
|
||||
bswap_shdr(&strtab);
|
||||
#endif
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
return; /* Shouldn't happen... */
|
||||
|
||||
found:
|
||||
/* Now know where the strtab and symtab are. Snarf them. */
|
||||
disas_symtab = malloc(symtab.sh_size);
|
||||
disas_strtab = strings = malloc(strtab.sh_size);
|
||||
if (!disas_symtab || !disas_strtab)
|
||||
return;
|
||||
|
||||
lseek(fd, symtab.sh_offset, SEEK_SET);
|
||||
if (read(fd, disas_symtab, symtab.sh_size) != symtab.sh_size)
|
||||
return;
|
||||
|
||||
#ifdef BSWAP_NEEDED
|
||||
for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++)
|
||||
bswap_sym(disas_symtab + sizeof(struct elf_sym)*i);
|
||||
#endif
|
||||
|
||||
lseek(fd, strtab.sh_offset, SEEK_SET);
|
||||
if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
|
||||
return;
|
||||
disas_num_syms = symtab.sh_size / sizeof(struct elf_sym);
|
||||
}
|
||||
|
||||
static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
|
||||
struct image_info * info)
|
||||
@@ -585,12 +752,12 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
struct elfhdr interp_elf_ex;
|
||||
struct exec interp_ex;
|
||||
int interpreter_fd = -1; /* avoid warning */
|
||||
unsigned long load_addr;
|
||||
unsigned long load_addr, load_bias;
|
||||
int load_addr_set = 0;
|
||||
unsigned int interpreter_type = INTERPRETER_NONE;
|
||||
unsigned char ibcs2_interpreter;
|
||||
int i;
|
||||
void * mapped_addr;
|
||||
unsigned long mapped_addr;
|
||||
struct elf_phdr * elf_ppnt;
|
||||
struct elf_phdr *elf_phdata;
|
||||
unsigned long elf_bss, k, elf_brk;
|
||||
@@ -605,6 +772,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
ibcs2_interpreter = 0;
|
||||
status = 0;
|
||||
load_addr = 0;
|
||||
load_bias = 0;
|
||||
elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
|
||||
#ifdef BSWAP_NEEDED
|
||||
bswap_ehdr(&elf_ex);
|
||||
@@ -622,7 +790,6 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
}
|
||||
|
||||
/* Now read in all of the header information */
|
||||
|
||||
elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
|
||||
if (elf_phdata == NULL) {
|
||||
return -ENOMEM;
|
||||
@@ -674,8 +841,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
* is an a.out format binary
|
||||
*/
|
||||
|
||||
elf_interpreter = (char *)malloc(elf_ppnt->p_filesz+
|
||||
strlen(bprm->interp_prefix));
|
||||
elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
|
||||
|
||||
if (elf_interpreter == NULL) {
|
||||
free (elf_phdata);
|
||||
@@ -683,12 +849,9 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
strcpy(elf_interpreter, bprm->interp_prefix);
|
||||
retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
|
||||
if(retval >= 0) {
|
||||
retval = read(bprm->fd,
|
||||
elf_interpreter+strlen(bprm->interp_prefix),
|
||||
elf_ppnt->p_filesz);
|
||||
retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
|
||||
}
|
||||
if(retval < 0) {
|
||||
perror("load_elf_binary2");
|
||||
@@ -710,7 +873,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
printf("Using ELF interpreter %s\n", elf_interpreter);
|
||||
#endif
|
||||
if (retval >= 0) {
|
||||
retval = open(elf_interpreter, O_RDONLY);
|
||||
retval = open(path(elf_interpreter), O_RDONLY);
|
||||
if(retval >= 0) {
|
||||
interpreter_fd = retval;
|
||||
}
|
||||
@@ -810,56 +973,85 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
* address.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
|
||||
if (elf_ppnt->p_type == PT_LOAD) {
|
||||
int elf_prot = 0;
|
||||
if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
|
||||
if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
|
||||
if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
|
||||
|
||||
mapped_addr = mmap4k(X86_ELF_PAGESTART(elf_ppnt->p_vaddr),
|
||||
(elf_ppnt->p_filesz +
|
||||
X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
|
||||
elf_prot,
|
||||
(MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
|
||||
bprm->fd,
|
||||
(elf_ppnt->p_offset -
|
||||
X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
|
||||
|
||||
if((unsigned long)mapped_addr == 0xffffffffffffffff) {
|
||||
perror("mmap");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
int elf_prot = 0;
|
||||
int elf_flags = 0;
|
||||
unsigned long error;
|
||||
|
||||
if (elf_ppnt->p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
|
||||
if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
|
||||
if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
|
||||
elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
|
||||
if (elf_ex.e_type == ET_EXEC || load_addr_set) {
|
||||
elf_flags |= MAP_FIXED;
|
||||
} else if (elf_ex.e_type == ET_DYN) {
|
||||
/* Try and get dynamic programs out of the way of the default mmap
|
||||
base, as well as whatever program they might try to exec. This
|
||||
is because the brk will follow the loader, and is not movable. */
|
||||
/* NOTE: for qemu, we do a big mmap to get enough space
|
||||
without harcoding any address */
|
||||
error = target_mmap(0, ET_DYN_MAP_SIZE,
|
||||
PROT_NONE, MAP_PRIVATE | MAP_ANON,
|
||||
-1, 0);
|
||||
if (error == -1) {
|
||||
perror("mmap");
|
||||
exit(-1);
|
||||
}
|
||||
load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
|
||||
}
|
||||
|
||||
error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
|
||||
(elf_ppnt->p_filesz +
|
||||
TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
|
||||
elf_prot,
|
||||
(MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
|
||||
bprm->fd,
|
||||
(elf_ppnt->p_offset -
|
||||
TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
|
||||
if (error == -1) {
|
||||
perror("mmap");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
#ifdef LOW_ELF_STACK
|
||||
if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
|
||||
elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr);
|
||||
if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
|
||||
elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr);
|
||||
#endif
|
||||
|
||||
if (!load_addr_set) {
|
||||
load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
|
||||
load_addr_set = 1;
|
||||
}
|
||||
k = elf_ppnt->p_vaddr;
|
||||
if (k < start_code) start_code = k;
|
||||
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
|
||||
if (k > elf_bss) elf_bss = k;
|
||||
#if 1
|
||||
if ((elf_ppnt->p_flags & PF_X) && end_code < k)
|
||||
#else
|
||||
if ( !(elf_ppnt->p_flags & PF_W) && end_code < k)
|
||||
#endif
|
||||
end_code = k;
|
||||
if (end_data < k) end_data = k;
|
||||
k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
|
||||
if (k > elf_brk) elf_brk = k;
|
||||
}
|
||||
|
||||
if (!load_addr_set) {
|
||||
load_addr_set = 1;
|
||||
load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
|
||||
if (elf_ex.e_type == ET_DYN) {
|
||||
load_bias += error -
|
||||
TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
|
||||
load_addr += load_bias;
|
||||
}
|
||||
}
|
||||
k = elf_ppnt->p_vaddr;
|
||||
if (k < start_code)
|
||||
start_code = k;
|
||||
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
|
||||
if (k > elf_bss)
|
||||
elf_bss = k;
|
||||
if ((elf_ppnt->p_flags & PF_X) && end_code < k)
|
||||
end_code = k;
|
||||
if (end_data < k)
|
||||
end_data = k;
|
||||
k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
|
||||
if (k > elf_brk) elf_brk = k;
|
||||
}
|
||||
|
||||
elf_entry += load_bias;
|
||||
elf_bss += load_bias;
|
||||
elf_brk += load_bias;
|
||||
start_code += load_bias;
|
||||
end_code += load_bias;
|
||||
// start_data += load_bias;
|
||||
end_data += load_bias;
|
||||
|
||||
if (elf_interpreter) {
|
||||
if (interpreter_type & 1) {
|
||||
elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
|
||||
@@ -882,6 +1074,9 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
|
||||
free(elf_phdata);
|
||||
|
||||
if (loglevel)
|
||||
load_symbols(&elf_ex, bprm->fd);
|
||||
|
||||
if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
|
||||
info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
|
||||
|
||||
@@ -893,7 +1088,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
bprm->argc,
|
||||
bprm->envc,
|
||||
(interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
|
||||
load_addr,
|
||||
load_addr, load_bias,
|
||||
interp_load_addr,
|
||||
(interpreter_type == INTERPRETER_AOUT ? 0 : 1),
|
||||
info);
|
||||
@@ -926,8 +1121,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
and some applications "depend" upon this behavior.
|
||||
Since we do not have the power to recompile these, we
|
||||
emulate the SVr4 behavior. Sigh. */
|
||||
mapped_addr = mmap4k(NULL, ALPHA_PAGE_SIZE, PROT_READ | PROT_EXEC,
|
||||
MAP_FIXED | MAP_PRIVATE, -1, 0);
|
||||
mapped_addr = target_mmap(0, host_page_size, PROT_READ | PROT_EXEC,
|
||||
MAP_FIXED | MAP_PRIVATE, -1, 0);
|
||||
}
|
||||
|
||||
#ifdef ELF_PLAT_INIT
|
||||
@@ -948,15 +1143,14 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
|
||||
|
||||
|
||||
int elf_exec(const char *interp_prefix,
|
||||
const char * filename, char ** argv, char ** envp,
|
||||
int elf_exec(const char * filename, char ** argv, char ** envp,
|
||||
struct target_pt_regs * regs, struct image_info *infop)
|
||||
{
|
||||
struct linux_binprm bprm;
|
||||
int retval;
|
||||
int i;
|
||||
|
||||
bprm.p = X86_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
|
||||
bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
|
||||
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
|
||||
bprm.page[i] = 0;
|
||||
retval = open(filename, O_RDONLY);
|
||||
@@ -968,7 +1162,6 @@ int elf_exec(const char *interp_prefix,
|
||||
else {
|
||||
bprm.fd = retval;
|
||||
}
|
||||
bprm.interp_prefix = (char *)interp_prefix;
|
||||
bprm.filename = (char *)filename;
|
||||
bprm.sh_bang = 0;
|
||||
bprm.loader = 0;
|
||||
@@ -994,8 +1187,7 @@ int elf_exec(const char *interp_prefix,
|
||||
}
|
||||
if(retval>=0) {
|
||||
/* success. Initialize important registers */
|
||||
regs->esp = infop->start_stack;
|
||||
regs->eip = infop->entry;
|
||||
init_thread(regs, infop);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
+16
-4
@@ -37,6 +37,8 @@
|
||||
IOCTL(TIOCNOTTY, 0, TYPE_NULL)
|
||||
IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(TIOCGPTN, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(TIOCSPTLCK, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(FIOCLEX, 0, TYPE_NULL)
|
||||
IOCTL(FIONCLEX, 0, TYPE_NULL)
|
||||
IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT))
|
||||
@@ -49,6 +51,12 @@
|
||||
IOCTL(TIOCMIWAIT, 0, TYPE_INT)
|
||||
IOCTL(TIOCGICOUNT, IOC_R, MK_PTR(MK_STRUCT(STRUCT_serial_icounter_struct)))
|
||||
|
||||
IOCTL(KIOCSOUND, 0, TYPE_INT)
|
||||
IOCTL(KDMKTONE, 0, TYPE_INT)
|
||||
IOCTL(KDGKBTYPE, IOC_R, MK_PTR(TYPE_CHAR))
|
||||
IOCTL(KDGKBENT, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_kbentry)))
|
||||
IOCTL(KDGKBSENT, IOC_RW, TYPE_PTRVOID)
|
||||
|
||||
IOCTL(BLKROSET, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(BLKROGET, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(BLKRRPART, 0, TYPE_NULL)
|
||||
@@ -142,6 +150,7 @@
|
||||
IOCTL(CDROM_DISC_STATUS, 0, TYPE_NULL)
|
||||
IOCTL(CDROMAUDIOBUFSIZ, 0, TYPE_INT)
|
||||
|
||||
#if 0
|
||||
IOCTL(SNDCTL_COPR_HALT, IOC_RW, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_COPR_LOAD, IOC_RW, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_COPR_RCODE, IOC_RW, MK_PTR(TYPE_INT))
|
||||
@@ -152,14 +161,15 @@
|
||||
IOCTL(SNDCTL_COPR_SENDMSG, IOC_RW, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_COPR_WCODE, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_COPR_WDATA, IOC_W, MK_PTR(TYPE_INT))
|
||||
#endif
|
||||
IOCTL(SNDCTL_DSP_CHANNELS, IOC_RW, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_GETBLKSIZE, IOC_RW, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_GETCAPS, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_GETFMTS, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_GETIPTR, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_GETISPACE, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_GETOPTR, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_GETOSPACE, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_GETIPTR, IOC_R, MK_PTR(MK_STRUCT(STRUCT_count_info)))
|
||||
IOCTL(SNDCTL_DSP_GETOPTR, IOC_R, MK_PTR(MK_STRUCT(STRUCT_count_info)))
|
||||
IOCTL(SNDCTL_DSP_GETISPACE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_audio_buf_info)))
|
||||
IOCTL(SNDCTL_DSP_GETOSPACE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_audio_buf_info)))
|
||||
IOCTL(SNDCTL_DSP_GETTRIGGER, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_MAPINBUF, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_MAPOUTBUF, IOC_R, MK_PTR(TYPE_INT))
|
||||
@@ -175,6 +185,7 @@
|
||||
IOCTL(SNDCTL_DSP_STEREO, IOC_RW, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_SUBDIVIDE, IOC_RW, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_SYNC, 0, TYPE_NULL)
|
||||
#if 0
|
||||
IOCTL(SNDCTL_FM_4OP_ENABLE, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_FM_LOAD_INSTR, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_MIDI_INFO, IOC_RW, MK_PTR(TYPE_INT))
|
||||
@@ -214,6 +225,7 @@
|
||||
IOCTL(SOUND_PCM_READ_CHANNELS, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SOUND_PCM_READ_BITS, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SOUND_PCM_READ_FILTER, IOC_R, MK_PTR(TYPE_INT))
|
||||
#endif
|
||||
IOCTL(SOUND_MIXER_INFO, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SOUND_MIXER_ACCESS, 0, TYPE_PTRVOID)
|
||||
IOCTL(SOUND_MIXER_PRIVATE1, IOC_RW, MK_PTR(TYPE_INT))
|
||||
|
||||
+234
-224
@@ -23,19 +23,14 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
|
||||
#include <sys/personality.h>
|
||||
#endif
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
#include "cpu-i386.h"
|
||||
|
||||
#define DEBUG_LOGFILE "/tmp/qemu.log"
|
||||
|
||||
FILE *logfile = NULL;
|
||||
int loglevel;
|
||||
const char *interp_prefix = CONFIG_QEMU_PREFIX "/qemu-i386";
|
||||
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
|
||||
|
||||
#ifdef __i386__
|
||||
/* Force usage of an ELF interpreter even if it is an ELF shared
|
||||
@@ -43,11 +38,19 @@ const char *interp_prefix = CONFIG_QEMU_PREFIX "/qemu-i386";
|
||||
const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
|
||||
#endif
|
||||
|
||||
/* for recent libc, we add these dummies symbol which are not declared
|
||||
when generating a linked object (bug in ld ?) */
|
||||
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
|
||||
long __init_array_start[0];
|
||||
long __init_array_end[0];
|
||||
long __fini_array_start[0];
|
||||
long __fini_array_end[0];
|
||||
#endif
|
||||
|
||||
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
|
||||
we allocate a bigger stack. Need a better solution, for example
|
||||
by remapping the process stack directly at the right place */
|
||||
unsigned long x86_stack_size = 512 * 1024;
|
||||
unsigned long stktop;
|
||||
|
||||
void gemu_log(const char *fmt, ...)
|
||||
{
|
||||
@@ -58,184 +61,79 @@ void gemu_log(const char *fmt, ...)
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#ifdef TARGET_I386
|
||||
/***********************************************************/
|
||||
/* CPUX86 core interface */
|
||||
|
||||
void cpu_x86_outb(int addr, int val)
|
||||
void cpu_x86_outb(CPUX86State *env, int addr, int val)
|
||||
{
|
||||
fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
|
||||
}
|
||||
|
||||
void cpu_x86_outw(int addr, int val)
|
||||
void cpu_x86_outw(CPUX86State *env, int addr, int val)
|
||||
{
|
||||
fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
|
||||
}
|
||||
|
||||
void cpu_x86_outl(int addr, int val)
|
||||
void cpu_x86_outl(CPUX86State *env, int addr, int val)
|
||||
{
|
||||
fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
|
||||
}
|
||||
|
||||
int cpu_x86_inb(int addr)
|
||||
int cpu_x86_inb(CPUX86State *env, int addr)
|
||||
{
|
||||
fprintf(stderr, "inb: port=0x%04x\n", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_x86_inw(int addr)
|
||||
int cpu_x86_inw(CPUX86State *env, int addr)
|
||||
{
|
||||
fprintf(stderr, "inw: port=0x%04x\n", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_x86_inl(int addr)
|
||||
int cpu_x86_inl(CPUX86State *env, int addr)
|
||||
{
|
||||
fprintf(stderr, "inl: port=0x%04x\n", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void write_dt(void *ptr, unsigned long addr, unsigned long limit,
|
||||
int seg32_bit)
|
||||
int cpu_x86_get_pic_interrupt(CPUX86State *env)
|
||||
{
|
||||
unsigned int e1, e2, limit_in_pages;
|
||||
limit_in_pages = 0;
|
||||
if (limit > 0xffff) {
|
||||
limit = limit >> 12;
|
||||
limit_in_pages = 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
|
||||
int flags)
|
||||
{
|
||||
unsigned int e1, e2;
|
||||
e1 = (addr << 16) | (limit & 0xffff);
|
||||
e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
|
||||
e2 |= limit_in_pages << 23; /* byte granularity */
|
||||
e2 |= seg32_bit << 22; /* 32 bit segment */
|
||||
e2 |= flags;
|
||||
stl((uint8_t *)ptr, e1);
|
||||
stl((uint8_t *)ptr + 4, e2);
|
||||
}
|
||||
|
||||
static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
|
||||
unsigned long addr, unsigned int sel)
|
||||
{
|
||||
unsigned int e1, e2;
|
||||
e1 = (addr & 0xffff) | (sel << 16);
|
||||
e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
|
||||
stl((uint8_t *)ptr, e1);
|
||||
stl((uint8_t *)ptr + 4, e2);
|
||||
}
|
||||
|
||||
uint64_t gdt_table[6];
|
||||
uint64_t idt_table[256];
|
||||
|
||||
//#define DEBUG_VM86
|
||||
|
||||
static inline int is_revectored(int nr, struct target_revectored_struct *bitmap)
|
||||
/* only dpl matters as we do only user space emulation */
|
||||
static void set_idt(int n, unsigned int dpl)
|
||||
{
|
||||
return (tswap32(bitmap->__map[nr >> 5]) >> (nr & 0x1f)) & 1;
|
||||
set_gate(idt_table + n, 0, dpl, 0, 0);
|
||||
}
|
||||
|
||||
static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg)
|
||||
{
|
||||
return (uint8_t *)((seg << 4) + (reg & 0xffff));
|
||||
}
|
||||
|
||||
static inline void pushw(CPUX86State *env, int val)
|
||||
{
|
||||
env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) |
|
||||
((env->regs[R_ESP] - 2) & 0xffff);
|
||||
*(uint16_t *)seg_to_linear(env->segs[R_SS], env->regs[R_ESP]) = val;
|
||||
}
|
||||
|
||||
static inline unsigned int get_vflags(CPUX86State *env)
|
||||
{
|
||||
unsigned int eflags;
|
||||
eflags = env->eflags & ~(VM_MASK | RF_MASK | IF_MASK);
|
||||
if (eflags & VIF_MASK)
|
||||
eflags |= IF_MASK;
|
||||
return eflags;
|
||||
}
|
||||
|
||||
void save_v86_state(CPUX86State *env)
|
||||
{
|
||||
TaskState *ts = env->opaque;
|
||||
#ifdef DEBUG_VM86
|
||||
printf("save_v86_state\n");
|
||||
#endif
|
||||
|
||||
/* put the VM86 registers in the userspace register structure */
|
||||
ts->target_v86->regs.eax = tswap32(env->regs[R_EAX]);
|
||||
ts->target_v86->regs.ebx = tswap32(env->regs[R_EBX]);
|
||||
ts->target_v86->regs.ecx = tswap32(env->regs[R_ECX]);
|
||||
ts->target_v86->regs.edx = tswap32(env->regs[R_EDX]);
|
||||
ts->target_v86->regs.esi = tswap32(env->regs[R_ESI]);
|
||||
ts->target_v86->regs.edi = tswap32(env->regs[R_EDI]);
|
||||
ts->target_v86->regs.ebp = tswap32(env->regs[R_EBP]);
|
||||
ts->target_v86->regs.esp = tswap32(env->regs[R_ESP]);
|
||||
ts->target_v86->regs.eip = tswap32(env->eip);
|
||||
ts->target_v86->regs.cs = tswap16(env->segs[R_CS]);
|
||||
ts->target_v86->regs.ss = tswap16(env->segs[R_SS]);
|
||||
ts->target_v86->regs.ds = tswap16(env->segs[R_DS]);
|
||||
ts->target_v86->regs.es = tswap16(env->segs[R_ES]);
|
||||
ts->target_v86->regs.fs = tswap16(env->segs[R_FS]);
|
||||
ts->target_v86->regs.gs = tswap16(env->segs[R_GS]);
|
||||
ts->target_v86->regs.eflags = tswap32(env->eflags);
|
||||
|
||||
/* restore 32 bit registers */
|
||||
env->regs[R_EAX] = ts->vm86_saved_regs.eax;
|
||||
env->regs[R_EBX] = ts->vm86_saved_regs.ebx;
|
||||
env->regs[R_ECX] = ts->vm86_saved_regs.ecx;
|
||||
env->regs[R_EDX] = ts->vm86_saved_regs.edx;
|
||||
env->regs[R_ESI] = ts->vm86_saved_regs.esi;
|
||||
env->regs[R_EDI] = ts->vm86_saved_regs.edi;
|
||||
env->regs[R_EBP] = ts->vm86_saved_regs.ebp;
|
||||
env->regs[R_ESP] = ts->vm86_saved_regs.esp;
|
||||
env->eflags = ts->vm86_saved_regs.eflags;
|
||||
env->eip = ts->vm86_saved_regs.eip;
|
||||
|
||||
cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs);
|
||||
cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss);
|
||||
cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds);
|
||||
cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es);
|
||||
cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs);
|
||||
cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs);
|
||||
}
|
||||
|
||||
/* return from vm86 mode to 32 bit. The vm86() syscall will return
|
||||
'retval' */
|
||||
static inline void return_to_32bit(CPUX86State *env, int retval)
|
||||
{
|
||||
#ifdef DEBUG_VM86
|
||||
printf("return_to_32bit: ret=0x%x\n", retval);
|
||||
#endif
|
||||
save_v86_state(env);
|
||||
env->regs[R_EAX] = retval;
|
||||
}
|
||||
|
||||
/* handle VM86 interrupt (NOTE: the CPU core currently does not
|
||||
support TSS interrupt revectoring, so this code is always executed) */
|
||||
static void do_int(CPUX86State *env, int intno)
|
||||
{
|
||||
TaskState *ts = env->opaque;
|
||||
uint32_t *int_ptr, segoffs;
|
||||
|
||||
if (env->segs[R_CS] == TARGET_BIOSSEG)
|
||||
goto cannot_handle; /* XXX: I am not sure this is really useful */
|
||||
if (is_revectored(intno, &ts->target_v86->int_revectored))
|
||||
goto cannot_handle;
|
||||
if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff,
|
||||
&ts->target_v86->int21_revectored))
|
||||
goto cannot_handle;
|
||||
int_ptr = (uint32_t *)(intno << 2);
|
||||
segoffs = tswap32(*int_ptr);
|
||||
if ((segoffs >> 16) == TARGET_BIOSSEG)
|
||||
goto cannot_handle;
|
||||
#ifdef DEBUG_VM86
|
||||
printf("VM86: emulating int 0x%x. CS:IP=%04x:%04x\n",
|
||||
intno, segoffs >> 16, segoffs & 0xffff);
|
||||
#endif
|
||||
/* save old state */
|
||||
pushw(env, get_vflags(env));
|
||||
pushw(env, env->segs[R_CS]);
|
||||
pushw(env, env->eip);
|
||||
/* goto interrupt handler */
|
||||
env->eip = segoffs & 0xffff;
|
||||
cpu_x86_load_seg(env, R_CS, segoffs >> 16);
|
||||
env->eflags &= ~(VIF_MASK | TF_MASK);
|
||||
return;
|
||||
cannot_handle:
|
||||
#ifdef DEBUG_VM86
|
||||
printf("VM86: return to 32 bits int 0x%x\n", intno);
|
||||
#endif
|
||||
return_to_32bit(env, TARGET_VM86_INTx | (intno << 8));
|
||||
}
|
||||
|
||||
void cpu_loop(struct CPUX86State *env)
|
||||
void cpu_loop(CPUX86State *env)
|
||||
{
|
||||
int trapnr;
|
||||
uint8_t *pc;
|
||||
@@ -243,69 +141,50 @@ void cpu_loop(struct CPUX86State *env)
|
||||
|
||||
for(;;) {
|
||||
trapnr = cpu_x86_exec(env);
|
||||
pc = env->seg_cache[R_CS].base + env->eip;
|
||||
switch(trapnr) {
|
||||
case 0x80:
|
||||
/* linux syscall */
|
||||
env->regs[R_EAX] = do_syscall(env,
|
||||
env->regs[R_EAX],
|
||||
env->regs[R_EBX],
|
||||
env->regs[R_ECX],
|
||||
env->regs[R_EDX],
|
||||
env->regs[R_ESI],
|
||||
env->regs[R_EDI],
|
||||
env->regs[R_EBP]);
|
||||
break;
|
||||
case EXCP0B_NOSEG:
|
||||
case EXCP0C_STACK:
|
||||
info.si_signo = SIGBUS;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_SI_KERNEL;
|
||||
info._sifields._sigfault._addr = 0;
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP0D_GPF:
|
||||
if (env->eflags & VM_MASK) {
|
||||
#ifdef DEBUG_VM86
|
||||
printf("VM86 exception %04x:%08x %02x %02x\n",
|
||||
env->segs[R_CS], env->eip, pc[0], pc[1]);
|
||||
#endif
|
||||
/* VM86 mode */
|
||||
switch(pc[0]) {
|
||||
case 0xcd: /* int */
|
||||
env->eip += 2;
|
||||
do_int(env, pc[1]);
|
||||
break;
|
||||
case 0x66:
|
||||
switch(pc[1]) {
|
||||
case 0xfb: /* sti */
|
||||
case 0x9d: /* popf */
|
||||
case 0xcf: /* iret */
|
||||
env->eip += 2;
|
||||
return_to_32bit(env, TARGET_VM86_STI);
|
||||
break;
|
||||
default:
|
||||
goto vm86_gpf;
|
||||
}
|
||||
break;
|
||||
case 0xfb: /* sti */
|
||||
case 0x9d: /* popf */
|
||||
case 0xcf: /* iret */
|
||||
env->eip++;
|
||||
return_to_32bit(env, TARGET_VM86_STI);
|
||||
break;
|
||||
default:
|
||||
vm86_gpf:
|
||||
/* real VM86 GPF exception */
|
||||
return_to_32bit(env, TARGET_VM86_UNKNOWN);
|
||||
break;
|
||||
}
|
||||
handle_vm86_fault(env);
|
||||
} else {
|
||||
if (pc[0] == 0xcd && pc[1] == 0x80) {
|
||||
/* syscall */
|
||||
env->eip += 2;
|
||||
env->regs[R_EAX] = do_syscall(env,
|
||||
env->regs[R_EAX],
|
||||
env->regs[R_EBX],
|
||||
env->regs[R_ECX],
|
||||
env->regs[R_EDX],
|
||||
env->regs[R_ESI],
|
||||
env->regs[R_EDI],
|
||||
env->regs[R_EBP]);
|
||||
} else {
|
||||
/* XXX: more precise info */
|
||||
info.si_signo = SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = 0;
|
||||
info._sifields._sigfault._addr = 0;
|
||||
queue_signal(info.si_signo, &info);
|
||||
}
|
||||
info.si_signo = SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_SI_KERNEL;
|
||||
info._sifields._sigfault._addr = 0;
|
||||
queue_signal(info.si_signo, &info);
|
||||
}
|
||||
break;
|
||||
case EXCP0E_PAGE:
|
||||
info.si_signo = SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
if (!(env->error_code & 1))
|
||||
info.si_code = TARGET_SEGV_MAPERR;
|
||||
else
|
||||
info.si_code = TARGET_SEGV_ACCERR;
|
||||
info._sifields._sigfault._addr = env->cr[2];
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP00_DIVZ:
|
||||
if (env->eflags & VM_MASK) {
|
||||
do_int(env, trapnr);
|
||||
handle_vm86_trap(env, trapnr);
|
||||
} else {
|
||||
/* division by zero */
|
||||
info.si_signo = SIGFPE;
|
||||
@@ -315,14 +194,31 @@ void cpu_loop(struct CPUX86State *env)
|
||||
queue_signal(info.si_signo, &info);
|
||||
}
|
||||
break;
|
||||
case EXCP01_SSTP:
|
||||
case EXCP03_INT3:
|
||||
if (env->eflags & VM_MASK) {
|
||||
handle_vm86_trap(env, trapnr);
|
||||
} else {
|
||||
info.si_signo = SIGTRAP;
|
||||
info.si_errno = 0;
|
||||
if (trapnr == EXCP01_SSTP) {
|
||||
info.si_code = TARGET_TRAP_BRKPT;
|
||||
info._sifields._sigfault._addr = env->eip;
|
||||
} else {
|
||||
info.si_code = TARGET_SI_KERNEL;
|
||||
info._sifields._sigfault._addr = 0;
|
||||
}
|
||||
queue_signal(info.si_signo, &info);
|
||||
}
|
||||
break;
|
||||
case EXCP04_INTO:
|
||||
case EXCP05_BOUND:
|
||||
if (env->eflags & VM_MASK) {
|
||||
do_int(env, trapnr);
|
||||
handle_vm86_trap(env, trapnr);
|
||||
} else {
|
||||
info.si_signo = SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = 0;
|
||||
info.si_code = TARGET_SI_KERNEL;
|
||||
info._sifields._sigfault._addr = 0;
|
||||
queue_signal(info.si_signo, &info);
|
||||
}
|
||||
@@ -338,6 +234,7 @@ void cpu_loop(struct CPUX86State *env)
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
default:
|
||||
pc = env->segs[R_CS].base + env->eip;
|
||||
fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
|
||||
(long)pc, trapnr);
|
||||
abort();
|
||||
@@ -345,25 +242,87 @@ void cpu_loop(struct CPUX86State *env)
|
||||
process_pending_signals(env);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_ARM
|
||||
|
||||
#define ARM_SYSCALL_BASE 0x900000
|
||||
|
||||
void cpu_loop(CPUARMState *env)
|
||||
{
|
||||
int trapnr;
|
||||
unsigned int n, insn;
|
||||
target_siginfo_t info;
|
||||
|
||||
for(;;) {
|
||||
trapnr = cpu_arm_exec(env);
|
||||
switch(trapnr) {
|
||||
case EXCP_UDEF:
|
||||
info.si_signo = SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLOPN;
|
||||
info._sifields._sigfault._addr = env->regs[15];
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP_SWI:
|
||||
{
|
||||
/* system call */
|
||||
insn = ldl((void *)(env->regs[15] - 4));
|
||||
n = insn & 0xffffff;
|
||||
if (n >= ARM_SYSCALL_BASE) {
|
||||
/* linux syscall */
|
||||
n -= ARM_SYSCALL_BASE;
|
||||
env->regs[0] = do_syscall(env,
|
||||
n,
|
||||
env->regs[0],
|
||||
env->regs[1],
|
||||
env->regs[2],
|
||||
env->regs[3],
|
||||
env->regs[4],
|
||||
0);
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error:
|
||||
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
|
||||
trapnr);
|
||||
cpu_arm_dump_state(env, stderr, 0);
|
||||
abort();
|
||||
}
|
||||
process_pending_signals(env);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf("qemu version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
|
||||
"usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]\n"
|
||||
"Linux x86 emulator\n"
|
||||
"Linux CPU emulator (compiled for %s emulation)\n"
|
||||
"\n"
|
||||
"-h print this help\n"
|
||||
"-d activate log (logfile=%s)\n"
|
||||
"-L path set the x86 elf interpreter prefix (default=%s)\n"
|
||||
"-s size set the x86 stack size in bytes (default=%ld)\n",
|
||||
DEBUG_LOGFILE,
|
||||
"-h print this help\n"
|
||||
"-L path set the elf interpreter prefix (default=%s)\n"
|
||||
"-s size set the stack size in bytes (default=%ld)\n"
|
||||
"\n"
|
||||
"debug options:\n"
|
||||
"-d activate log (logfile=%s)\n"
|
||||
"-p pagesize set the host page size to 'pagesize'\n",
|
||||
TARGET_ARCH,
|
||||
interp_prefix,
|
||||
x86_stack_size);
|
||||
exit(1);
|
||||
x86_stack_size,
|
||||
DEBUG_LOGFILE);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
/* XXX: currently only used for async signals (see signal.c) */
|
||||
CPUX86State *global_env;
|
||||
CPUState *global_env;
|
||||
/* used only if single thread */
|
||||
CPUState *cpu_single_env = NULL;
|
||||
|
||||
/* used to free thread contexts */
|
||||
TaskState *first_task_state;
|
||||
|
||||
@@ -373,19 +332,13 @@ int main(int argc, char **argv)
|
||||
struct target_pt_regs regs1, *regs = ®s1;
|
||||
struct image_info info1, *info = &info1;
|
||||
TaskState ts1, *ts = &ts1;
|
||||
CPUX86State *env;
|
||||
CPUState *env;
|
||||
int optind;
|
||||
const char *r;
|
||||
|
||||
if (argc <= 1)
|
||||
usage();
|
||||
|
||||
/* Set personality to X86_LINUX. May fail on unpatched kernels:
|
||||
if so, they need to have munged paths themselves (eg. chroot,
|
||||
hacked ld.so, whatever). */
|
||||
if (personality(0x11) >= 0)
|
||||
interp_prefix = "";
|
||||
|
||||
loglevel = 0;
|
||||
optind = 1;
|
||||
for(;;) {
|
||||
@@ -411,6 +364,13 @@ int main(int argc, char **argv)
|
||||
x86_stack_size *= 1024;
|
||||
} else if (!strcmp(r, "L")) {
|
||||
interp_prefix = argv[optind++];
|
||||
} else if (!strcmp(r, "p")) {
|
||||
host_page_size = atoi(argv[optind++]);
|
||||
if (host_page_size == 0 ||
|
||||
(host_page_size & (host_page_size - 1)) != 0) {
|
||||
fprintf(stderr, "page size must be a power of two\n");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
@@ -424,7 +384,7 @@ int main(int argc, char **argv)
|
||||
logfile = fopen(DEBUG_LOGFILE, "w");
|
||||
if (!logfile) {
|
||||
perror(DEBUG_LOGFILE);
|
||||
exit(1);
|
||||
_exit(1);
|
||||
}
|
||||
setvbuf(logfile, NULL, _IOLBF, 0);
|
||||
}
|
||||
@@ -435,34 +395,43 @@ int main(int argc, char **argv)
|
||||
/* Zero out image_info */
|
||||
memset(info, 0, sizeof(struct image_info));
|
||||
|
||||
if(elf_exec(interp_prefix, filename, argv+optind, environ, regs, info) != 0) {
|
||||
/* Scan interp_prefix dir for replacement files. */
|
||||
init_paths(interp_prefix);
|
||||
|
||||
/* NOTE: we need to init the CPU at this stage to get the
|
||||
host_page_size */
|
||||
env = cpu_init();
|
||||
|
||||
if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
|
||||
printf("Error loading %s\n", filename);
|
||||
exit(1);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
if (loglevel) {
|
||||
page_dump(logfile);
|
||||
|
||||
fprintf(logfile, "start_brk 0x%08lx\n" , info->start_brk);
|
||||
fprintf(logfile, "end_code 0x%08lx\n" , info->end_code);
|
||||
fprintf(logfile, "start_code 0x%08lx\n" , info->start_code);
|
||||
fprintf(logfile, "end_data 0x%08lx\n" , info->end_data);
|
||||
fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack);
|
||||
fprintf(logfile, "brk 0x%08lx\n" , info->brk);
|
||||
fprintf(logfile, "esp 0x%08lx\n" , regs->esp);
|
||||
fprintf(logfile, "eip 0x%08lx\n" , regs->eip);
|
||||
fprintf(logfile, "entry 0x%08lx\n" , info->entry);
|
||||
}
|
||||
|
||||
target_set_brk((char *)info->brk);
|
||||
syscall_init();
|
||||
signal_init();
|
||||
|
||||
env = cpu_x86_init();
|
||||
global_env = env;
|
||||
|
||||
/* build Task State */
|
||||
memset(ts, 0, sizeof(TaskState));
|
||||
env->opaque = ts;
|
||||
ts->used = 1;
|
||||
env->user_mode_only = 1;
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
/* linux register setup */
|
||||
env->regs[R_EAX] = regs->eax;
|
||||
env->regs[R_EBX] = regs->ebx;
|
||||
@@ -474,11 +443,40 @@ int main(int argc, char **argv)
|
||||
env->regs[R_ESP] = regs->esp;
|
||||
env->eip = regs->eip;
|
||||
|
||||
/* linux interrupt setup */
|
||||
env->idt.base = (void *)idt_table;
|
||||
env->idt.limit = sizeof(idt_table) - 1;
|
||||
set_idt(0, 0);
|
||||
set_idt(1, 0);
|
||||
set_idt(2, 0);
|
||||
set_idt(3, 3);
|
||||
set_idt(4, 3);
|
||||
set_idt(5, 3);
|
||||
set_idt(6, 0);
|
||||
set_idt(7, 0);
|
||||
set_idt(8, 0);
|
||||
set_idt(9, 0);
|
||||
set_idt(10, 0);
|
||||
set_idt(11, 0);
|
||||
set_idt(12, 0);
|
||||
set_idt(13, 0);
|
||||
set_idt(14, 0);
|
||||
set_idt(15, 0);
|
||||
set_idt(16, 0);
|
||||
set_idt(17, 0);
|
||||
set_idt(18, 0);
|
||||
set_idt(19, 0);
|
||||
set_idt(0x80, 3);
|
||||
|
||||
/* linux segment setup */
|
||||
env->gdt.base = (void *)gdt_table;
|
||||
env->gdt.limit = sizeof(gdt_table) - 1;
|
||||
write_dt(&gdt_table[__USER_CS >> 3], 0, 0xffffffff, 1);
|
||||
write_dt(&gdt_table[__USER_DS >> 3], 0, 0xffffffff, 1);
|
||||
write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
|
||||
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
|
||||
(3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
|
||||
write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
|
||||
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
|
||||
(3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
|
||||
cpu_x86_load_seg(env, R_CS, __USER_CS);
|
||||
cpu_x86_load_seg(env, R_DS, __USER_DS);
|
||||
cpu_x86_load_seg(env, R_ES, __USER_DS);
|
||||
@@ -486,6 +484,18 @@ int main(int argc, char **argv)
|
||||
cpu_x86_load_seg(env, R_FS, __USER_DS);
|
||||
cpu_x86_load_seg(env, R_GS, __USER_DS);
|
||||
|
||||
#elif defined(TARGET_ARM)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < 16; i++) {
|
||||
env->regs[i] = regs->uregs[i];
|
||||
}
|
||||
env->cpsr = regs->uregs[16];
|
||||
}
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
|
||||
cpu_loop(env);
|
||||
/* never exits */
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
* mmap support for qemu
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
//#define DEBUG_MMAP
|
||||
|
||||
/* NOTE: all the constants are the HOST ones */
|
||||
int target_mprotect(unsigned long start, unsigned long len, int prot)
|
||||
{
|
||||
unsigned long end, host_start, host_end, addr;
|
||||
int prot1, ret;
|
||||
|
||||
#ifdef DEBUG_MMAP
|
||||
printf("mprotect: start=0x%lx len=0x%lx prot=%c%c%c\n", start, len,
|
||||
prot & PROT_READ ? 'r' : '-',
|
||||
prot & PROT_WRITE ? 'w' : '-',
|
||||
prot & PROT_EXEC ? 'x' : '-');
|
||||
#endif
|
||||
|
||||
if ((start & ~TARGET_PAGE_MASK) != 0)
|
||||
return -EINVAL;
|
||||
len = TARGET_PAGE_ALIGN(len);
|
||||
end = start + len;
|
||||
if (end < start)
|
||||
return -EINVAL;
|
||||
if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
|
||||
return -EINVAL;
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
host_start = start & host_page_mask;
|
||||
host_end = HOST_PAGE_ALIGN(end);
|
||||
if (start > host_start) {
|
||||
/* handle host page containing start */
|
||||
prot1 = prot;
|
||||
for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
|
||||
prot1 |= page_get_flags(addr);
|
||||
}
|
||||
if (host_end == host_start + host_page_size) {
|
||||
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
|
||||
prot1 |= page_get_flags(addr);
|
||||
}
|
||||
end = host_end;
|
||||
}
|
||||
ret = mprotect((void *)host_start, host_page_size, prot1 & PAGE_BITS);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
host_start += host_page_size;
|
||||
}
|
||||
if (end < host_end) {
|
||||
prot1 = prot;
|
||||
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
|
||||
prot1 |= page_get_flags(addr);
|
||||
}
|
||||
ret = mprotect((void *)(host_end - host_page_size), host_page_size,
|
||||
prot1 & PAGE_BITS);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
host_end -= host_page_size;
|
||||
}
|
||||
|
||||
/* handle the pages in the middle */
|
||||
if (host_start < host_end) {
|
||||
ret = mprotect((void *)host_start, host_end - host_start, prot);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
page_set_flags(start, start + len, prot | PAGE_VALID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* map an incomplete host page */
|
||||
int mmap_frag(unsigned long host_start,
|
||||
unsigned long start, unsigned long end,
|
||||
int prot, int flags, int fd, unsigned long offset)
|
||||
{
|
||||
unsigned long host_end, ret, addr;
|
||||
int prot1, prot_new;
|
||||
|
||||
host_end = host_start + host_page_size;
|
||||
|
||||
/* get the protection of the target pages outside the mapping */
|
||||
prot1 = 0;
|
||||
for(addr = host_start; addr < host_end; addr++) {
|
||||
if (addr < start || addr >= end)
|
||||
prot1 |= page_get_flags(addr);
|
||||
}
|
||||
|
||||
if (prot1 == 0) {
|
||||
/* no page was there, so we allocate one */
|
||||
ret = (long)mmap((void *)host_start, host_page_size, prot,
|
||||
flags | MAP_ANONYMOUS, -1, 0);
|
||||
if (ret == -1)
|
||||
return ret;
|
||||
}
|
||||
prot1 &= PAGE_BITS;
|
||||
|
||||
prot_new = prot | prot1;
|
||||
if (!(flags & MAP_ANONYMOUS)) {
|
||||
/* msync() won't work here, so we return an error if write is
|
||||
possible while it is a shared mapping */
|
||||
if ((flags & MAP_TYPE) == MAP_SHARED &&
|
||||
(prot & PROT_WRITE))
|
||||
return -EINVAL;
|
||||
|
||||
/* adjust protection to be able to read */
|
||||
if (!(prot1 & PROT_WRITE))
|
||||
mprotect((void *)host_start, host_page_size, prot1 | PROT_WRITE);
|
||||
|
||||
/* read the corresponding file data */
|
||||
pread(fd, (void *)start, end - start, offset);
|
||||
|
||||
/* put final protection */
|
||||
if (prot_new != (prot1 | PROT_WRITE))
|
||||
mprotect((void *)host_start, host_page_size, prot_new);
|
||||
} else {
|
||||
/* just update the protection */
|
||||
if (prot_new != prot1) {
|
||||
mprotect((void *)host_start, host_page_size, prot_new);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* NOTE: all the constants are the HOST ones */
|
||||
long target_mmap(unsigned long start, unsigned long len, int prot,
|
||||
int flags, int fd, unsigned long offset)
|
||||
{
|
||||
unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len;
|
||||
|
||||
#ifdef DEBUG_MMAP
|
||||
{
|
||||
printf("mmap: start=0x%lx len=0x%lx prot=%c%c%c flags=",
|
||||
start, len,
|
||||
prot & PROT_READ ? 'r' : '-',
|
||||
prot & PROT_WRITE ? 'w' : '-',
|
||||
prot & PROT_EXEC ? 'x' : '-');
|
||||
if (flags & MAP_FIXED)
|
||||
printf("MAP_FIXED ");
|
||||
if (flags & MAP_ANONYMOUS)
|
||||
printf("MAP_ANON ");
|
||||
switch(flags & MAP_TYPE) {
|
||||
case MAP_PRIVATE:
|
||||
printf("MAP_PRIVATE ");
|
||||
break;
|
||||
case MAP_SHARED:
|
||||
printf("MAP_SHARED ");
|
||||
break;
|
||||
default:
|
||||
printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE);
|
||||
break;
|
||||
}
|
||||
printf("fd=%d offset=%lx\n", fd, offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (offset & ~TARGET_PAGE_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
len = TARGET_PAGE_ALIGN(len);
|
||||
if (len == 0)
|
||||
return start;
|
||||
host_start = start & host_page_mask;
|
||||
|
||||
if (!(flags & MAP_FIXED)) {
|
||||
#if defined(__alpha__) || defined(__sparc__)
|
||||
/* tell the kenel to search at the same place as i386 */
|
||||
if (host_start == 0)
|
||||
host_start = 0x40000000;
|
||||
#endif
|
||||
if (host_page_size != real_host_page_size) {
|
||||
/* NOTE: this code is only for debugging with '-p' option */
|
||||
/* reserve a memory area */
|
||||
host_len = HOST_PAGE_ALIGN(len) + host_page_size - TARGET_PAGE_SIZE;
|
||||
host_start = (long)mmap((void *)host_start, host_len, PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (host_start == -1)
|
||||
return host_start;
|
||||
host_end = host_start + host_len;
|
||||
start = HOST_PAGE_ALIGN(host_start);
|
||||
end = start + HOST_PAGE_ALIGN(len);
|
||||
if (start > host_start)
|
||||
munmap((void *)host_start, start - host_start);
|
||||
if (end < host_end)
|
||||
munmap((void *)end, host_end - end);
|
||||
/* use it as a fixed mapping */
|
||||
flags |= MAP_FIXED;
|
||||
} else {
|
||||
/* if not fixed, no need to do anything */
|
||||
host_offset = offset & host_page_mask;
|
||||
host_len = len + offset - host_offset;
|
||||
start = (long)mmap((void *)host_start, host_len,
|
||||
prot, flags, fd, host_offset);
|
||||
if (start == -1)
|
||||
return start;
|
||||
/* update start so that it points to the file position at 'offset' */
|
||||
if (!(flags & MAP_ANONYMOUS))
|
||||
start += offset - host_offset;
|
||||
goto the_end1;
|
||||
}
|
||||
}
|
||||
|
||||
if (start & ~TARGET_PAGE_MASK)
|
||||
return -EINVAL;
|
||||
end = start + len;
|
||||
host_end = HOST_PAGE_ALIGN(end);
|
||||
|
||||
/* worst case: we cannot map the file because the offset is not
|
||||
aligned, so we read it */
|
||||
if (!(flags & MAP_ANONYMOUS) &&
|
||||
(offset & ~host_page_mask) != (start & ~host_page_mask)) {
|
||||
/* msync() won't work here, so we return an error if write is
|
||||
possible while it is a shared mapping */
|
||||
if ((flags & MAP_TYPE) == MAP_SHARED &&
|
||||
(prot & PROT_WRITE))
|
||||
return -EINVAL;
|
||||
retaddr = target_mmap(start, len, prot | PROT_WRITE,
|
||||
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
if (retaddr == -1)
|
||||
return retaddr;
|
||||
pread(fd, (void *)start, len, offset);
|
||||
if (!(prot & PROT_WRITE)) {
|
||||
ret = target_mprotect(start, len, prot);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
/* handle the start of the mapping */
|
||||
if (start > host_start) {
|
||||
if (host_end == host_start + host_page_size) {
|
||||
/* one single host page */
|
||||
ret = mmap_frag(host_start, start, end,
|
||||
prot, flags, fd, offset);
|
||||
if (ret == -1)
|
||||
return ret;
|
||||
goto the_end1;
|
||||
}
|
||||
ret = mmap_frag(host_start, start, host_start + host_page_size,
|
||||
prot, flags, fd, offset);
|
||||
if (ret == -1)
|
||||
return ret;
|
||||
host_start += host_page_size;
|
||||
}
|
||||
/* handle the end of the mapping */
|
||||
if (end < host_end) {
|
||||
ret = mmap_frag(host_end - host_page_size,
|
||||
host_end - host_page_size, host_end,
|
||||
prot, flags, fd,
|
||||
offset + host_end - host_page_size - start);
|
||||
if (ret == -1)
|
||||
return ret;
|
||||
host_end -= host_page_size;
|
||||
}
|
||||
|
||||
/* map the middle (easier) */
|
||||
if (host_start < host_end) {
|
||||
unsigned long offset1;
|
||||
if (flags & MAP_ANONYMOUS)
|
||||
offset1 = 0;
|
||||
else
|
||||
offset1 = offset + host_start - start;
|
||||
ret = (long)mmap((void *)host_start, host_end - host_start,
|
||||
prot, flags, fd, offset1);
|
||||
if (ret == -1)
|
||||
return ret;
|
||||
}
|
||||
the_end1:
|
||||
page_set_flags(start, start + len, prot | PAGE_VALID);
|
||||
the_end:
|
||||
#ifdef DEBUG_MMAP
|
||||
printf("ret=0x%lx\n", (long)start);
|
||||
page_dump(stdout);
|
||||
printf("\n");
|
||||
#endif
|
||||
return start;
|
||||
}
|
||||
|
||||
int target_munmap(unsigned long start, unsigned long len)
|
||||
{
|
||||
unsigned long end, host_start, host_end, addr;
|
||||
int prot, ret;
|
||||
|
||||
#ifdef DEBUG_MMAP
|
||||
printf("munmap: start=0x%lx len=0x%lx\n", start, len);
|
||||
#endif
|
||||
if (start & ~TARGET_PAGE_MASK)
|
||||
return -EINVAL;
|
||||
len = TARGET_PAGE_ALIGN(len);
|
||||
if (len == 0)
|
||||
return -EINVAL;
|
||||
end = start + len;
|
||||
host_start = start & host_page_mask;
|
||||
host_end = HOST_PAGE_ALIGN(end);
|
||||
|
||||
if (start > host_start) {
|
||||
/* handle host page containing start */
|
||||
prot = 0;
|
||||
for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
|
||||
prot |= page_get_flags(addr);
|
||||
}
|
||||
if (host_end == host_start + host_page_size) {
|
||||
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
|
||||
prot |= page_get_flags(addr);
|
||||
}
|
||||
end = host_end;
|
||||
}
|
||||
if (prot != 0)
|
||||
host_start += host_page_size;
|
||||
}
|
||||
if (end < host_end) {
|
||||
prot = 0;
|
||||
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
|
||||
prot |= page_get_flags(addr);
|
||||
}
|
||||
if (prot != 0)
|
||||
host_end -= host_page_size;
|
||||
}
|
||||
|
||||
/* unmap what we can */
|
||||
if (host_start < host_end) {
|
||||
ret = munmap((void *)host_start, host_end - host_start);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
page_set_flags(start, start + len, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED
|
||||
blocks which have been allocated starting on a host page */
|
||||
long target_mremap(unsigned long old_addr, unsigned long old_size,
|
||||
unsigned long new_size, unsigned long flags,
|
||||
unsigned long new_addr)
|
||||
{
|
||||
int prot;
|
||||
|
||||
/* XXX: use 5 args syscall */
|
||||
new_addr = (long)mremap((void *)old_addr, old_size, new_size, flags);
|
||||
if (new_addr == -1)
|
||||
return new_addr;
|
||||
prot = page_get_flags(old_addr);
|
||||
page_set_flags(old_addr, old_addr + old_size, 0);
|
||||
page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
|
||||
return new_addr;
|
||||
}
|
||||
|
||||
int target_msync(unsigned long start, unsigned long len, int flags)
|
||||
{
|
||||
unsigned long end;
|
||||
|
||||
if (start & ~TARGET_PAGE_MASK)
|
||||
return -EINVAL;
|
||||
len = TARGET_PAGE_ALIGN(len);
|
||||
end = start + len;
|
||||
if (end < start)
|
||||
return -EINVAL;
|
||||
if (end == start)
|
||||
return 0;
|
||||
|
||||
start &= host_page_mask;
|
||||
return msync((void *)start, end - start, flags);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
/* Code to mangle pathnames into those matching a given prefix.
|
||||
eg. open("/lib/foo.so") => open("/usr/gnemul/i386-linux/lib/foo.so");
|
||||
|
||||
The assumption is that this area does not change.
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include "qemu.h"
|
||||
|
||||
struct pathelem
|
||||
{
|
||||
/* Name of this, eg. lib */
|
||||
char *name;
|
||||
/* Full path name, eg. /usr/gnemul/x86-linux/lib. */
|
||||
char *pathname;
|
||||
struct pathelem *parent;
|
||||
/* Children */
|
||||
unsigned int num_entries;
|
||||
struct pathelem *entries[0];
|
||||
};
|
||||
|
||||
static struct pathelem *base;
|
||||
|
||||
/* First N chars of S1 match S2, and S2 is N chars long. */
|
||||
static int strneq(const char *s1, unsigned int n, const char *s2)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
if (s1[i] != s2[i])
|
||||
return 0;
|
||||
return s2[i] == 0;
|
||||
}
|
||||
|
||||
static struct pathelem *add_entry(struct pathelem *root, const char *name);
|
||||
|
||||
static struct pathelem *new_entry(const char *root,
|
||||
struct pathelem *parent,
|
||||
const char *name)
|
||||
{
|
||||
struct pathelem *new = malloc(sizeof(*new));
|
||||
new->name = strdup(name);
|
||||
asprintf(&new->pathname, "%s/%s", root, name);
|
||||
new->num_entries = 0;
|
||||
return new;
|
||||
}
|
||||
|
||||
#define streq(a,b) (strcmp((a), (b)) == 0)
|
||||
|
||||
static struct pathelem *add_dir_maybe(struct pathelem *path)
|
||||
{
|
||||
DIR *dir;
|
||||
|
||||
if ((dir = opendir(path->pathname)) != NULL) {
|
||||
struct dirent *dirent;
|
||||
|
||||
while ((dirent = readdir(dir)) != NULL) {
|
||||
if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){
|
||||
path = add_entry(path, dirent->d_name);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
static struct pathelem *add_entry(struct pathelem *root, const char *name)
|
||||
{
|
||||
root->num_entries++;
|
||||
|
||||
root = realloc(root, sizeof(*root)
|
||||
+ sizeof(root->entries[0])*root->num_entries);
|
||||
|
||||
root->entries[root->num_entries-1] = new_entry(root->pathname, root, name);
|
||||
root->entries[root->num_entries-1]
|
||||
= add_dir_maybe(root->entries[root->num_entries-1]);
|
||||
return root;
|
||||
}
|
||||
|
||||
/* This needs to be done after tree is stabalized (ie. no more reallocs!). */
|
||||
static void set_parents(struct pathelem *child, struct pathelem *parent)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
child->parent = parent;
|
||||
for (i = 0; i < child->num_entries; i++)
|
||||
set_parents(child->entries[i], child);
|
||||
}
|
||||
|
||||
void init_paths(const char *prefix)
|
||||
{
|
||||
if (prefix[0] != '/' ||
|
||||
prefix[0] == '\0' ||
|
||||
!strcmp(prefix, "/"))
|
||||
return;
|
||||
|
||||
base = new_entry("", NULL, prefix+1);
|
||||
base = add_dir_maybe(base);
|
||||
set_parents(base, base);
|
||||
}
|
||||
|
||||
/* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */
|
||||
static const char *
|
||||
follow_path(const struct pathelem *cursor, const char *name)
|
||||
{
|
||||
unsigned int i, namelen;
|
||||
|
||||
name += strspn(name, "/");
|
||||
namelen = strcspn(name, "/");
|
||||
|
||||
if (namelen == 0)
|
||||
return cursor->pathname;
|
||||
|
||||
if (strneq(name, namelen, ".."))
|
||||
return follow_path(cursor->parent, name + namelen);
|
||||
|
||||
if (strneq(name, namelen, "."))
|
||||
return follow_path(cursor, name + namelen);
|
||||
|
||||
for (i = 0; i < cursor->num_entries; i++)
|
||||
if (strneq(name, namelen, cursor->entries[i]->name))
|
||||
return follow_path(cursor->entries[i], name + namelen);
|
||||
|
||||
/* Not found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Look for path in emulation dir, otherwise return name. */
|
||||
const char *path(const char *name)
|
||||
{
|
||||
/* Only do absolute paths: quick and dirty, but should mostly be OK.
|
||||
Could do relative by tracking cwd. */
|
||||
if (!base || name[0] != '/')
|
||||
return name;
|
||||
|
||||
return follow_path(base, name) ?: name;
|
||||
}
|
||||
+45
-5
@@ -6,9 +6,14 @@
|
||||
#include <signal.h>
|
||||
#include "syscall_defs.h"
|
||||
|
||||
#ifdef TARGET_I386
|
||||
#if defined(TARGET_I386)
|
||||
#include "cpu-i386.h"
|
||||
#include "syscall-i386.h"
|
||||
#elif defined(TARGET_ARM)
|
||||
#include "cpu-arm.h"
|
||||
#include "syscall-arm.h"
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
|
||||
/* This struct is used to hold certain information about the image.
|
||||
@@ -33,6 +38,7 @@ struct image_info {
|
||||
int personality;
|
||||
};
|
||||
|
||||
#ifdef TARGET_I386
|
||||
/* Information about the current linux thread */
|
||||
struct vm86_saved_state {
|
||||
uint32_t eax; /* return code */
|
||||
@@ -47,21 +53,26 @@ struct vm86_saved_state {
|
||||
uint32_t eip;
|
||||
uint16_t cs, ss, ds, es, fs, gs;
|
||||
};
|
||||
#endif
|
||||
|
||||
/* NOTE: we force a big alignment so that the stack stored after is
|
||||
aligned too */
|
||||
typedef struct TaskState {
|
||||
struct TaskState *next;
|
||||
#ifdef TARGET_I386
|
||||
struct target_vm86plus_struct *target_v86;
|
||||
struct vm86_saved_state vm86_saved_regs;
|
||||
struct target_vm86plus_struct vm86plus;
|
||||
uint32_t v86flags;
|
||||
uint32_t v86mask;
|
||||
#endif
|
||||
int used; /* non zero if used */
|
||||
uint8_t stack[0];
|
||||
} __attribute__((aligned(16))) TaskState;
|
||||
|
||||
extern TaskState *first_task_state;
|
||||
|
||||
int elf_exec(const char *interp_prefix,
|
||||
const char * filename, char ** argv, char ** envp,
|
||||
int elf_exec(const char * filename, char ** argv, char ** envp,
|
||||
struct target_pt_regs * regs, struct image_info *infop);
|
||||
|
||||
void target_set_brk(char *new_brk);
|
||||
@@ -69,11 +80,40 @@ void syscall_init(void);
|
||||
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
long arg4, long arg5, long arg6);
|
||||
void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
|
||||
extern CPUX86State *global_env;
|
||||
void cpu_loop(CPUX86State *env);
|
||||
extern CPUState *global_env;
|
||||
void cpu_loop(CPUState *env);
|
||||
void init_paths(const char *prefix);
|
||||
const char *path(const char *pathname);
|
||||
|
||||
extern int loglevel;
|
||||
extern FILE *logfile;
|
||||
|
||||
/* signal.c */
|
||||
void process_pending_signals(void *cpu_env);
|
||||
void signal_init(void);
|
||||
int queue_signal(int sig, target_siginfo_t *info);
|
||||
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
|
||||
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
|
||||
long do_sigreturn(CPUState *env);
|
||||
long do_rt_sigreturn(CPUState *env);
|
||||
|
||||
#ifdef TARGET_I386
|
||||
/* vm86.c */
|
||||
void save_v86_state(CPUX86State *env);
|
||||
void handle_vm86_trap(CPUX86State *env, int trapno);
|
||||
void handle_vm86_fault(CPUX86State *env);
|
||||
int do_vm86(CPUX86State *env, long subfunction,
|
||||
struct target_vm86plus_struct * target_v86);
|
||||
#endif
|
||||
|
||||
/* mmap.c */
|
||||
int target_mprotect(unsigned long start, unsigned long len, int prot);
|
||||
long target_mmap(unsigned long start, unsigned long len, int prot,
|
||||
int flags, int fd, unsigned long offset);
|
||||
int target_munmap(unsigned long start, unsigned long len);
|
||||
long target_mremap(unsigned long old_addr, unsigned long old_size,
|
||||
unsigned long new_size, unsigned long flags,
|
||||
unsigned long new_addr);
|
||||
int target_msync(unsigned long start, unsigned long len, int flags);
|
||||
|
||||
#endif
|
||||
+72
-52
@@ -21,10 +21,18 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
#ifdef __ia64__
|
||||
#undef uc_mcontext
|
||||
#undef uc_sigmask
|
||||
#undef uc_stack
|
||||
#undef uc_link
|
||||
#endif
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
//#define DEBUG_SIGNAL
|
||||
@@ -102,7 +110,8 @@ static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
|
||||
tinfo->si_signo = sig;
|
||||
tinfo->si_errno = 0;
|
||||
tinfo->si_code = 0;
|
||||
if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS) {
|
||||
if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
|
||||
sig == SIGBUS || sig == SIGTRAP) {
|
||||
/* should never come here, but who knows. The information for
|
||||
the target is irrelevant */
|
||||
tinfo->_sifields._sigfault._addr = 0;
|
||||
@@ -123,7 +132,8 @@ static void tswap_siginfo(target_siginfo_t *tinfo,
|
||||
tinfo->si_signo = tswap32(sig);
|
||||
tinfo->si_errno = tswap32(info->si_errno);
|
||||
tinfo->si_code = tswap32(info->si_code);
|
||||
if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS) {
|
||||
if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
|
||||
sig == SIGBUS || sig == SIGTRAP) {
|
||||
tinfo->_sifields._sigfault._addr =
|
||||
tswapl(info->_sifields._sigfault._addr);
|
||||
} else if (sig >= TARGET_SIGRTMIN) {
|
||||
@@ -165,7 +175,7 @@ void signal_init(void)
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
act.sa_sigaction = host_signal_handler;
|
||||
for(i = 1; i < NSIG; i++) {
|
||||
sigaction(i, &act, NULL);
|
||||
sigaction(i, &act, NULL);
|
||||
}
|
||||
|
||||
memset(sigact_table, 0, sizeof(sigact_table));
|
||||
@@ -308,7 +318,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
|
||||
/* the CPU emulator uses some host signals to detect exceptions,
|
||||
we we forward to it some signals */
|
||||
if (host_signum == SIGSEGV || host_signum == SIGBUS) {
|
||||
if (cpu_x86_signal_handler(host_signum, info, puc))
|
||||
if (cpu_signal_handler(host_signum, info, puc))
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -323,7 +333,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
|
||||
host_to_target_siginfo_noswap(&tinfo, info);
|
||||
if (queue_signal(sig, &tinfo) == 1) {
|
||||
/* interrupt the virtual CPU as soon as possible */
|
||||
cpu_x86_interrupt(global_env);
|
||||
cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,10 +517,10 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
err |= __put_user(env->segs[R_GS], (unsigned int *)&sc->gs);
|
||||
err |= __put_user(env->segs[R_FS], (unsigned int *)&sc->fs);
|
||||
err |= __put_user(env->segs[R_ES], (unsigned int *)&sc->es);
|
||||
err |= __put_user(env->segs[R_DS], (unsigned int *)&sc->ds);
|
||||
err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
|
||||
err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
|
||||
err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
|
||||
err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
|
||||
err |= __put_user(env->regs[R_EDI], &sc->edi);
|
||||
err |= __put_user(env->regs[R_ESI], &sc->esi);
|
||||
err |= __put_user(env->regs[R_EBP], &sc->ebp);
|
||||
@@ -519,25 +529,22 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
|
||||
err |= __put_user(env->regs[R_EDX], &sc->edx);
|
||||
err |= __put_user(env->regs[R_ECX], &sc->ecx);
|
||||
err |= __put_user(env->regs[R_EAX], &sc->eax);
|
||||
err |= __put_user(/*current->thread.trap_no*/ 0, &sc->trapno);
|
||||
err |= __put_user(/*current->thread.error_code*/ 0, &sc->err);
|
||||
err |= __put_user(env->exception_index, &sc->trapno);
|
||||
err |= __put_user(env->error_code, &sc->err);
|
||||
err |= __put_user(env->eip, &sc->eip);
|
||||
err |= __put_user(env->segs[R_CS], (unsigned int *)&sc->cs);
|
||||
err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
|
||||
err |= __put_user(env->eflags, &sc->eflags);
|
||||
err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
|
||||
err |= __put_user(env->segs[R_SS], (unsigned int *)&sc->ss);
|
||||
#if 0
|
||||
tmp = save_i387(fpstate);
|
||||
if (tmp < 0)
|
||||
err = 1;
|
||||
else
|
||||
err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate);
|
||||
#else
|
||||
err |= __put_user(0, &sc->fpstate);
|
||||
#endif
|
||||
err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
|
||||
|
||||
cpu_x86_fsave(env, (void *)fpstate, 1);
|
||||
fpstate->status = fpstate->sw;
|
||||
err |= __put_user(0xffff, &fpstate->magic);
|
||||
err |= __put_user(fpstate, &sc->fpstate);
|
||||
|
||||
/* non-iBCS2 extensions.. */
|
||||
err |= __put_user(mask, &sc->oldmask);
|
||||
err |= __put_user(/*current->thread.cr2*/ 0, &sc->cr2);
|
||||
err |= __put_user(env->cr[2], &sc->cr2);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -560,13 +567,14 @@ get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size)
|
||||
}
|
||||
|
||||
/* This is the legacy signal stack switching. */
|
||||
else if ((regs->xss & 0xffff) != __USER_DS &&
|
||||
!(ka->sa.sa_flags & SA_RESTORER) &&
|
||||
ka->sa.sa_restorer) {
|
||||
esp = (unsigned long) ka->sa.sa_restorer;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
return (void *)((esp - frame_size) & -8ul);
|
||||
if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
|
||||
!(ka->sa.sa_flags & TARGET_SA_RESTORER) &&
|
||||
ka->sa.sa_restorer) {
|
||||
esp = (unsigned long) ka->sa.sa_restorer;
|
||||
}
|
||||
return (void *)((esp - frame_size) & -8ul);
|
||||
}
|
||||
|
||||
static void setup_frame(int sig, struct emulated_sigaction *ka,
|
||||
@@ -711,25 +719,6 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
|
||||
{
|
||||
unsigned int err = 0;
|
||||
|
||||
|
||||
|
||||
#define COPY(x) err |= __get_user(regs->x, &sc->x)
|
||||
|
||||
#define COPY_SEG(seg) \
|
||||
{ unsigned short tmp; \
|
||||
err |= __get_user(tmp, &sc->seg); \
|
||||
regs->x##seg = tmp; }
|
||||
|
||||
#define COPY_SEG_STRICT(seg) \
|
||||
{ unsigned short tmp; \
|
||||
err |= __get_user(tmp, &sc->seg); \
|
||||
regs->x##seg = tmp|3; }
|
||||
|
||||
#define GET_SEG(seg) \
|
||||
{ unsigned short tmp; \
|
||||
err |= __get_user(tmp, &sc->seg); \
|
||||
loadsegment(seg,tmp); }
|
||||
|
||||
cpu_x86_load_seg(env, R_GS, lduw(&sc->gs));
|
||||
cpu_x86_load_seg(env, R_FS, lduw(&sc->fs));
|
||||
cpu_x86_load_seg(env, R_ES, lduw(&sc->es));
|
||||
@@ -754,17 +743,18 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
|
||||
// regs->orig_eax = -1; /* disable syscall checks */
|
||||
}
|
||||
|
||||
#if 0
|
||||
{
|
||||
struct _fpstate * buf;
|
||||
err |= __get_user(buf, &sc->fpstate);
|
||||
buf = (void *)ldl(&sc->fpstate);
|
||||
if (buf) {
|
||||
#if 0
|
||||
if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
|
||||
goto badframe;
|
||||
err |= restore_i387(buf);
|
||||
#endif
|
||||
cpu_x86_frstor(env, (void *)buf, 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
*peax = ldl(&sc->eax);
|
||||
return err;
|
||||
#if 0
|
||||
@@ -780,6 +770,9 @@ long do_sigreturn(CPUX86State *env)
|
||||
sigset_t set;
|
||||
int eax, i;
|
||||
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
fprintf(stderr, "do_sigreturn\n");
|
||||
#endif
|
||||
/* set blocked signals */
|
||||
target_set.sig[0] = frame->sc.oldmask;
|
||||
for(i = 1; i < TARGET_NSIG_WORDS; i++)
|
||||
@@ -832,6 +825,33 @@ badframe:
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void setup_frame(int sig, struct emulated_sigaction *ka,
|
||||
target_sigset_t *set, CPUState *env)
|
||||
{
|
||||
fprintf(stderr, "setup_frame: not implemented\n");
|
||||
}
|
||||
|
||||
static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
|
||||
target_siginfo_t *info,
|
||||
target_sigset_t *set, CPUState *env)
|
||||
{
|
||||
fprintf(stderr, "setup_rt_frame: not implemented\n");
|
||||
}
|
||||
|
||||
long do_sigreturn(CPUState *env)
|
||||
{
|
||||
fprintf(stderr, "do_sigreturn: not implemented\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
long do_rt_sigreturn(CPUState *env)
|
||||
{
|
||||
fprintf(stderr, "do_rt_sigreturn: not implemented\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void process_pending_signals(void *cpu_env)
|
||||
|
||||
+299
-157
@@ -58,25 +58,16 @@
|
||||
#include <linux/hdreg.h>
|
||||
#include <linux/soundcard.h>
|
||||
#include <linux/dirent.h>
|
||||
#include <linux/kd.h>
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
#ifndef PAGE_SIZE
|
||||
#define PAGE_SIZE 4096
|
||||
#define PAGE_MASK ~(PAGE_SIZE - 1)
|
||||
#endif
|
||||
|
||||
//#include <linux/msdos_fs.h>
|
||||
#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
|
||||
#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2])
|
||||
|
||||
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
|
||||
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
|
||||
long do_sigreturn(CPUX86State *env);
|
||||
long do_rt_sigreturn(CPUX86State *env);
|
||||
|
||||
#define __NR_sys_uname __NR_uname
|
||||
#define __NR_sys_getcwd1 __NR_getcwd
|
||||
#define __NR_sys_statfs __NR_statfs
|
||||
@@ -85,7 +76,7 @@ long do_rt_sigreturn(CPUX86State *env);
|
||||
#define __NR_sys_getdents64 __NR_getdents64
|
||||
#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
|
||||
|
||||
#ifdef __alpha__
|
||||
#if defined(__alpha__) || defined (__ia64__)
|
||||
#define __NR__llseek __NR_lseek
|
||||
#endif
|
||||
|
||||
@@ -105,6 +96,9 @@ _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
|
||||
_syscall2(int,sys_statfs,const char *,path,struct kernel_statfs *,buf)
|
||||
_syscall2(int,sys_fstatfs,int,fd,struct kernel_statfs *,buf)
|
||||
_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
|
||||
#ifdef __NR_exit_group
|
||||
_syscall1(int,exit_group,int,error_code)
|
||||
#endif
|
||||
|
||||
extern int personality(int);
|
||||
extern int flock(int, int);
|
||||
@@ -114,6 +108,7 @@ extern int setresuid(uid_t, uid_t, uid_t);
|
||||
extern int getresuid(uid_t *, uid_t *, uid_t *);
|
||||
extern int setresgid(gid_t, gid_t, gid_t);
|
||||
extern int getresgid(gid_t *, gid_t *, gid_t *);
|
||||
extern int setgroups(int, gid_t *);
|
||||
|
||||
static inline long get_errno(long ret)
|
||||
{
|
||||
@@ -148,7 +143,7 @@ static long do_brk(char *new_brk)
|
||||
if (new_brk < target_original_brk)
|
||||
return -ENOMEM;
|
||||
|
||||
brk_page = (char *)(((unsigned long)target_brk + PAGE_SIZE - 1) & PAGE_MASK);
|
||||
brk_page = (char *)HOST_PAGE_ALIGN((unsigned long)target_brk);
|
||||
|
||||
/* If the new brk is less than this, set it and we're done... */
|
||||
if (new_brk < brk_page) {
|
||||
@@ -157,11 +152,10 @@ static long do_brk(char *new_brk)
|
||||
}
|
||||
|
||||
/* We need to allocate more memory after the brk... */
|
||||
new_alloc_size = ((new_brk - brk_page + 1)+(PAGE_SIZE-1)) & PAGE_MASK;
|
||||
mapped_addr = get_errno((long)mmap((caddr_t)brk_page, new_alloc_size,
|
||||
PROT_READ|PROT_WRITE,
|
||||
MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0));
|
||||
|
||||
new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1);
|
||||
mapped_addr = get_errno(target_mmap((unsigned long)brk_page, new_alloc_size,
|
||||
PROT_READ|PROT_WRITE,
|
||||
MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0));
|
||||
if (is_error(mapped_addr)) {
|
||||
return mapped_addr;
|
||||
} else {
|
||||
@@ -216,6 +210,29 @@ static inline void host_to_target_fds(target_long *target_fds,
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void host_to_target_rusage(struct target_rusage *target_rusage,
|
||||
const struct rusage *rusage)
|
||||
{
|
||||
target_rusage->ru_utime.tv_sec = tswapl(rusage->ru_utime.tv_sec);
|
||||
target_rusage->ru_utime.tv_usec = tswapl(rusage->ru_utime.tv_usec);
|
||||
target_rusage->ru_stime.tv_sec = tswapl(rusage->ru_stime.tv_sec);
|
||||
target_rusage->ru_stime.tv_usec = tswapl(rusage->ru_stime.tv_usec);
|
||||
target_rusage->ru_maxrss = tswapl(rusage->ru_maxrss);
|
||||
target_rusage->ru_ixrss = tswapl(rusage->ru_ixrss);
|
||||
target_rusage->ru_idrss = tswapl(rusage->ru_idrss);
|
||||
target_rusage->ru_isrss = tswapl(rusage->ru_isrss);
|
||||
target_rusage->ru_minflt = tswapl(rusage->ru_minflt);
|
||||
target_rusage->ru_majflt = tswapl(rusage->ru_majflt);
|
||||
target_rusage->ru_nswap = tswapl(rusage->ru_nswap);
|
||||
target_rusage->ru_inblock = tswapl(rusage->ru_inblock);
|
||||
target_rusage->ru_oublock = tswapl(rusage->ru_oublock);
|
||||
target_rusage->ru_msgsnd = tswapl(rusage->ru_msgsnd);
|
||||
target_rusage->ru_msgrcv = tswapl(rusage->ru_msgrcv);
|
||||
target_rusage->ru_nsignals = tswapl(rusage->ru_nsignals);
|
||||
target_rusage->ru_nvcsw = tswapl(rusage->ru_nvcsw);
|
||||
target_rusage->ru_nivcsw = tswapl(rusage->ru_nivcsw);
|
||||
}
|
||||
|
||||
static inline void target_to_host_timeval(struct timeval *tv,
|
||||
const struct target_timeval *target_tv)
|
||||
{
|
||||
@@ -680,8 +697,8 @@ enum {
|
||||
#undef STRUCT_SPECIAL
|
||||
|
||||
typedef struct IOCTLEntry {
|
||||
int target_cmd;
|
||||
int host_cmd;
|
||||
unsigned int target_cmd;
|
||||
unsigned int host_cmd;
|
||||
const char *name;
|
||||
int access;
|
||||
const argtype arg_type[5];
|
||||
@@ -693,7 +710,7 @@ typedef struct IOCTLEntry {
|
||||
|
||||
#define MAX_STRUCT_SIZE 4096
|
||||
|
||||
const IOCTLEntry ioctl_entries[] = {
|
||||
IOCTLEntry ioctl_entries[] = {
|
||||
#define IOCTL(cmd, access, types...) \
|
||||
{ TARGET_ ## cmd, cmd, #cmd, access, { types } },
|
||||
#include "ioctls.h"
|
||||
@@ -936,7 +953,19 @@ StructEntry struct_termios_def = {
|
||||
.align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
|
||||
};
|
||||
|
||||
#ifdef TARGET_I386
|
||||
static bitmask_transtbl mmap_flags_tbl[] = {
|
||||
{ TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
|
||||
{ TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
|
||||
{ TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
|
||||
{ TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
|
||||
{ TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
|
||||
{ TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
|
||||
{ TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
|
||||
{ TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
|
||||
/* NOTE: there is really one LDT for all the threads */
|
||||
uint8_t *ldt_table;
|
||||
@@ -1025,7 +1054,7 @@ static int write_ldt(CPUX86State *env,
|
||||
0x7000;
|
||||
if (!oldmode)
|
||||
entry_2 |= (useable << 20);
|
||||
|
||||
|
||||
/* Install the new entry ... */
|
||||
install:
|
||||
lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
|
||||
@@ -1053,77 +1082,7 @@ int do_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecount
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* vm86 emulation */
|
||||
|
||||
#define SAFE_MASK (0xDD5)
|
||||
|
||||
int do_vm86(CPUX86State *env, long subfunction,
|
||||
struct target_vm86plus_struct * target_v86)
|
||||
{
|
||||
TaskState *ts = env->opaque;
|
||||
int ret;
|
||||
|
||||
switch (subfunction) {
|
||||
case TARGET_VM86_REQUEST_IRQ:
|
||||
case TARGET_VM86_FREE_IRQ:
|
||||
case TARGET_VM86_GET_IRQ_BITS:
|
||||
case TARGET_VM86_GET_AND_RESET_IRQ:
|
||||
gemu_log("qemu: unsupported vm86 subfunction (%ld)\n", subfunction);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
case TARGET_VM86_PLUS_INSTALL_CHECK:
|
||||
/* NOTE: on old vm86 stuff this will return the error
|
||||
from verify_area(), because the subfunction is
|
||||
interpreted as (invalid) address to vm86_struct.
|
||||
So the installation check works.
|
||||
*/
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ts->target_v86 = target_v86;
|
||||
/* save current CPU regs */
|
||||
ts->vm86_saved_regs.eax = 0; /* default vm86 syscall return code */
|
||||
ts->vm86_saved_regs.ebx = env->regs[R_EBX];
|
||||
ts->vm86_saved_regs.ecx = env->regs[R_ECX];
|
||||
ts->vm86_saved_regs.edx = env->regs[R_EDX];
|
||||
ts->vm86_saved_regs.esi = env->regs[R_ESI];
|
||||
ts->vm86_saved_regs.edi = env->regs[R_EDI];
|
||||
ts->vm86_saved_regs.ebp = env->regs[R_EBP];
|
||||
ts->vm86_saved_regs.esp = env->regs[R_ESP];
|
||||
ts->vm86_saved_regs.eflags = env->eflags;
|
||||
ts->vm86_saved_regs.eip = env->eip;
|
||||
ts->vm86_saved_regs.cs = env->segs[R_CS];
|
||||
ts->vm86_saved_regs.ss = env->segs[R_SS];
|
||||
ts->vm86_saved_regs.ds = env->segs[R_DS];
|
||||
ts->vm86_saved_regs.es = env->segs[R_ES];
|
||||
ts->vm86_saved_regs.fs = env->segs[R_FS];
|
||||
ts->vm86_saved_regs.gs = env->segs[R_GS];
|
||||
|
||||
/* build vm86 CPU state */
|
||||
env->eflags = (env->eflags & ~SAFE_MASK) |
|
||||
(tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK;
|
||||
|
||||
env->regs[R_EBX] = tswap32(target_v86->regs.ebx);
|
||||
env->regs[R_ECX] = tswap32(target_v86->regs.ecx);
|
||||
env->regs[R_EDX] = tswap32(target_v86->regs.edx);
|
||||
env->regs[R_ESI] = tswap32(target_v86->regs.esi);
|
||||
env->regs[R_EDI] = tswap32(target_v86->regs.edi);
|
||||
env->regs[R_EBP] = tswap32(target_v86->regs.ebp);
|
||||
env->regs[R_ESP] = tswap32(target_v86->regs.esp);
|
||||
env->eip = tswap32(target_v86->regs.eip);
|
||||
cpu_x86_load_seg(env, R_CS, tswap16(target_v86->regs.cs));
|
||||
cpu_x86_load_seg(env, R_SS, tswap16(target_v86->regs.ss));
|
||||
cpu_x86_load_seg(env, R_DS, tswap16(target_v86->regs.ds));
|
||||
cpu_x86_load_seg(env, R_ES, tswap16(target_v86->regs.es));
|
||||
cpu_x86_load_seg(env, R_FS, tswap16(target_v86->regs.fs));
|
||||
cpu_x86_load_seg(env, R_GS, tswap16(target_v86->regs.gs));
|
||||
ret = tswap32(target_v86->regs.eax); /* eax will be restored at
|
||||
the end of the syscall */
|
||||
/* now the virtual CPU is ready for vm86 execution ! */
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
#endif /* defined(TARGET_I386) */
|
||||
|
||||
/* this stack is the equivalent of the kernel stack associated with a
|
||||
thread/process */
|
||||
@@ -1131,22 +1090,20 @@ int do_vm86(CPUX86State *env, long subfunction,
|
||||
|
||||
static int clone_func(void *arg)
|
||||
{
|
||||
CPUX86State *env = arg;
|
||||
CPUState *env = arg;
|
||||
cpu_loop(env);
|
||||
/* never exits */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp)
|
||||
int do_fork(CPUState *env, unsigned int flags, unsigned long newsp)
|
||||
{
|
||||
int ret;
|
||||
TaskState *ts;
|
||||
uint8_t *new_stack;
|
||||
CPUX86State *new_env;
|
||||
CPUState *new_env;
|
||||
|
||||
if (flags & CLONE_VM) {
|
||||
if (!newsp)
|
||||
newsp = env->regs[R_ESP];
|
||||
ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE);
|
||||
memset(ts, 0, sizeof(TaskState));
|
||||
new_stack = ts->stack;
|
||||
@@ -1155,12 +1112,27 @@ int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp)
|
||||
ts->next = first_task_state;
|
||||
first_task_state = ts;
|
||||
/* we create a new CPU instance. */
|
||||
new_env = cpu_x86_init();
|
||||
memcpy(new_env, env, sizeof(CPUX86State));
|
||||
new_env = cpu_init();
|
||||
memcpy(new_env, env, sizeof(CPUState));
|
||||
#if defined(TARGET_I386)
|
||||
if (!newsp)
|
||||
newsp = env->regs[R_ESP];
|
||||
new_env->regs[R_ESP] = newsp;
|
||||
new_env->regs[R_EAX] = 0;
|
||||
#elif defined(TARGET_ARM)
|
||||
if (!newsp)
|
||||
newsp = env->regs[13];
|
||||
new_env->regs[13] = newsp;
|
||||
new_env->regs[0] = 0;
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
new_env->opaque = ts;
|
||||
ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
|
||||
#ifdef __ia64__
|
||||
ret = clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
|
||||
#else
|
||||
ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
|
||||
#endif
|
||||
} else {
|
||||
/* if no CLONE_VM, we consider it is a fork */
|
||||
if ((flags & ~CSIGNAL) != 0)
|
||||
@@ -1170,7 +1142,48 @@ int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
static long do_fcntl(int fd, int cmd, unsigned long arg)
|
||||
{
|
||||
struct flock fl;
|
||||
struct target_flock *target_fl = (void *)arg;
|
||||
long ret;
|
||||
|
||||
switch(cmd) {
|
||||
case TARGET_F_GETLK:
|
||||
ret = fcntl(fd, cmd, &fl);
|
||||
if (ret == 0) {
|
||||
target_fl->l_type = tswap16(fl.l_type);
|
||||
target_fl->l_whence = tswap16(fl.l_whence);
|
||||
target_fl->l_start = tswapl(fl.l_start);
|
||||
target_fl->l_len = tswapl(fl.l_len);
|
||||
target_fl->l_pid = tswapl(fl.l_pid);
|
||||
}
|
||||
break;
|
||||
|
||||
case TARGET_F_SETLK:
|
||||
case TARGET_F_SETLKW:
|
||||
fl.l_type = tswap16(target_fl->l_type);
|
||||
fl.l_whence = tswap16(target_fl->l_whence);
|
||||
fl.l_start = tswapl(target_fl->l_start);
|
||||
fl.l_len = tswapl(target_fl->l_len);
|
||||
fl.l_pid = tswapl(target_fl->l_pid);
|
||||
ret = fcntl(fd, cmd, &fl);
|
||||
break;
|
||||
|
||||
case TARGET_F_GETLK64:
|
||||
case TARGET_F_SETLK64:
|
||||
case TARGET_F_SETLKW64:
|
||||
ret = -1;
|
||||
errno = EINVAL;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = fcntl(fd, cmd, arg);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#define high2lowuid(x) (x)
|
||||
#define high2lowgid(x) (x)
|
||||
@@ -1179,11 +1192,43 @@ int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp)
|
||||
|
||||
void syscall_init(void)
|
||||
{
|
||||
IOCTLEntry *ie;
|
||||
const argtype *arg_type;
|
||||
int size;
|
||||
|
||||
#define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
|
||||
#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
|
||||
#include "syscall_types.h"
|
||||
#undef STRUCT
|
||||
#undef STRUCT_SPECIAL
|
||||
|
||||
/* we patch the ioctl size if necessary. We rely on the fact that
|
||||
no ioctl has all the bits at '1' in the size field */
|
||||
ie = ioctl_entries;
|
||||
while (ie->target_cmd != 0) {
|
||||
if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
|
||||
TARGET_IOC_SIZEMASK) {
|
||||
arg_type = ie->arg_type;
|
||||
if (arg_type[0] != TYPE_PTR) {
|
||||
fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
|
||||
ie->target_cmd);
|
||||
exit(1);
|
||||
}
|
||||
arg_type++;
|
||||
size = thunk_type_size(arg_type, 0);
|
||||
ie->target_cmd = (ie->target_cmd &
|
||||
~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
|
||||
(size << TARGET_IOC_SIZESHIFT);
|
||||
}
|
||||
/* automatic consistency check if same arch */
|
||||
#if defined(__i386__) && defined(TARGET_I386)
|
||||
if (ie->target_cmd != ie->host_cmd) {
|
||||
fprintf(stderr, "ERROR: ioctl: target=0x%x host=0x%x\n",
|
||||
ie->target_cmd, ie->host_cmd);
|
||||
}
|
||||
#endif
|
||||
ie++;
|
||||
}
|
||||
}
|
||||
|
||||
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
@@ -1206,13 +1251,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
ret = 0; /* avoid warning */
|
||||
break;
|
||||
case TARGET_NR_read:
|
||||
page_unprotect_range((void *)arg2, arg3);
|
||||
ret = get_errno(read(arg1, (void *)arg2, arg3));
|
||||
break;
|
||||
case TARGET_NR_write:
|
||||
ret = get_errno(write(arg1, (void *)arg2, arg3));
|
||||
break;
|
||||
case TARGET_NR_open:
|
||||
ret = get_errno(open((const char *)arg1, arg2, arg3));
|
||||
ret = get_errno(open(path((const char *)arg1), arg2, arg3));
|
||||
break;
|
||||
case TARGET_NR_close:
|
||||
ret = get_errno(close(arg1));
|
||||
@@ -1411,15 +1457,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
ret = do_ioctl(arg1, arg2, arg3);
|
||||
break;
|
||||
case TARGET_NR_fcntl:
|
||||
switch(arg2) {
|
||||
case F_GETLK:
|
||||
case F_SETLK:
|
||||
case F_SETLKW:
|
||||
goto unimplemented;
|
||||
default:
|
||||
ret = get_errno(fcntl(arg1, arg2, arg3));
|
||||
break;
|
||||
}
|
||||
ret = get_errno(do_fcntl(arg1, arg2, arg3));
|
||||
break;
|
||||
case TARGET_NR_mpx:
|
||||
goto unimplemented;
|
||||
@@ -1669,7 +1707,15 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_getrusage:
|
||||
goto unimplemented;
|
||||
{
|
||||
struct rusage rusage;
|
||||
struct target_rusage *target_rusage = (void *)arg2;
|
||||
ret = get_errno(getrusage(arg1, &rusage));
|
||||
if (!is_error(ret)) {
|
||||
host_to_target_rusage(target_rusage, &rusage);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_gettimeofday:
|
||||
{
|
||||
struct target_timeval *target_tv = (void *)arg1;
|
||||
@@ -1689,9 +1735,33 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_getgroups:
|
||||
goto unimplemented;
|
||||
{
|
||||
int gidsetsize = arg1;
|
||||
uint16_t *target_grouplist = (void *)arg2;
|
||||
gid_t *grouplist;
|
||||
int i;
|
||||
|
||||
grouplist = alloca(gidsetsize * sizeof(gid_t));
|
||||
ret = get_errno(getgroups(gidsetsize, grouplist));
|
||||
if (!is_error(ret)) {
|
||||
for(i = 0;i < gidsetsize; i++)
|
||||
target_grouplist[i] = tswap16(grouplist[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_setgroups:
|
||||
goto unimplemented;
|
||||
{
|
||||
int gidsetsize = arg1;
|
||||
uint16_t *target_grouplist = (void *)arg2;
|
||||
gid_t *grouplist;
|
||||
int i;
|
||||
|
||||
grouplist = alloca(gidsetsize * sizeof(gid_t));
|
||||
for(i = 0;i < gidsetsize; i++)
|
||||
grouplist[i] = tswap16(target_grouplist[i]);
|
||||
ret = get_errno(setgroups(gidsetsize, grouplist));
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_select:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_symlink:
|
||||
@@ -1700,7 +1770,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_oldlstat:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_readlink:
|
||||
ret = get_errno(readlink((const char *)arg1, (char *)arg2, arg3));
|
||||
ret = get_errno(readlink(path((const char *)arg1), (char *)arg2, arg3));
|
||||
break;
|
||||
case TARGET_NR_uselib:
|
||||
goto unimplemented;
|
||||
@@ -1722,7 +1792,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
v4 = tswap32(vptr[3]);
|
||||
v5 = tswap32(vptr[4]);
|
||||
v6 = tswap32(vptr[5]);
|
||||
ret = get_errno((long)mmap((void *)v1, v2, v3, v4, v5, v6));
|
||||
ret = get_errno(target_mmap(v1, v2, v3,
|
||||
target_to_host_bitmask(v4, mmap_flags_tbl),
|
||||
v5, v6));
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
@@ -1731,16 +1803,19 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
#else
|
||||
case TARGET_NR_mmap:
|
||||
#endif
|
||||
ret = get_errno((long)mmap((void *)arg1, arg2, arg3, arg4, arg5, arg6));
|
||||
ret = get_errno(target_mmap(arg1, arg2, arg3,
|
||||
target_to_host_bitmask(arg4, mmap_flags_tbl),
|
||||
arg5,
|
||||
arg6 << TARGET_PAGE_BITS));
|
||||
break;
|
||||
case TARGET_NR_munmap:
|
||||
ret = get_errno(munmap((void *)arg1, arg2));
|
||||
ret = get_errno(target_munmap(arg1, arg2));
|
||||
break;
|
||||
case TARGET_NR_mprotect:
|
||||
ret = get_errno(mprotect((void *)arg1, arg2, arg3));
|
||||
ret = get_errno(target_mprotect(arg1, arg2, arg3));
|
||||
break;
|
||||
case TARGET_NR_mremap:
|
||||
ret = get_errno((long)mremap((void *)arg1, arg2, arg3, arg4));
|
||||
ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
|
||||
break;
|
||||
case TARGET_NR_msync:
|
||||
ret = get_errno(msync((void *)arg1, arg2, arg3));
|
||||
@@ -1779,7 +1854,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
goto unimplemented;
|
||||
case TARGET_NR_statfs:
|
||||
stfs = (void *)arg2;
|
||||
ret = get_errno(sys_statfs((const char *)arg1, stfs));
|
||||
ret = get_errno(sys_statfs(path((const char *)arg1), stfs));
|
||||
convert_statfs:
|
||||
if (!is_error(ret)) {
|
||||
tswap32s(&stfs->f_type);
|
||||
@@ -1844,10 +1919,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_stat:
|
||||
ret = get_errno(stat((const char *)arg1, &st));
|
||||
ret = get_errno(stat(path((const char *)arg1), &st));
|
||||
goto do_stat;
|
||||
case TARGET_NR_lstat:
|
||||
ret = get_errno(lstat((const char *)arg1, &st));
|
||||
ret = get_errno(lstat(path((const char *)arg1), &st));
|
||||
goto do_stat;
|
||||
case TARGET_NR_fstat:
|
||||
{
|
||||
@@ -1857,7 +1932,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
struct target_stat *target_st = (void *)arg2;
|
||||
target_st->st_dev = tswap16(st.st_dev);
|
||||
target_st->st_ino = tswapl(st.st_ino);
|
||||
target_st->st_mode = tswap32(st.st_mode);
|
||||
target_st->st_mode = tswap16(st.st_mode);
|
||||
target_st->st_nlink = tswap16(st.st_nlink);
|
||||
target_st->st_uid = tswap16(st.st_uid);
|
||||
target_st->st_gid = tswap16(st.st_gid);
|
||||
@@ -1895,24 +1970,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
if (status_ptr)
|
||||
*status_ptr = tswap32(status);
|
||||
if (target_rusage) {
|
||||
target_rusage->ru_utime.tv_sec = tswapl(rusage.ru_utime.tv_sec);
|
||||
target_rusage->ru_utime.tv_usec = tswapl(rusage.ru_utime.tv_usec);
|
||||
target_rusage->ru_stime.tv_sec = tswapl(rusage.ru_stime.tv_sec);
|
||||
target_rusage->ru_stime.tv_usec = tswapl(rusage.ru_stime.tv_usec);
|
||||
target_rusage->ru_maxrss = tswapl(rusage.ru_maxrss);
|
||||
target_rusage->ru_ixrss = tswapl(rusage.ru_ixrss);
|
||||
target_rusage->ru_idrss = tswapl(rusage.ru_idrss);
|
||||
target_rusage->ru_isrss = tswapl(rusage.ru_isrss);
|
||||
target_rusage->ru_minflt = tswapl(rusage.ru_minflt);
|
||||
target_rusage->ru_majflt = tswapl(rusage.ru_majflt);
|
||||
target_rusage->ru_nswap = tswapl(rusage.ru_nswap);
|
||||
target_rusage->ru_inblock = tswapl(rusage.ru_inblock);
|
||||
target_rusage->ru_oublock = tswapl(rusage.ru_oublock);
|
||||
target_rusage->ru_msgsnd = tswapl(rusage.ru_msgsnd);
|
||||
target_rusage->ru_msgrcv = tswapl(rusage.ru_msgrcv);
|
||||
target_rusage->ru_nsignals = tswapl(rusage.ru_nsignals);
|
||||
target_rusage->ru_nvcsw = tswapl(rusage.ru_nvcsw);
|
||||
target_rusage->ru_nivcsw = tswapl(rusage.ru_nivcsw);
|
||||
host_to_target_rusage(target_rusage, &rusage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1930,6 +1988,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_clone:
|
||||
ret = get_errno(do_fork(cpu_env, arg1, arg2));
|
||||
break;
|
||||
#ifdef __NR_exit_group
|
||||
/* new thread calls */
|
||||
case TARGET_NR_exit_group:
|
||||
ret = get_errno(exit_group(arg1));
|
||||
break;
|
||||
#endif
|
||||
case TARGET_NR_setdomainname:
|
||||
ret = get_errno(setdomainname((const char *)arg1, arg2));
|
||||
break;
|
||||
@@ -1987,7 +2051,47 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_getdents:
|
||||
#if TARGET_LONG_SIZE != 4
|
||||
#error not supported
|
||||
#endif
|
||||
#elif TARGET_LONG_SIZE == 4 && HOST_LONG_SIZE == 8
|
||||
{
|
||||
struct target_dirent *target_dirp = (void *)arg2;
|
||||
struct dirent *dirp;
|
||||
long count = arg3;
|
||||
|
||||
dirp = malloc(count);
|
||||
if (!dirp)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = get_errno(sys_getdents(arg1, dirp, count));
|
||||
if (!is_error(ret)) {
|
||||
struct dirent *de;
|
||||
struct target_dirent *tde;
|
||||
int len = ret;
|
||||
int reclen, treclen;
|
||||
int count1, tnamelen;
|
||||
|
||||
count1 = 0;
|
||||
de = dirp;
|
||||
tde = target_dirp;
|
||||
while (len > 0) {
|
||||
reclen = de->d_reclen;
|
||||
treclen = reclen - (2 * (sizeof(long) - sizeof(target_long)));
|
||||
tde->d_reclen = tswap16(treclen);
|
||||
tde->d_ino = tswapl(de->d_ino);
|
||||
tde->d_off = tswapl(de->d_off);
|
||||
tnamelen = treclen - (2 * sizeof(target_long) + 2);
|
||||
if (tnamelen > 256)
|
||||
tnamelen = 256;
|
||||
strncpy(tde->d_name, de->d_name, tnamelen);
|
||||
de = (struct dirent *)((char *)de + reclen);
|
||||
len -= reclen;
|
||||
tde = (struct dirent *)((char *)tde + treclen);
|
||||
count1 += treclen;
|
||||
}
|
||||
ret = count1;
|
||||
}
|
||||
free(dirp);
|
||||
}
|
||||
#else
|
||||
{
|
||||
struct dirent *dirp = (void *)arg2;
|
||||
long count = arg3;
|
||||
@@ -2010,6 +2114,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case TARGET_NR_getdents64:
|
||||
{
|
||||
@@ -2204,9 +2309,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_prctl:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_pread:
|
||||
goto unimplemented;
|
||||
page_unprotect_range((void *)arg2, arg3);
|
||||
ret = get_errno(pread(arg1, (void *)arg2, arg3, arg4));
|
||||
break;
|
||||
case TARGET_NR_pwrite:
|
||||
goto unimplemented;
|
||||
ret = get_errno(pwrite(arg1, (void *)arg2, arg3, arg4));
|
||||
break;
|
||||
case TARGET_NR_chown:
|
||||
ret = get_errno(chown((const char *)arg1, arg2, arg3));
|
||||
break;
|
||||
@@ -2229,16 +2337,25 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0));
|
||||
break;
|
||||
case TARGET_NR_ugetrlimit:
|
||||
goto unimplemented;
|
||||
{
|
||||
struct rlimit rlim;
|
||||
ret = get_errno(getrlimit(arg1, &rlim));
|
||||
if (!is_error(ret)) {
|
||||
struct target_rlimit *target_rlim = (void *)arg2;
|
||||
target_rlim->rlim_cur = tswapl(rlim.rlim_cur);
|
||||
target_rlim->rlim_max = tswapl(rlim.rlim_max);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TARGET_NR_truncate64:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_ftruncate64:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_stat64:
|
||||
ret = get_errno(stat((const char *)arg1, &st));
|
||||
ret = get_errno(stat(path((const char *)arg1), &st));
|
||||
goto do_stat64;
|
||||
case TARGET_NR_lstat64:
|
||||
ret = get_errno(lstat((const char *)arg1, &st));
|
||||
ret = get_errno(lstat(path((const char *)arg1), &st));
|
||||
goto do_stat64;
|
||||
case TARGET_NR_fstat64:
|
||||
{
|
||||
@@ -2246,15 +2363,19 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
do_stat64:
|
||||
if (!is_error(ret)) {
|
||||
struct target_stat64 *target_st = (void *)arg2;
|
||||
memset(target_st, 0, sizeof(struct target_stat64));
|
||||
target_st->st_dev = tswap16(st.st_dev);
|
||||
target_st->st_ino = tswapl(st.st_ino);
|
||||
target_st->st_ino = tswap64(st.st_ino);
|
||||
#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
|
||||
target_st->__st_ino = tswapl(st.st_ino);
|
||||
#endif
|
||||
target_st->st_mode = tswap32(st.st_mode);
|
||||
target_st->st_nlink = tswap16(st.st_nlink);
|
||||
target_st->st_uid = tswap16(st.st_uid);
|
||||
target_st->st_gid = tswap16(st.st_gid);
|
||||
target_st->st_nlink = tswap32(st.st_nlink);
|
||||
target_st->st_uid = tswapl(st.st_uid);
|
||||
target_st->st_gid = tswapl(st.st_gid);
|
||||
target_st->st_rdev = tswap16(st.st_rdev);
|
||||
/* XXX: better use of kernel struct */
|
||||
target_st->st_size = tswapl(st.st_size);
|
||||
target_st->st_size = tswap64(st.st_size);
|
||||
target_st->st_blksize = tswapl(st.st_blksize);
|
||||
target_st->st_blocks = tswapl(st.st_blocks);
|
||||
target_st->target_st_atime = tswapl(st.st_atime);
|
||||
@@ -2343,16 +2464,37 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
goto unimplemented;
|
||||
#if TARGET_LONG_BITS == 32
|
||||
case TARGET_NR_fcntl64:
|
||||
{
|
||||
struct flock64 fl;
|
||||
struct target_flock64 *target_fl = (void *)arg3;
|
||||
|
||||
switch(arg2) {
|
||||
case F_GETLK64:
|
||||
ret = get_errno(fcntl(arg1, arg2, &fl));
|
||||
if (ret == 0) {
|
||||
target_fl->l_type = tswap16(fl.l_type);
|
||||
target_fl->l_whence = tswap16(fl.l_whence);
|
||||
target_fl->l_start = tswap64(fl.l_start);
|
||||
target_fl->l_len = tswap64(fl.l_len);
|
||||
target_fl->l_pid = tswapl(fl.l_pid);
|
||||
}
|
||||
break;
|
||||
|
||||
case F_SETLK64:
|
||||
case F_SETLKW64:
|
||||
goto unimplemented;
|
||||
fl.l_type = tswap16(target_fl->l_type);
|
||||
fl.l_whence = tswap16(target_fl->l_whence);
|
||||
fl.l_start = tswap64(target_fl->l_start);
|
||||
fl.l_len = tswap64(target_fl->l_len);
|
||||
fl.l_pid = tswapl(target_fl->l_pid);
|
||||
ret = get_errno(fcntl(arg1, arg2, &fl));
|
||||
break;
|
||||
default:
|
||||
ret = get_errno(fcntl(arg1, arg2, arg3));
|
||||
ret = get_errno(do_fcntl(arg1, arg2, arg3));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case TARGET_NR_security:
|
||||
goto unimplemented;
|
||||
|
||||
+992
-2
File diff suppressed because it is too large.
Load diff
@@ -64,3 +64,15 @@ STRUCT(hd_geometry,
|
||||
|
||||
STRUCT(dirent,
|
||||
TYPE_LONG, TYPE_LONG, TYPE_SHORT, MK_ARRAY(TYPE_CHAR, 256))
|
||||
|
||||
STRUCT(kbentry,
|
||||
TYPE_CHAR, TYPE_CHAR, TYPE_SHORT)
|
||||
|
||||
STRUCT(audio_buf_info,
|
||||
TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT)
|
||||
|
||||
STRUCT(count_info,
|
||||
TYPE_INT, TYPE_INT, TYPE_INT)
|
||||
|
||||
STRUCT(mixer_info,
|
||||
MK_ARRAY(TYPE_CHAR, 16), MK_ARRAY(TYPE_CHAR, 32), TYPE_INT, MK_ARRAY(TYPE_INT, 10))
|
||||
@@ -0,0 +1,477 @@
|
||||
/*
|
||||
* vm86 linux syscall support
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
//#define DEBUG_VM86
|
||||
|
||||
#define set_flags(X,new,mask) \
|
||||
((X) = ((X) & ~(mask)) | ((new) & (mask)))
|
||||
|
||||
#define SAFE_MASK (0xDD5)
|
||||
#define RETURN_MASK (0xDFF)
|
||||
|
||||
static inline int is_revectored(int nr, struct target_revectored_struct *bitmap)
|
||||
{
|
||||
return (((uint8_t *)bitmap)[nr >> 3] >> (nr & 7)) & 1;
|
||||
}
|
||||
|
||||
static inline void vm_putw(uint8_t *segptr, unsigned int reg16, unsigned int val)
|
||||
{
|
||||
stw(segptr + (reg16 & 0xffff), val);
|
||||
}
|
||||
|
||||
static inline void vm_putl(uint8_t *segptr, unsigned int reg16, unsigned int val)
|
||||
{
|
||||
stl(segptr + (reg16 & 0xffff), val);
|
||||
}
|
||||
|
||||
static inline unsigned int vm_getw(uint8_t *segptr, unsigned int reg16)
|
||||
{
|
||||
return lduw(segptr + (reg16 & 0xffff));
|
||||
}
|
||||
|
||||
static inline unsigned int vm_getl(uint8_t *segptr, unsigned int reg16)
|
||||
{
|
||||
return ldl(segptr + (reg16 & 0xffff));
|
||||
}
|
||||
|
||||
void save_v86_state(CPUX86State *env)
|
||||
{
|
||||
TaskState *ts = env->opaque;
|
||||
|
||||
/* put the VM86 registers in the userspace register structure */
|
||||
ts->target_v86->regs.eax = tswap32(env->regs[R_EAX]);
|
||||
ts->target_v86->regs.ebx = tswap32(env->regs[R_EBX]);
|
||||
ts->target_v86->regs.ecx = tswap32(env->regs[R_ECX]);
|
||||
ts->target_v86->regs.edx = tswap32(env->regs[R_EDX]);
|
||||
ts->target_v86->regs.esi = tswap32(env->regs[R_ESI]);
|
||||
ts->target_v86->regs.edi = tswap32(env->regs[R_EDI]);
|
||||
ts->target_v86->regs.ebp = tswap32(env->regs[R_EBP]);
|
||||
ts->target_v86->regs.esp = tswap32(env->regs[R_ESP]);
|
||||
ts->target_v86->regs.eip = tswap32(env->eip);
|
||||
ts->target_v86->regs.cs = tswap16(env->segs[R_CS].selector);
|
||||
ts->target_v86->regs.ss = tswap16(env->segs[R_SS].selector);
|
||||
ts->target_v86->regs.ds = tswap16(env->segs[R_DS].selector);
|
||||
ts->target_v86->regs.es = tswap16(env->segs[R_ES].selector);
|
||||
ts->target_v86->regs.fs = tswap16(env->segs[R_FS].selector);
|
||||
ts->target_v86->regs.gs = tswap16(env->segs[R_GS].selector);
|
||||
set_flags(env->eflags, ts->v86flags, VIF_MASK | ts->v86mask);
|
||||
ts->target_v86->regs.eflags = tswap32(env->eflags);
|
||||
#ifdef DEBUG_VM86
|
||||
fprintf(logfile, "save_v86_state: eflags=%08x cs:ip=%04x:%04x\n",
|
||||
env->eflags, env->segs[R_CS].selector, env->eip);
|
||||
#endif
|
||||
|
||||
/* restore 32 bit registers */
|
||||
env->regs[R_EAX] = ts->vm86_saved_regs.eax;
|
||||
env->regs[R_EBX] = ts->vm86_saved_regs.ebx;
|
||||
env->regs[R_ECX] = ts->vm86_saved_regs.ecx;
|
||||
env->regs[R_EDX] = ts->vm86_saved_regs.edx;
|
||||
env->regs[R_ESI] = ts->vm86_saved_regs.esi;
|
||||
env->regs[R_EDI] = ts->vm86_saved_regs.edi;
|
||||
env->regs[R_EBP] = ts->vm86_saved_regs.ebp;
|
||||
env->regs[R_ESP] = ts->vm86_saved_regs.esp;
|
||||
env->eflags = ts->vm86_saved_regs.eflags;
|
||||
env->eip = ts->vm86_saved_regs.eip;
|
||||
|
||||
cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs);
|
||||
cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss);
|
||||
cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds);
|
||||
cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es);
|
||||
cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs);
|
||||
cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs);
|
||||
}
|
||||
|
||||
/* return from vm86 mode to 32 bit. The vm86() syscall will return
|
||||
'retval' */
|
||||
static inline void return_to_32bit(CPUX86State *env, int retval)
|
||||
{
|
||||
#ifdef DEBUG_VM86
|
||||
fprintf(logfile, "return_to_32bit: ret=0x%x\n", retval);
|
||||
#endif
|
||||
save_v86_state(env);
|
||||
env->regs[R_EAX] = retval;
|
||||
}
|
||||
|
||||
static inline int set_IF(CPUX86State *env)
|
||||
{
|
||||
TaskState *ts = env->opaque;
|
||||
|
||||
ts->v86flags |= VIF_MASK;
|
||||
if (ts->v86flags & VIP_MASK) {
|
||||
return_to_32bit(env, TARGET_VM86_STI);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void clear_IF(CPUX86State *env)
|
||||
{
|
||||
TaskState *ts = env->opaque;
|
||||
|
||||
ts->v86flags &= ~VIF_MASK;
|
||||
}
|
||||
|
||||
static inline void clear_TF(CPUX86State *env)
|
||||
{
|
||||
env->eflags &= ~TF_MASK;
|
||||
}
|
||||
|
||||
static inline void clear_AC(CPUX86State *env)
|
||||
{
|
||||
env->eflags &= ~AC_MASK;
|
||||
}
|
||||
|
||||
static inline int set_vflags_long(unsigned long eflags, CPUX86State *env)
|
||||
{
|
||||
TaskState *ts = env->opaque;
|
||||
|
||||
set_flags(ts->v86flags, eflags, ts->v86mask);
|
||||
set_flags(env->eflags, eflags, SAFE_MASK);
|
||||
if (eflags & IF_MASK)
|
||||
return set_IF(env);
|
||||
else
|
||||
clear_IF(env);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int set_vflags_short(unsigned short flags, CPUX86State *env)
|
||||
{
|
||||
TaskState *ts = env->opaque;
|
||||
|
||||
set_flags(ts->v86flags, flags, ts->v86mask & 0xffff);
|
||||
set_flags(env->eflags, flags, SAFE_MASK);
|
||||
if (flags & IF_MASK)
|
||||
return set_IF(env);
|
||||
else
|
||||
clear_IF(env);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned int get_vflags(CPUX86State *env)
|
||||
{
|
||||
TaskState *ts = env->opaque;
|
||||
unsigned int flags;
|
||||
|
||||
flags = env->eflags & RETURN_MASK;
|
||||
if (ts->v86flags & VIF_MASK)
|
||||
flags |= IF_MASK;
|
||||
flags |= IOPL_MASK;
|
||||
return flags | (ts->v86flags & ts->v86mask);
|
||||
}
|
||||
|
||||
#define ADD16(reg, val) reg = (reg & ~0xffff) | ((reg + (val)) & 0xffff)
|
||||
|
||||
/* handle VM86 interrupt (NOTE: the CPU core currently does not
|
||||
support TSS interrupt revectoring, so this code is always executed) */
|
||||
static void do_int(CPUX86State *env, int intno)
|
||||
{
|
||||
TaskState *ts = env->opaque;
|
||||
uint32_t *int_ptr, segoffs;
|
||||
uint8_t *ssp;
|
||||
unsigned int sp;
|
||||
|
||||
if (env->segs[R_CS].selector == TARGET_BIOSSEG)
|
||||
goto cannot_handle;
|
||||
if (is_revectored(intno, &ts->vm86plus.int_revectored))
|
||||
goto cannot_handle;
|
||||
if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff,
|
||||
&ts->vm86plus.int21_revectored))
|
||||
goto cannot_handle;
|
||||
int_ptr = (uint32_t *)(intno << 2);
|
||||
segoffs = tswap32(*int_ptr);
|
||||
if ((segoffs >> 16) == TARGET_BIOSSEG)
|
||||
goto cannot_handle;
|
||||
#if defined(DEBUG_VM86)
|
||||
fprintf(logfile, "VM86: emulating int 0x%x. CS:IP=%04x:%04x\n",
|
||||
intno, segoffs >> 16, segoffs & 0xffff);
|
||||
#endif
|
||||
/* save old state */
|
||||
ssp = (uint8_t *)(env->segs[R_SS].selector << 4);
|
||||
sp = env->regs[R_ESP] & 0xffff;
|
||||
vm_putw(ssp, sp - 2, get_vflags(env));
|
||||
vm_putw(ssp, sp - 4, env->segs[R_CS].selector);
|
||||
vm_putw(ssp, sp - 6, env->eip);
|
||||
ADD16(env->regs[R_ESP], -6);
|
||||
/* goto interrupt handler */
|
||||
env->eip = segoffs & 0xffff;
|
||||
cpu_x86_load_seg(env, R_CS, segoffs >> 16);
|
||||
clear_TF(env);
|
||||
clear_IF(env);
|
||||
clear_AC(env);
|
||||
return;
|
||||
cannot_handle:
|
||||
#if defined(DEBUG_VM86)
|
||||
fprintf(logfile, "VM86: return to 32 bits int 0x%x\n", intno);
|
||||
#endif
|
||||
return_to_32bit(env, TARGET_VM86_INTx | (intno << 8));
|
||||
}
|
||||
|
||||
void handle_vm86_trap(CPUX86State *env, int trapno)
|
||||
{
|
||||
if (trapno == 1 || trapno == 3) {
|
||||
return_to_32bit(env, TARGET_VM86_TRAP + (trapno << 8));
|
||||
} else {
|
||||
do_int(env, trapno);
|
||||
}
|
||||
}
|
||||
|
||||
#define CHECK_IF_IN_TRAP() \
|
||||
if ((ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) && \
|
||||
(ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_TFpendig)) \
|
||||
newflags |= TF_MASK
|
||||
|
||||
#define VM86_FAULT_RETURN \
|
||||
if ((ts->vm86plus.vm86plus.flags & TARGET_force_return_for_pic) && \
|
||||
(ts->v86flags & (IF_MASK | VIF_MASK))) \
|
||||
return_to_32bit(env, TARGET_VM86_PICRETURN); \
|
||||
return
|
||||
|
||||
void handle_vm86_fault(CPUX86State *env)
|
||||
{
|
||||
TaskState *ts = env->opaque;
|
||||
uint8_t *csp, *pc, *ssp;
|
||||
unsigned int ip, sp, newflags, newip, newcs, opcode, intno;
|
||||
int data32, pref_done;
|
||||
|
||||
csp = (uint8_t *)(env->segs[R_CS].selector << 4);
|
||||
ip = env->eip & 0xffff;
|
||||
pc = csp + ip;
|
||||
|
||||
ssp = (uint8_t *)(env->segs[R_SS].selector << 4);
|
||||
sp = env->regs[R_ESP] & 0xffff;
|
||||
|
||||
#if defined(DEBUG_VM86)
|
||||
fprintf(logfile, "VM86 exception %04x:%08x %02x %02x\n",
|
||||
env->segs[R_CS].selector, env->eip, pc[0], pc[1]);
|
||||
#endif
|
||||
|
||||
data32 = 0;
|
||||
pref_done = 0;
|
||||
do {
|
||||
opcode = csp[ip];
|
||||
ADD16(ip, 1);
|
||||
switch (opcode) {
|
||||
case 0x66: /* 32-bit data */ data32=1; break;
|
||||
case 0x67: /* 32-bit address */ break;
|
||||
case 0x2e: /* CS */ break;
|
||||
case 0x3e: /* DS */ break;
|
||||
case 0x26: /* ES */ break;
|
||||
case 0x36: /* SS */ break;
|
||||
case 0x65: /* GS */ break;
|
||||
case 0x64: /* FS */ break;
|
||||
case 0xf2: /* repnz */ break;
|
||||
case 0xf3: /* rep */ break;
|
||||
default: pref_done = 1;
|
||||
}
|
||||
} while (!pref_done);
|
||||
|
||||
/* VM86 mode */
|
||||
switch(opcode) {
|
||||
case 0x9c: /* pushf */
|
||||
if (data32) {
|
||||
vm_putl(ssp, sp - 4, get_vflags(env));
|
||||
ADD16(env->regs[R_ESP], -4);
|
||||
} else {
|
||||
vm_putw(ssp, sp - 2, get_vflags(env));
|
||||
ADD16(env->regs[R_ESP], -2);
|
||||
}
|
||||
env->eip = ip;
|
||||
VM86_FAULT_RETURN;
|
||||
|
||||
case 0x9d: /* popf */
|
||||
if (data32) {
|
||||
newflags = vm_getl(ssp, sp);
|
||||
ADD16(env->regs[R_ESP], 4);
|
||||
} else {
|
||||
newflags = vm_getw(ssp, sp);
|
||||
ADD16(env->regs[R_ESP], 2);
|
||||
}
|
||||
env->eip = ip;
|
||||
CHECK_IF_IN_TRAP();
|
||||
if (data32) {
|
||||
if (set_vflags_long(newflags, env))
|
||||
return;
|
||||
} else {
|
||||
if (set_vflags_short(newflags, env))
|
||||
return;
|
||||
}
|
||||
VM86_FAULT_RETURN;
|
||||
|
||||
case 0xcd: /* int */
|
||||
intno = csp[ip];
|
||||
ADD16(ip, 1);
|
||||
env->eip = ip;
|
||||
if (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) {
|
||||
if ( (ts->vm86plus.vm86plus.vm86dbg_intxxtab[intno >> 3] >>
|
||||
(intno &7)) & 1) {
|
||||
return_to_32bit(env, TARGET_VM86_INTx + (intno << 8));
|
||||
return;
|
||||
}
|
||||
}
|
||||
do_int(env, intno);
|
||||
break;
|
||||
|
||||
case 0xcf: /* iret */
|
||||
if (data32) {
|
||||
newip = vm_getl(ssp, sp) & 0xffff;
|
||||
newcs = vm_getl(ssp, sp + 4) & 0xffff;
|
||||
newflags = vm_getl(ssp, sp + 8);
|
||||
ADD16(env->regs[R_ESP], 12);
|
||||
} else {
|
||||
newip = vm_getw(ssp, sp);
|
||||
newcs = vm_getw(ssp, sp + 2);
|
||||
newflags = vm_getw(ssp, sp + 4);
|
||||
ADD16(env->regs[R_ESP], 6);
|
||||
}
|
||||
env->eip = newip;
|
||||
cpu_x86_load_seg(env, R_CS, newcs);
|
||||
CHECK_IF_IN_TRAP();
|
||||
if (data32) {
|
||||
if (set_vflags_long(newflags, env))
|
||||
return;
|
||||
} else {
|
||||
if (set_vflags_short(newflags, env))
|
||||
return;
|
||||
}
|
||||
VM86_FAULT_RETURN;
|
||||
|
||||
case 0xfa: /* cli */
|
||||
env->eip = ip;
|
||||
clear_IF(env);
|
||||
VM86_FAULT_RETURN;
|
||||
|
||||
case 0xfb: /* sti */
|
||||
env->eip = ip;
|
||||
if (set_IF(env))
|
||||
return;
|
||||
VM86_FAULT_RETURN;
|
||||
|
||||
default:
|
||||
/* real VM86 GPF exception */
|
||||
return_to_32bit(env, TARGET_VM86_UNKNOWN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int do_vm86(CPUX86State *env, long subfunction,
|
||||
struct target_vm86plus_struct * target_v86)
|
||||
{
|
||||
TaskState *ts = env->opaque;
|
||||
int ret;
|
||||
|
||||
switch (subfunction) {
|
||||
case TARGET_VM86_REQUEST_IRQ:
|
||||
case TARGET_VM86_FREE_IRQ:
|
||||
case TARGET_VM86_GET_IRQ_BITS:
|
||||
case TARGET_VM86_GET_AND_RESET_IRQ:
|
||||
gemu_log("qemu: unsupported vm86 subfunction (%ld)\n", subfunction);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
case TARGET_VM86_PLUS_INSTALL_CHECK:
|
||||
/* NOTE: on old vm86 stuff this will return the error
|
||||
from verify_area(), because the subfunction is
|
||||
interpreted as (invalid) address to vm86_struct.
|
||||
So the installation check works.
|
||||
*/
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ts->target_v86 = target_v86;
|
||||
/* save current CPU regs */
|
||||
ts->vm86_saved_regs.eax = 0; /* default vm86 syscall return code */
|
||||
ts->vm86_saved_regs.ebx = env->regs[R_EBX];
|
||||
ts->vm86_saved_regs.ecx = env->regs[R_ECX];
|
||||
ts->vm86_saved_regs.edx = env->regs[R_EDX];
|
||||
ts->vm86_saved_regs.esi = env->regs[R_ESI];
|
||||
ts->vm86_saved_regs.edi = env->regs[R_EDI];
|
||||
ts->vm86_saved_regs.ebp = env->regs[R_EBP];
|
||||
ts->vm86_saved_regs.esp = env->regs[R_ESP];
|
||||
ts->vm86_saved_regs.eflags = env->eflags;
|
||||
ts->vm86_saved_regs.eip = env->eip;
|
||||
ts->vm86_saved_regs.cs = env->segs[R_CS].selector;
|
||||
ts->vm86_saved_regs.ss = env->segs[R_SS].selector;
|
||||
ts->vm86_saved_regs.ds = env->segs[R_DS].selector;
|
||||
ts->vm86_saved_regs.es = env->segs[R_ES].selector;
|
||||
ts->vm86_saved_regs.fs = env->segs[R_FS].selector;
|
||||
ts->vm86_saved_regs.gs = env->segs[R_GS].selector;
|
||||
|
||||
/* build vm86 CPU state */
|
||||
ts->v86flags = tswap32(target_v86->regs.eflags);
|
||||
env->eflags = (env->eflags & ~SAFE_MASK) |
|
||||
(tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK;
|
||||
|
||||
ts->vm86plus.cpu_type = tswapl(target_v86->cpu_type);
|
||||
switch (ts->vm86plus.cpu_type) {
|
||||
case TARGET_CPU_286:
|
||||
ts->v86mask = 0;
|
||||
break;
|
||||
case TARGET_CPU_386:
|
||||
ts->v86mask = NT_MASK | IOPL_MASK;
|
||||
break;
|
||||
case TARGET_CPU_486:
|
||||
ts->v86mask = AC_MASK | NT_MASK | IOPL_MASK;
|
||||
break;
|
||||
default:
|
||||
ts->v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
|
||||
break;
|
||||
}
|
||||
|
||||
env->regs[R_EBX] = tswap32(target_v86->regs.ebx);
|
||||
env->regs[R_ECX] = tswap32(target_v86->regs.ecx);
|
||||
env->regs[R_EDX] = tswap32(target_v86->regs.edx);
|
||||
env->regs[R_ESI] = tswap32(target_v86->regs.esi);
|
||||
env->regs[R_EDI] = tswap32(target_v86->regs.edi);
|
||||
env->regs[R_EBP] = tswap32(target_v86->regs.ebp);
|
||||
env->regs[R_ESP] = tswap32(target_v86->regs.esp);
|
||||
env->eip = tswap32(target_v86->regs.eip);
|
||||
cpu_x86_load_seg(env, R_CS, tswap16(target_v86->regs.cs));
|
||||
cpu_x86_load_seg(env, R_SS, tswap16(target_v86->regs.ss));
|
||||
cpu_x86_load_seg(env, R_DS, tswap16(target_v86->regs.ds));
|
||||
cpu_x86_load_seg(env, R_ES, tswap16(target_v86->regs.es));
|
||||
cpu_x86_load_seg(env, R_FS, tswap16(target_v86->regs.fs));
|
||||
cpu_x86_load_seg(env, R_GS, tswap16(target_v86->regs.gs));
|
||||
ret = tswap32(target_v86->regs.eax); /* eax will be restored at
|
||||
the end of the syscall */
|
||||
memcpy(&ts->vm86plus.int_revectored,
|
||||
&target_v86->int_revectored, 32);
|
||||
memcpy(&ts->vm86plus.int21_revectored,
|
||||
&target_v86->int21_revectored, 32);
|
||||
ts->vm86plus.vm86plus.flags = tswapl(target_v86->vm86plus.flags);
|
||||
memcpy(&ts->vm86plus.vm86plus.vm86dbg_intxxtab,
|
||||
target_v86->vm86plus.vm86dbg_intxxtab, 32);
|
||||
|
||||
#ifdef DEBUG_VM86
|
||||
fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n",
|
||||
env->segs[R_CS].selector, env->eip);
|
||||
#endif
|
||||
/* now the virtual CPU is ready for vm86 execution ! */
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* ARM micro operations (templates for various register related
|
||||
* operations)
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
void OPPROTO glue(op_movl_T0_, REGNAME)(void)
|
||||
{
|
||||
T0 = REG;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_movl_T1_, REGNAME)(void)
|
||||
{
|
||||
T1 = REG;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_movl_T2_, REGNAME)(void)
|
||||
{
|
||||
T2 = REG;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_movl_, REGNAME), _T0)(void)
|
||||
{
|
||||
REG = T0;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_movl_, REGNAME), _T1)(void)
|
||||
{
|
||||
REG = T1;
|
||||
}
|
||||
|
||||
#undef REG
|
||||
#undef REGNAME
|
||||
@@ -0,0 +1,665 @@
|
||||
/*
|
||||
* ARM micro operations
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "exec-arm.h"
|
||||
|
||||
#define REGNAME r0
|
||||
#define REG (env->regs[0])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r1
|
||||
#define REG (env->regs[1])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r2
|
||||
#define REG (env->regs[2])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r3
|
||||
#define REG (env->regs[3])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r4
|
||||
#define REG (env->regs[4])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r5
|
||||
#define REG (env->regs[5])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r6
|
||||
#define REG (env->regs[6])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r7
|
||||
#define REG (env->regs[7])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r8
|
||||
#define REG (env->regs[8])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r9
|
||||
#define REG (env->regs[9])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r10
|
||||
#define REG (env->regs[10])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r11
|
||||
#define REG (env->regs[11])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r12
|
||||
#define REG (env->regs[12])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r13
|
||||
#define REG (env->regs[13])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r14
|
||||
#define REG (env->regs[14])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r15
|
||||
#define REG (env->regs[15])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
void OPPROTO op_movl_T0_0(void)
|
||||
{
|
||||
T0 = 0;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T0_im(void)
|
||||
{
|
||||
T0 = PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T1_im(void)
|
||||
{
|
||||
T1 = PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T2_im(void)
|
||||
{
|
||||
T2 = PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_addl_T1_im(void)
|
||||
{
|
||||
T1 += PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_addl_T1_T2(void)
|
||||
{
|
||||
T1 += T2;
|
||||
}
|
||||
|
||||
void OPPROTO op_subl_T1_T2(void)
|
||||
{
|
||||
T1 -= T2;
|
||||
}
|
||||
|
||||
void OPPROTO op_addl_T0_T1(void)
|
||||
{
|
||||
T0 += T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_addl_T0_T1_cc(void)
|
||||
{
|
||||
unsigned int src1;
|
||||
src1 = T0;
|
||||
T0 += T1;
|
||||
env->NZF = T0;
|
||||
env->CF = T0 < src1;
|
||||
env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_adcl_T0_T1(void)
|
||||
{
|
||||
T0 += T1 + env->CF;
|
||||
}
|
||||
|
||||
void OPPROTO op_adcl_T0_T1_cc(void)
|
||||
{
|
||||
unsigned int src1;
|
||||
src1 = T0;
|
||||
if (!env->CF) {
|
||||
T0 += T1;
|
||||
env->CF = T0 < src1;
|
||||
} else {
|
||||
T0 += T1 + 1;
|
||||
env->CF = T0 <= src1;
|
||||
}
|
||||
env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0);
|
||||
env->NZF = T0;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
#define OPSUB(sub, sbc, T0, T1) \
|
||||
\
|
||||
void OPPROTO op_ ## sub ## l_T0_T1(void) \
|
||||
{ \
|
||||
T0 -= T1; \
|
||||
} \
|
||||
\
|
||||
void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \
|
||||
{ \
|
||||
unsigned int src1; \
|
||||
src1 = T0; \
|
||||
T0 -= T1; \
|
||||
env->NZF = T0; \
|
||||
env->CF = src1 < T1; \
|
||||
env->VF = (src1 ^ T1) & (src1 ^ T0); \
|
||||
} \
|
||||
\
|
||||
void OPPROTO op_ ## sbc ## l_T0_T1(void) \
|
||||
{ \
|
||||
T0 = T0 - T1 + env->CF - 1; \
|
||||
} \
|
||||
\
|
||||
void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \
|
||||
{ \
|
||||
unsigned int src1; \
|
||||
src1 = T0; \
|
||||
if (!env->CF) { \
|
||||
T0 = T0 - T1 - 1; \
|
||||
T0 += T1; \
|
||||
env->CF = src1 < T1; \
|
||||
} else { \
|
||||
T0 = T0 - T1; \
|
||||
env->CF = src1 <= T1; \
|
||||
} \
|
||||
env->VF = (src1 ^ T1) & (src1 ^ T0); \
|
||||
env->NZF = T0; \
|
||||
FORCE_RET(); \
|
||||
}
|
||||
|
||||
OPSUB(sub, sbc, T0, T1)
|
||||
|
||||
OPSUB(rsb, rsc, T1, T0)
|
||||
|
||||
void OPPROTO op_andl_T0_T1(void)
|
||||
{
|
||||
T0 &= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_xorl_T0_T1(void)
|
||||
{
|
||||
T0 ^= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_orl_T0_T1(void)
|
||||
{
|
||||
T0 |= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_bicl_T0_T1(void)
|
||||
{
|
||||
T0 &= ~T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_notl_T1(void)
|
||||
{
|
||||
T1 = ~T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_logic_cc(void)
|
||||
{
|
||||
env->NZF = T0;
|
||||
}
|
||||
|
||||
#define EIP (env->regs[15])
|
||||
|
||||
void OPPROTO op_test_eq(void)
|
||||
{
|
||||
if (env->NZF == 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_ne(void)
|
||||
{
|
||||
if (env->NZF != 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_cs(void)
|
||||
{
|
||||
if (env->CF != 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_cc(void)
|
||||
{
|
||||
if (env->CF == 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_mi(void)
|
||||
{
|
||||
if ((env->NZF & 0x80000000) != 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_pl(void)
|
||||
{
|
||||
if ((env->NZF & 0x80000000) == 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_vs(void)
|
||||
{
|
||||
if ((env->VF & 0x80000000) != 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_vc(void)
|
||||
{
|
||||
if ((env->VF & 0x80000000) == 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_hi(void)
|
||||
{
|
||||
if (env->CF != 0 && env->NZF != 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_ls(void)
|
||||
{
|
||||
if (env->CF == 0 || env->NZF == 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_ge(void)
|
||||
{
|
||||
if (((env->VF ^ env->NZF) & 0x80000000) == 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_lt(void)
|
||||
{
|
||||
if (((env->VF ^ env->NZF) & 0x80000000) != 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_gt(void)
|
||||
{
|
||||
if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_le(void)
|
||||
{
|
||||
if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_jmp(void)
|
||||
{
|
||||
JUMP_TB(PARAM1, 1, PARAM2);
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T0_psr(void)
|
||||
{
|
||||
int ZF;
|
||||
ZF = (env->NZF == 0);
|
||||
T0 = env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) |
|
||||
(env->CF << 29) | ((env->VF & 0x80000000) >> 3);
|
||||
}
|
||||
|
||||
/* NOTE: N = 1 and Z = 1 cannot be stored currently */
|
||||
void OPPROTO op_movl_psr_T0(void)
|
||||
{
|
||||
unsigned int psr;
|
||||
psr = T0;
|
||||
env->CF = (psr >> 29) & 1;
|
||||
env->NZF = (psr & 0xc0000000) ^ 0x40000000;
|
||||
env->VF = (psr << 3) & 0x80000000;
|
||||
/* for user mode we do not update other state info */
|
||||
}
|
||||
|
||||
void OPPROTO op_mul_T0_T1(void)
|
||||
{
|
||||
T0 = T0 * T1;
|
||||
}
|
||||
|
||||
/* 64 bit unsigned mul */
|
||||
void OPPROTO op_mull_T0_T1(void)
|
||||
{
|
||||
uint64_t res;
|
||||
res = T0 * T1;
|
||||
T1 = res >> 32;
|
||||
T0 = res;
|
||||
}
|
||||
|
||||
/* 64 bit signed mul */
|
||||
void OPPROTO op_imull_T0_T1(void)
|
||||
{
|
||||
uint64_t res;
|
||||
res = (int32_t)T0 * (int32_t)T1;
|
||||
T1 = res >> 32;
|
||||
T0 = res;
|
||||
}
|
||||
|
||||
void OPPROTO op_addq_T0_T1(void)
|
||||
{
|
||||
uint64_t res;
|
||||
res = ((uint64_t)T1 << 32) | T0;
|
||||
res += ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]);
|
||||
T1 = res >> 32;
|
||||
T0 = res;
|
||||
}
|
||||
|
||||
void OPPROTO op_logicq_cc(void)
|
||||
{
|
||||
env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0);
|
||||
}
|
||||
|
||||
/* memory access */
|
||||
|
||||
void OPPROTO op_ldub_T0_T1(void)
|
||||
{
|
||||
T0 = ldub((void *)T1);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldsb_T0_T1(void)
|
||||
{
|
||||
T0 = ldsb((void *)T1);
|
||||
}
|
||||
|
||||
void OPPROTO op_lduw_T0_T1(void)
|
||||
{
|
||||
T0 = lduw((void *)T1);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldsw_T0_T1(void)
|
||||
{
|
||||
T0 = ldsw((void *)T1);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldl_T0_T1(void)
|
||||
{
|
||||
T0 = ldl((void *)T1);
|
||||
}
|
||||
|
||||
void OPPROTO op_stb_T0_T1(void)
|
||||
{
|
||||
stb((void *)T1, T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_stw_T0_T1(void)
|
||||
{
|
||||
stw((void *)T1, T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_stl_T0_T1(void)
|
||||
{
|
||||
stl((void *)T1, T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_swpb_T0_T1(void)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
cpu_lock();
|
||||
tmp = ldub((void *)T1);
|
||||
stb((void *)T1, T0);
|
||||
T0 = tmp;
|
||||
cpu_unlock();
|
||||
}
|
||||
|
||||
void OPPROTO op_swpl_T0_T1(void)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
cpu_lock();
|
||||
tmp = ldl((void *)T1);
|
||||
stl((void *)T1, T0);
|
||||
T0 = tmp;
|
||||
cpu_unlock();
|
||||
}
|
||||
|
||||
/* shifts */
|
||||
|
||||
/* T1 based */
|
||||
void OPPROTO op_shll_T1_im(void)
|
||||
{
|
||||
T1 = T1 << PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_shrl_T1_im(void)
|
||||
{
|
||||
T1 = (uint32_t)T1 >> PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_sarl_T1_im(void)
|
||||
{
|
||||
T1 = (int32_t)T1 >> PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_rorl_T1_im(void)
|
||||
{
|
||||
int shift;
|
||||
shift = PARAM1;
|
||||
T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
|
||||
}
|
||||
|
||||
/* T1 based, set C flag */
|
||||
void OPPROTO op_shll_T1_im_cc(void)
|
||||
{
|
||||
env->CF = (T1 >> (32 - PARAM1)) & 1;
|
||||
T1 = T1 << PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_shrl_T1_im_cc(void)
|
||||
{
|
||||
env->CF = (T1 >> (PARAM1 - 1)) & 1;
|
||||
T1 = (uint32_t)T1 >> PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_sarl_T1_im_cc(void)
|
||||
{
|
||||
env->CF = (T1 >> (PARAM1 - 1)) & 1;
|
||||
T1 = (int32_t)T1 >> PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_rorl_T1_im_cc(void)
|
||||
{
|
||||
int shift;
|
||||
shift = PARAM1;
|
||||
env->CF = (T1 >> (shift - 1)) & 1;
|
||||
T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
|
||||
}
|
||||
|
||||
/* T2 based */
|
||||
void OPPROTO op_shll_T2_im(void)
|
||||
{
|
||||
T2 = T2 << PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_shrl_T2_im(void)
|
||||
{
|
||||
T2 = (uint32_t)T2 >> PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_sarl_T2_im(void)
|
||||
{
|
||||
T2 = (int32_t)T2 >> PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_rorl_T2_im(void)
|
||||
{
|
||||
int shift;
|
||||
shift = PARAM1;
|
||||
T2 = ((uint32_t)T2 >> shift) | (T2 << (32 - shift));
|
||||
}
|
||||
|
||||
/* T1 based, use T0 as shift count */
|
||||
|
||||
void OPPROTO op_shll_T1_T0(void)
|
||||
{
|
||||
int shift;
|
||||
shift = T0 & 0xff;
|
||||
if (shift >= 32)
|
||||
T1 = 0;
|
||||
else
|
||||
T1 = T1 << shift;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_shrl_T1_T0(void)
|
||||
{
|
||||
int shift;
|
||||
shift = T0 & 0xff;
|
||||
if (shift >= 32)
|
||||
T1 = 0;
|
||||
else
|
||||
T1 = (uint32_t)T1 >> shift;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_sarl_T1_T0(void)
|
||||
{
|
||||
int shift;
|
||||
shift = T0 & 0xff;
|
||||
if (shift >= 32)
|
||||
shift = 31;
|
||||
T1 = (int32_t)T1 >> shift;
|
||||
}
|
||||
|
||||
void OPPROTO op_rorl_T1_T0(void)
|
||||
{
|
||||
int shift;
|
||||
shift = T0 & 0x1f;
|
||||
if (shift) {
|
||||
T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
/* T1 based, use T0 as shift count and compute CF */
|
||||
|
||||
void OPPROTO op_shll_T1_T0_cc(void)
|
||||
{
|
||||
int shift;
|
||||
shift = T0 & 0xff;
|
||||
if (shift >= 32) {
|
||||
if (shift == 32)
|
||||
env->CF = T1 & 1;
|
||||
else
|
||||
env->CF = 0;
|
||||
T1 = 0;
|
||||
} else if (shift != 0) {
|
||||
env->CF = (T1 >> (32 - shift)) & 1;
|
||||
T1 = T1 << shift;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_shrl_T1_T0_cc(void)
|
||||
{
|
||||
int shift;
|
||||
shift = T0 & 0xff;
|
||||
if (shift >= 32) {
|
||||
if (shift == 32)
|
||||
env->CF = (T1 >> 31) & 1;
|
||||
else
|
||||
env->CF = 0;
|
||||
T1 = 0;
|
||||
} else if (shift != 0) {
|
||||
env->CF = (T1 >> (shift - 1)) & 1;
|
||||
T1 = (uint32_t)T1 >> shift;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_sarl_T1_T0_cc(void)
|
||||
{
|
||||
int shift;
|
||||
shift = T0 & 0xff;
|
||||
if (shift >= 32) {
|
||||
env->CF = (T1 >> 31) & 1;
|
||||
T1 = (int32_t)T1 >> 31;
|
||||
} else {
|
||||
env->CF = (T1 >> (shift - 1)) & 1;
|
||||
T1 = (int32_t)T1 >> shift;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_rorl_T1_T0_cc(void)
|
||||
{
|
||||
int shift1, shift;
|
||||
shift1 = T0 & 0xff;
|
||||
shift = shift1 & 0x1f;
|
||||
if (shift == 0) {
|
||||
if (shift1 != 0)
|
||||
env->CF = (T1 >> 31) & 1;
|
||||
} else {
|
||||
env->CF = (T1 >> (shift - 1)) & 1;
|
||||
T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
/* exceptions */
|
||||
|
||||
void OPPROTO op_swi(void)
|
||||
{
|
||||
env->exception_index = EXCP_SWI;
|
||||
cpu_loop_exit();
|
||||
}
|
||||
|
||||
void OPPROTO op_undef_insn(void)
|
||||
{
|
||||
env->exception_index = EXCP_UDEF;
|
||||
cpu_loop_exit();
|
||||
}
|
||||
|
||||
/* thread support */
|
||||
|
||||
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
void cpu_lock(void)
|
||||
{
|
||||
spin_lock(&global_cpu_lock);
|
||||
}
|
||||
|
||||
void cpu_unlock(void)
|
||||
{
|
||||
spin_unlock(&global_cpu_lock);
|
||||
}
|
||||
|
||||
+10
-11
@@ -2,7 +2,6 @@
|
||||
void OPPROTO glue(glue(op_movs, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, inc;
|
||||
inc = (DF << SHIFT);
|
||||
v = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
glue(st, SUFFIX)(DI_ADDR, v);
|
||||
inc = (DF << SHIFT);
|
||||
@@ -86,7 +85,7 @@ void OPPROTO glue(glue(op_scas, SUFFIX), STRING_SUFFIX)(void)
|
||||
v = glue(ldu, SUFFIX)(DI_ADDR);
|
||||
inc = (DF << SHIFT);
|
||||
INC_DI();
|
||||
CC_SRC = EAX;
|
||||
CC_SRC = v;
|
||||
CC_DST = EAX - v;
|
||||
}
|
||||
|
||||
@@ -105,7 +104,7 @@ void OPPROTO glue(glue(op_repz_scas, SUFFIX), STRING_SUFFIX)(void)
|
||||
if (v1 != v2)
|
||||
break;
|
||||
} while (CX != 0);
|
||||
CC_SRC = v1;
|
||||
CC_SRC = v2;
|
||||
CC_DST = v1 - v2;
|
||||
CC_OP = CC_OP_SUBB + SHIFT;
|
||||
}
|
||||
@@ -127,7 +126,7 @@ void OPPROTO glue(glue(op_repnz_scas, SUFFIX), STRING_SUFFIX)(void)
|
||||
if (v1 == v2)
|
||||
break;
|
||||
} while (CX != 0);
|
||||
CC_SRC = v1;
|
||||
CC_SRC = v2;
|
||||
CC_DST = v1 - v2;
|
||||
CC_OP = CC_OP_SUBB + SHIFT;
|
||||
}
|
||||
@@ -142,7 +141,7 @@ void OPPROTO glue(glue(op_cmps, SUFFIX), STRING_SUFFIX)(void)
|
||||
inc = (DF << SHIFT);
|
||||
INC_SI();
|
||||
INC_DI();
|
||||
CC_SRC = v1;
|
||||
CC_SRC = v2;
|
||||
CC_DST = v1 - v2;
|
||||
}
|
||||
|
||||
@@ -160,7 +159,7 @@ void OPPROTO glue(glue(op_repz_cmps, SUFFIX), STRING_SUFFIX)(void)
|
||||
if (v1 != v2)
|
||||
break;
|
||||
} while (CX != 0);
|
||||
CC_SRC = v1;
|
||||
CC_SRC = v2;
|
||||
CC_DST = v1 - v2;
|
||||
CC_OP = CC_OP_SUBB + SHIFT;
|
||||
}
|
||||
@@ -181,7 +180,7 @@ void OPPROTO glue(glue(op_repnz_cmps, SUFFIX), STRING_SUFFIX)(void)
|
||||
if (v1 == v2)
|
||||
break;
|
||||
} while (CX != 0);
|
||||
CC_SRC = v1;
|
||||
CC_SRC = v2;
|
||||
CC_DST = v1 - v2;
|
||||
CC_OP = CC_OP_SUBB + SHIFT;
|
||||
}
|
||||
@@ -193,7 +192,7 @@ void OPPROTO glue(glue(op_outs, SUFFIX), STRING_SUFFIX)(void)
|
||||
int v, dx, inc;
|
||||
dx = EDX & 0xffff;
|
||||
v = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
glue(cpu_x86_out, SUFFIX)(dx, v);
|
||||
glue(cpu_x86_out, SUFFIX)(env, dx, v);
|
||||
inc = (DF << SHIFT);
|
||||
INC_SI();
|
||||
}
|
||||
@@ -205,7 +204,7 @@ void OPPROTO glue(glue(op_rep_outs, SUFFIX), STRING_SUFFIX)(void)
|
||||
dx = EDX & 0xffff;
|
||||
while (CX != 0) {
|
||||
v = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
glue(cpu_x86_out, SUFFIX)(dx, v);
|
||||
glue(cpu_x86_out, SUFFIX)(env, dx, v);
|
||||
INC_SI();
|
||||
DEC_CX();
|
||||
}
|
||||
@@ -216,7 +215,7 @@ void OPPROTO glue(glue(op_ins, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, dx, inc;
|
||||
dx = EDX & 0xffff;
|
||||
v = glue(cpu_x86_in, SUFFIX)(dx);
|
||||
v = glue(cpu_x86_in, SUFFIX)(env, dx);
|
||||
glue(st, SUFFIX)(DI_ADDR, v);
|
||||
inc = (DF << SHIFT);
|
||||
INC_DI();
|
||||
@@ -228,7 +227,7 @@ void OPPROTO glue(glue(op_rep_ins, SUFFIX), STRING_SUFFIX)(void)
|
||||
inc = (DF << SHIFT);
|
||||
dx = EDX & 0xffff;
|
||||
while (CX != 0) {
|
||||
v = glue(cpu_x86_in, SUFFIX)(dx);
|
||||
v = glue(cpu_x86_in, SUFFIX)(env, dx);
|
||||
glue(st, SUFFIX)(DI_ADDR, v);
|
||||
INC_DI();
|
||||
DEC_CX();
|
||||
|
||||
-644
@@ -1,644 +0,0 @@
|
||||
DEF(end, 0)
|
||||
DEF(movl_A0_EAX, 0)
|
||||
DEF(addl_A0_EAX, 0)
|
||||
DEF(addl_A0_EAX_s1, 0)
|
||||
DEF(addl_A0_EAX_s2, 0)
|
||||
DEF(addl_A0_EAX_s3, 0)
|
||||
DEF(movl_T0_EAX, 0)
|
||||
DEF(movl_T1_EAX, 0)
|
||||
DEF(movh_T0_EAX, 0)
|
||||
DEF(movh_T1_EAX, 0)
|
||||
DEF(movl_EAX_T0, 0)
|
||||
DEF(movl_EAX_T1, 0)
|
||||
DEF(movl_EAX_A0, 0)
|
||||
DEF(cmovw_EAX_T1_T0, 0)
|
||||
DEF(cmovl_EAX_T1_T0, 0)
|
||||
DEF(movw_EAX_T0, 0)
|
||||
DEF(movw_EAX_T1, 0)
|
||||
DEF(movw_EAX_A0, 0)
|
||||
DEF(movb_EAX_T0, 0)
|
||||
DEF(movh_EAX_T0, 0)
|
||||
DEF(movb_EAX_T1, 0)
|
||||
DEF(movh_EAX_T1, 0)
|
||||
DEF(movl_A0_ECX, 0)
|
||||
DEF(addl_A0_ECX, 0)
|
||||
DEF(addl_A0_ECX_s1, 0)
|
||||
DEF(addl_A0_ECX_s2, 0)
|
||||
DEF(addl_A0_ECX_s3, 0)
|
||||
DEF(movl_T0_ECX, 0)
|
||||
DEF(movl_T1_ECX, 0)
|
||||
DEF(movh_T0_ECX, 0)
|
||||
DEF(movh_T1_ECX, 0)
|
||||
DEF(movl_ECX_T0, 0)
|
||||
DEF(movl_ECX_T1, 0)
|
||||
DEF(movl_ECX_A0, 0)
|
||||
DEF(cmovw_ECX_T1_T0, 0)
|
||||
DEF(cmovl_ECX_T1_T0, 0)
|
||||
DEF(movw_ECX_T0, 0)
|
||||
DEF(movw_ECX_T1, 0)
|
||||
DEF(movw_ECX_A0, 0)
|
||||
DEF(movb_ECX_T0, 0)
|
||||
DEF(movh_ECX_T0, 0)
|
||||
DEF(movb_ECX_T1, 0)
|
||||
DEF(movh_ECX_T1, 0)
|
||||
DEF(movl_A0_EDX, 0)
|
||||
DEF(addl_A0_EDX, 0)
|
||||
DEF(addl_A0_EDX_s1, 0)
|
||||
DEF(addl_A0_EDX_s2, 0)
|
||||
DEF(addl_A0_EDX_s3, 0)
|
||||
DEF(movl_T0_EDX, 0)
|
||||
DEF(movl_T1_EDX, 0)
|
||||
DEF(movh_T0_EDX, 0)
|
||||
DEF(movh_T1_EDX, 0)
|
||||
DEF(movl_EDX_T0, 0)
|
||||
DEF(movl_EDX_T1, 0)
|
||||
DEF(movl_EDX_A0, 0)
|
||||
DEF(cmovw_EDX_T1_T0, 0)
|
||||
DEF(cmovl_EDX_T1_T0, 0)
|
||||
DEF(movw_EDX_T0, 0)
|
||||
DEF(movw_EDX_T1, 0)
|
||||
DEF(movw_EDX_A0, 0)
|
||||
DEF(movb_EDX_T0, 0)
|
||||
DEF(movh_EDX_T0, 0)
|
||||
DEF(movb_EDX_T1, 0)
|
||||
DEF(movh_EDX_T1, 0)
|
||||
DEF(movl_A0_EBX, 0)
|
||||
DEF(addl_A0_EBX, 0)
|
||||
DEF(addl_A0_EBX_s1, 0)
|
||||
DEF(addl_A0_EBX_s2, 0)
|
||||
DEF(addl_A0_EBX_s3, 0)
|
||||
DEF(movl_T0_EBX, 0)
|
||||
DEF(movl_T1_EBX, 0)
|
||||
DEF(movh_T0_EBX, 0)
|
||||
DEF(movh_T1_EBX, 0)
|
||||
DEF(movl_EBX_T0, 0)
|
||||
DEF(movl_EBX_T1, 0)
|
||||
DEF(movl_EBX_A0, 0)
|
||||
DEF(cmovw_EBX_T1_T0, 0)
|
||||
DEF(cmovl_EBX_T1_T0, 0)
|
||||
DEF(movw_EBX_T0, 0)
|
||||
DEF(movw_EBX_T1, 0)
|
||||
DEF(movw_EBX_A0, 0)
|
||||
DEF(movb_EBX_T0, 0)
|
||||
DEF(movh_EBX_T0, 0)
|
||||
DEF(movb_EBX_T1, 0)
|
||||
DEF(movh_EBX_T1, 0)
|
||||
DEF(movl_A0_ESP, 0)
|
||||
DEF(addl_A0_ESP, 0)
|
||||
DEF(addl_A0_ESP_s1, 0)
|
||||
DEF(addl_A0_ESP_s2, 0)
|
||||
DEF(addl_A0_ESP_s3, 0)
|
||||
DEF(movl_T0_ESP, 0)
|
||||
DEF(movl_T1_ESP, 0)
|
||||
DEF(movh_T0_ESP, 0)
|
||||
DEF(movh_T1_ESP, 0)
|
||||
DEF(movl_ESP_T0, 0)
|
||||
DEF(movl_ESP_T1, 0)
|
||||
DEF(movl_ESP_A0, 0)
|
||||
DEF(cmovw_ESP_T1_T0, 0)
|
||||
DEF(cmovl_ESP_T1_T0, 0)
|
||||
DEF(movw_ESP_T0, 0)
|
||||
DEF(movw_ESP_T1, 0)
|
||||
DEF(movw_ESP_A0, 0)
|
||||
DEF(movb_ESP_T0, 0)
|
||||
DEF(movh_ESP_T0, 0)
|
||||
DEF(movb_ESP_T1, 0)
|
||||
DEF(movh_ESP_T1, 0)
|
||||
DEF(movl_A0_EBP, 0)
|
||||
DEF(addl_A0_EBP, 0)
|
||||
DEF(addl_A0_EBP_s1, 0)
|
||||
DEF(addl_A0_EBP_s2, 0)
|
||||
DEF(addl_A0_EBP_s3, 0)
|
||||
DEF(movl_T0_EBP, 0)
|
||||
DEF(movl_T1_EBP, 0)
|
||||
DEF(movh_T0_EBP, 0)
|
||||
DEF(movh_T1_EBP, 0)
|
||||
DEF(movl_EBP_T0, 0)
|
||||
DEF(movl_EBP_T1, 0)
|
||||
DEF(movl_EBP_A0, 0)
|
||||
DEF(cmovw_EBP_T1_T0, 0)
|
||||
DEF(cmovl_EBP_T1_T0, 0)
|
||||
DEF(movw_EBP_T0, 0)
|
||||
DEF(movw_EBP_T1, 0)
|
||||
DEF(movw_EBP_A0, 0)
|
||||
DEF(movb_EBP_T0, 0)
|
||||
DEF(movh_EBP_T0, 0)
|
||||
DEF(movb_EBP_T1, 0)
|
||||
DEF(movh_EBP_T1, 0)
|
||||
DEF(movl_A0_ESI, 0)
|
||||
DEF(addl_A0_ESI, 0)
|
||||
DEF(addl_A0_ESI_s1, 0)
|
||||
DEF(addl_A0_ESI_s2, 0)
|
||||
DEF(addl_A0_ESI_s3, 0)
|
||||
DEF(movl_T0_ESI, 0)
|
||||
DEF(movl_T1_ESI, 0)
|
||||
DEF(movh_T0_ESI, 0)
|
||||
DEF(movh_T1_ESI, 0)
|
||||
DEF(movl_ESI_T0, 0)
|
||||
DEF(movl_ESI_T1, 0)
|
||||
DEF(movl_ESI_A0, 0)
|
||||
DEF(cmovw_ESI_T1_T0, 0)
|
||||
DEF(cmovl_ESI_T1_T0, 0)
|
||||
DEF(movw_ESI_T0, 0)
|
||||
DEF(movw_ESI_T1, 0)
|
||||
DEF(movw_ESI_A0, 0)
|
||||
DEF(movb_ESI_T0, 0)
|
||||
DEF(movh_ESI_T0, 0)
|
||||
DEF(movb_ESI_T1, 0)
|
||||
DEF(movh_ESI_T1, 0)
|
||||
DEF(movl_A0_EDI, 0)
|
||||
DEF(addl_A0_EDI, 0)
|
||||
DEF(addl_A0_EDI_s1, 0)
|
||||
DEF(addl_A0_EDI_s2, 0)
|
||||
DEF(addl_A0_EDI_s3, 0)
|
||||
DEF(movl_T0_EDI, 0)
|
||||
DEF(movl_T1_EDI, 0)
|
||||
DEF(movh_T0_EDI, 0)
|
||||
DEF(movh_T1_EDI, 0)
|
||||
DEF(movl_EDI_T0, 0)
|
||||
DEF(movl_EDI_T1, 0)
|
||||
DEF(movl_EDI_A0, 0)
|
||||
DEF(cmovw_EDI_T1_T0, 0)
|
||||
DEF(cmovl_EDI_T1_T0, 0)
|
||||
DEF(movw_EDI_T0, 0)
|
||||
DEF(movw_EDI_T1, 0)
|
||||
DEF(movw_EDI_A0, 0)
|
||||
DEF(movb_EDI_T0, 0)
|
||||
DEF(movh_EDI_T0, 0)
|
||||
DEF(movb_EDI_T1, 0)
|
||||
DEF(movh_EDI_T1, 0)
|
||||
DEF(addl_T0_T1_cc, 0)
|
||||
DEF(orl_T0_T1_cc, 0)
|
||||
DEF(andl_T0_T1_cc, 0)
|
||||
DEF(subl_T0_T1_cc, 0)
|
||||
DEF(xorl_T0_T1_cc, 0)
|
||||
DEF(cmpl_T0_T1_cc, 0)
|
||||
DEF(negl_T0_cc, 0)
|
||||
DEF(incl_T0_cc, 0)
|
||||
DEF(decl_T0_cc, 0)
|
||||
DEF(testl_T0_T1_cc, 0)
|
||||
DEF(addl_T0_T1, 0)
|
||||
DEF(orl_T0_T1, 0)
|
||||
DEF(andl_T0_T1, 0)
|
||||
DEF(subl_T0_T1, 0)
|
||||
DEF(xorl_T0_T1, 0)
|
||||
DEF(negl_T0, 0)
|
||||
DEF(incl_T0, 0)
|
||||
DEF(decl_T0, 0)
|
||||
DEF(notl_T0, 0)
|
||||
DEF(bswapl_T0, 0)
|
||||
DEF(mulb_AL_T0, 0)
|
||||
DEF(imulb_AL_T0, 0)
|
||||
DEF(mulw_AX_T0, 0)
|
||||
DEF(imulw_AX_T0, 0)
|
||||
DEF(mull_EAX_T0, 0)
|
||||
DEF(imull_EAX_T0, 0)
|
||||
DEF(imulw_T0_T1, 0)
|
||||
DEF(imull_T0_T1, 0)
|
||||
DEF(divb_AL_T0, 0)
|
||||
DEF(idivb_AL_T0, 0)
|
||||
DEF(divw_AX_T0, 0)
|
||||
DEF(idivw_AX_T0, 0)
|
||||
DEF(divl_EAX_T0, 0)
|
||||
DEF(idivl_EAX_T0, 0)
|
||||
DEF(movl_T0_im, 1)
|
||||
DEF(addl_T0_im, 1)
|
||||
DEF(andl_T0_ffff, 0)
|
||||
DEF(movl_T0_T1, 0)
|
||||
DEF(movl_T1_im, 1)
|
||||
DEF(addl_T1_im, 1)
|
||||
DEF(movl_T1_A0, 0)
|
||||
DEF(movl_A0_im, 1)
|
||||
DEF(addl_A0_im, 1)
|
||||
DEF(addl_A0_AL, 0)
|
||||
DEF(andl_A0_ffff, 0)
|
||||
DEF(ldub_T0_A0, 0)
|
||||
DEF(ldsb_T0_A0, 0)
|
||||
DEF(lduw_T0_A0, 0)
|
||||
DEF(ldsw_T0_A0, 0)
|
||||
DEF(ldl_T0_A0, 0)
|
||||
DEF(ldub_T1_A0, 0)
|
||||
DEF(ldsb_T1_A0, 0)
|
||||
DEF(lduw_T1_A0, 0)
|
||||
DEF(ldsw_T1_A0, 0)
|
||||
DEF(ldl_T1_A0, 0)
|
||||
DEF(stb_T0_A0, 0)
|
||||
DEF(stw_T0_A0, 0)
|
||||
DEF(stl_T0_A0, 0)
|
||||
DEF(add_bitw_A0_T1, 0)
|
||||
DEF(add_bitl_A0_T1, 0)
|
||||
DEF(jmp_T0, 0)
|
||||
DEF(jmp_im, 1)
|
||||
DEF(int_im, 1)
|
||||
DEF(int3, 1)
|
||||
DEF(into, 0)
|
||||
DEF(cli, 0)
|
||||
DEF(sti, 0)
|
||||
DEF(cli_vm, 0)
|
||||
DEF(sti_vm, 1)
|
||||
DEF(boundw, 0)
|
||||
DEF(boundl, 0)
|
||||
DEF(cmpxchg8b, 0)
|
||||
DEF(jb_subb, 2)
|
||||
DEF(jz_subb, 2)
|
||||
DEF(jbe_subb, 2)
|
||||
DEF(js_subb, 2)
|
||||
DEF(jl_subb, 2)
|
||||
DEF(jle_subb, 2)
|
||||
DEF(setb_T0_subb, 0)
|
||||
DEF(setz_T0_subb, 0)
|
||||
DEF(setbe_T0_subb, 0)
|
||||
DEF(sets_T0_subb, 0)
|
||||
DEF(setl_T0_subb, 0)
|
||||
DEF(setle_T0_subb, 0)
|
||||
DEF(rolb_T0_T1_cc, 0)
|
||||
DEF(rolb_T0_T1, 0)
|
||||
DEF(rorb_T0_T1_cc, 0)
|
||||
DEF(rorb_T0_T1, 0)
|
||||
DEF(rclb_T0_T1_cc, 0)
|
||||
DEF(rcrb_T0_T1_cc, 0)
|
||||
DEF(shlb_T0_T1_cc, 0)
|
||||
DEF(shlb_T0_T1, 0)
|
||||
DEF(shrb_T0_T1_cc, 0)
|
||||
DEF(shrb_T0_T1, 0)
|
||||
DEF(sarb_T0_T1_cc, 0)
|
||||
DEF(sarb_T0_T1, 0)
|
||||
DEF(adcb_T0_T1_cc, 0)
|
||||
DEF(sbbb_T0_T1_cc, 0)
|
||||
DEF(cmpxchgb_T0_T1_EAX_cc, 0)
|
||||
DEF(movsb_fast, 0)
|
||||
DEF(rep_movsb_fast, 0)
|
||||
DEF(stosb_fast, 0)
|
||||
DEF(rep_stosb_fast, 0)
|
||||
DEF(lodsb_fast, 0)
|
||||
DEF(rep_lodsb_fast, 0)
|
||||
DEF(scasb_fast, 0)
|
||||
DEF(repz_scasb_fast, 0)
|
||||
DEF(repnz_scasb_fast, 0)
|
||||
DEF(cmpsb_fast, 0)
|
||||
DEF(repz_cmpsb_fast, 0)
|
||||
DEF(repnz_cmpsb_fast, 0)
|
||||
DEF(outsb_fast, 0)
|
||||
DEF(rep_outsb_fast, 0)
|
||||
DEF(insb_fast, 0)
|
||||
DEF(rep_insb_fast, 0)
|
||||
DEF(movsb_a32, 0)
|
||||
DEF(rep_movsb_a32, 0)
|
||||
DEF(stosb_a32, 0)
|
||||
DEF(rep_stosb_a32, 0)
|
||||
DEF(lodsb_a32, 0)
|
||||
DEF(rep_lodsb_a32, 0)
|
||||
DEF(scasb_a32, 0)
|
||||
DEF(repz_scasb_a32, 0)
|
||||
DEF(repnz_scasb_a32, 0)
|
||||
DEF(cmpsb_a32, 0)
|
||||
DEF(repz_cmpsb_a32, 0)
|
||||
DEF(repnz_cmpsb_a32, 0)
|
||||
DEF(outsb_a32, 0)
|
||||
DEF(rep_outsb_a32, 0)
|
||||
DEF(insb_a32, 0)
|
||||
DEF(rep_insb_a32, 0)
|
||||
DEF(movsb_a16, 0)
|
||||
DEF(rep_movsb_a16, 0)
|
||||
DEF(stosb_a16, 0)
|
||||
DEF(rep_stosb_a16, 0)
|
||||
DEF(lodsb_a16, 0)
|
||||
DEF(rep_lodsb_a16, 0)
|
||||
DEF(scasb_a16, 0)
|
||||
DEF(repz_scasb_a16, 0)
|
||||
DEF(repnz_scasb_a16, 0)
|
||||
DEF(cmpsb_a16, 0)
|
||||
DEF(repz_cmpsb_a16, 0)
|
||||
DEF(repnz_cmpsb_a16, 0)
|
||||
DEF(outsb_a16, 0)
|
||||
DEF(rep_outsb_a16, 0)
|
||||
DEF(insb_a16, 0)
|
||||
DEF(rep_insb_a16, 0)
|
||||
DEF(outb_T0_T1, 0)
|
||||
DEF(inb_T0_T1, 0)
|
||||
DEF(jb_subw, 2)
|
||||
DEF(jz_subw, 2)
|
||||
DEF(jbe_subw, 2)
|
||||
DEF(js_subw, 2)
|
||||
DEF(jl_subw, 2)
|
||||
DEF(jle_subw, 2)
|
||||
DEF(loopnzw, 2)
|
||||
DEF(loopzw, 2)
|
||||
DEF(loopw, 2)
|
||||
DEF(jecxzw, 2)
|
||||
DEF(setb_T0_subw, 0)
|
||||
DEF(setz_T0_subw, 0)
|
||||
DEF(setbe_T0_subw, 0)
|
||||
DEF(sets_T0_subw, 0)
|
||||
DEF(setl_T0_subw, 0)
|
||||
DEF(setle_T0_subw, 0)
|
||||
DEF(rolw_T0_T1_cc, 0)
|
||||
DEF(rolw_T0_T1, 0)
|
||||
DEF(rorw_T0_T1_cc, 0)
|
||||
DEF(rorw_T0_T1, 0)
|
||||
DEF(rclw_T0_T1_cc, 0)
|
||||
DEF(rcrw_T0_T1_cc, 0)
|
||||
DEF(shlw_T0_T1_cc, 0)
|
||||
DEF(shlw_T0_T1, 0)
|
||||
DEF(shrw_T0_T1_cc, 0)
|
||||
DEF(shrw_T0_T1, 0)
|
||||
DEF(sarw_T0_T1_cc, 0)
|
||||
DEF(sarw_T0_T1, 0)
|
||||
DEF(shldw_T0_T1_im_cc, 1)
|
||||
DEF(shldw_T0_T1_ECX_cc, 0)
|
||||
DEF(shrdw_T0_T1_im_cc, 1)
|
||||
DEF(shrdw_T0_T1_ECX_cc, 0)
|
||||
DEF(adcw_T0_T1_cc, 0)
|
||||
DEF(sbbw_T0_T1_cc, 0)
|
||||
DEF(cmpxchgw_T0_T1_EAX_cc, 0)
|
||||
DEF(btw_T0_T1_cc, 0)
|
||||
DEF(btsw_T0_T1_cc, 0)
|
||||
DEF(btrw_T0_T1_cc, 0)
|
||||
DEF(btcw_T0_T1_cc, 0)
|
||||
DEF(bsfw_T0_cc, 0)
|
||||
DEF(bsrw_T0_cc, 0)
|
||||
DEF(movsw_fast, 0)
|
||||
DEF(rep_movsw_fast, 0)
|
||||
DEF(stosw_fast, 0)
|
||||
DEF(rep_stosw_fast, 0)
|
||||
DEF(lodsw_fast, 0)
|
||||
DEF(rep_lodsw_fast, 0)
|
||||
DEF(scasw_fast, 0)
|
||||
DEF(repz_scasw_fast, 0)
|
||||
DEF(repnz_scasw_fast, 0)
|
||||
DEF(cmpsw_fast, 0)
|
||||
DEF(repz_cmpsw_fast, 0)
|
||||
DEF(repnz_cmpsw_fast, 0)
|
||||
DEF(outsw_fast, 0)
|
||||
DEF(rep_outsw_fast, 0)
|
||||
DEF(insw_fast, 0)
|
||||
DEF(rep_insw_fast, 0)
|
||||
DEF(movsw_a32, 0)
|
||||
DEF(rep_movsw_a32, 0)
|
||||
DEF(stosw_a32, 0)
|
||||
DEF(rep_stosw_a32, 0)
|
||||
DEF(lodsw_a32, 0)
|
||||
DEF(rep_lodsw_a32, 0)
|
||||
DEF(scasw_a32, 0)
|
||||
DEF(repz_scasw_a32, 0)
|
||||
DEF(repnz_scasw_a32, 0)
|
||||
DEF(cmpsw_a32, 0)
|
||||
DEF(repz_cmpsw_a32, 0)
|
||||
DEF(repnz_cmpsw_a32, 0)
|
||||
DEF(outsw_a32, 0)
|
||||
DEF(rep_outsw_a32, 0)
|
||||
DEF(insw_a32, 0)
|
||||
DEF(rep_insw_a32, 0)
|
||||
DEF(movsw_a16, 0)
|
||||
DEF(rep_movsw_a16, 0)
|
||||
DEF(stosw_a16, 0)
|
||||
DEF(rep_stosw_a16, 0)
|
||||
DEF(lodsw_a16, 0)
|
||||
DEF(rep_lodsw_a16, 0)
|
||||
DEF(scasw_a16, 0)
|
||||
DEF(repz_scasw_a16, 0)
|
||||
DEF(repnz_scasw_a16, 0)
|
||||
DEF(cmpsw_a16, 0)
|
||||
DEF(repz_cmpsw_a16, 0)
|
||||
DEF(repnz_cmpsw_a16, 0)
|
||||
DEF(outsw_a16, 0)
|
||||
DEF(rep_outsw_a16, 0)
|
||||
DEF(insw_a16, 0)
|
||||
DEF(rep_insw_a16, 0)
|
||||
DEF(outw_T0_T1, 0)
|
||||
DEF(inw_T0_T1, 0)
|
||||
DEF(jb_subl, 2)
|
||||
DEF(jz_subl, 2)
|
||||
DEF(jbe_subl, 2)
|
||||
DEF(js_subl, 2)
|
||||
DEF(jl_subl, 2)
|
||||
DEF(jle_subl, 2)
|
||||
DEF(loopnzl, 2)
|
||||
DEF(loopzl, 2)
|
||||
DEF(loopl, 2)
|
||||
DEF(jecxzl, 2)
|
||||
DEF(setb_T0_subl, 0)
|
||||
DEF(setz_T0_subl, 0)
|
||||
DEF(setbe_T0_subl, 0)
|
||||
DEF(sets_T0_subl, 0)
|
||||
DEF(setl_T0_subl, 0)
|
||||
DEF(setle_T0_subl, 0)
|
||||
DEF(roll_T0_T1_cc, 0)
|
||||
DEF(roll_T0_T1, 0)
|
||||
DEF(rorl_T0_T1_cc, 0)
|
||||
DEF(rorl_T0_T1, 0)
|
||||
DEF(rcll_T0_T1_cc, 0)
|
||||
DEF(rcrl_T0_T1_cc, 0)
|
||||
DEF(shll_T0_T1_cc, 0)
|
||||
DEF(shll_T0_T1, 0)
|
||||
DEF(shrl_T0_T1_cc, 0)
|
||||
DEF(shrl_T0_T1, 0)
|
||||
DEF(sarl_T0_T1_cc, 0)
|
||||
DEF(sarl_T0_T1, 0)
|
||||
DEF(shldl_T0_T1_im_cc, 1)
|
||||
DEF(shldl_T0_T1_ECX_cc, 0)
|
||||
DEF(shrdl_T0_T1_im_cc, 1)
|
||||
DEF(shrdl_T0_T1_ECX_cc, 0)
|
||||
DEF(adcl_T0_T1_cc, 0)
|
||||
DEF(sbbl_T0_T1_cc, 0)
|
||||
DEF(cmpxchgl_T0_T1_EAX_cc, 0)
|
||||
DEF(btl_T0_T1_cc, 0)
|
||||
DEF(btsl_T0_T1_cc, 0)
|
||||
DEF(btrl_T0_T1_cc, 0)
|
||||
DEF(btcl_T0_T1_cc, 0)
|
||||
DEF(bsfl_T0_cc, 0)
|
||||
DEF(bsrl_T0_cc, 0)
|
||||
DEF(movsl_fast, 0)
|
||||
DEF(rep_movsl_fast, 0)
|
||||
DEF(stosl_fast, 0)
|
||||
DEF(rep_stosl_fast, 0)
|
||||
DEF(lodsl_fast, 0)
|
||||
DEF(rep_lodsl_fast, 0)
|
||||
DEF(scasl_fast, 0)
|
||||
DEF(repz_scasl_fast, 0)
|
||||
DEF(repnz_scasl_fast, 0)
|
||||
DEF(cmpsl_fast, 0)
|
||||
DEF(repz_cmpsl_fast, 0)
|
||||
DEF(repnz_cmpsl_fast, 0)
|
||||
DEF(outsl_fast, 0)
|
||||
DEF(rep_outsl_fast, 0)
|
||||
DEF(insl_fast, 0)
|
||||
DEF(rep_insl_fast, 0)
|
||||
DEF(movsl_a32, 0)
|
||||
DEF(rep_movsl_a32, 0)
|
||||
DEF(stosl_a32, 0)
|
||||
DEF(rep_stosl_a32, 0)
|
||||
DEF(lodsl_a32, 0)
|
||||
DEF(rep_lodsl_a32, 0)
|
||||
DEF(scasl_a32, 0)
|
||||
DEF(repz_scasl_a32, 0)
|
||||
DEF(repnz_scasl_a32, 0)
|
||||
DEF(cmpsl_a32, 0)
|
||||
DEF(repz_cmpsl_a32, 0)
|
||||
DEF(repnz_cmpsl_a32, 0)
|
||||
DEF(outsl_a32, 0)
|
||||
DEF(rep_outsl_a32, 0)
|
||||
DEF(insl_a32, 0)
|
||||
DEF(rep_insl_a32, 0)
|
||||
DEF(movsl_a16, 0)
|
||||
DEF(rep_movsl_a16, 0)
|
||||
DEF(stosl_a16, 0)
|
||||
DEF(rep_stosl_a16, 0)
|
||||
DEF(lodsl_a16, 0)
|
||||
DEF(rep_lodsl_a16, 0)
|
||||
DEF(scasl_a16, 0)
|
||||
DEF(repz_scasl_a16, 0)
|
||||
DEF(repnz_scasl_a16, 0)
|
||||
DEF(cmpsl_a16, 0)
|
||||
DEF(repz_cmpsl_a16, 0)
|
||||
DEF(repnz_cmpsl_a16, 0)
|
||||
DEF(outsl_a16, 0)
|
||||
DEF(rep_outsl_a16, 0)
|
||||
DEF(insl_a16, 0)
|
||||
DEF(rep_insl_a16, 0)
|
||||
DEF(outl_T0_T1, 0)
|
||||
DEF(inl_T0_T1, 0)
|
||||
DEF(movsbl_T0_T0, 0)
|
||||
DEF(movzbl_T0_T0, 0)
|
||||
DEF(movswl_T0_T0, 0)
|
||||
DEF(movzwl_T0_T0, 0)
|
||||
DEF(movswl_EAX_AX, 0)
|
||||
DEF(movsbw_AX_AL, 0)
|
||||
DEF(movslq_EDX_EAX, 0)
|
||||
DEF(movswl_DX_AX, 0)
|
||||
DEF(pushl_T0, 0)
|
||||
DEF(pushw_T0, 0)
|
||||
DEF(pushl_ss32_T0, 0)
|
||||
DEF(pushw_ss32_T0, 0)
|
||||
DEF(pushl_ss16_T0, 0)
|
||||
DEF(pushw_ss16_T0, 0)
|
||||
DEF(popl_T0, 0)
|
||||
DEF(popw_T0, 0)
|
||||
DEF(popl_ss32_T0, 0)
|
||||
DEF(popw_ss32_T0, 0)
|
||||
DEF(popl_ss16_T0, 0)
|
||||
DEF(popw_ss16_T0, 0)
|
||||
DEF(addl_ESP_4, 0)
|
||||
DEF(addl_ESP_2, 0)
|
||||
DEF(addw_ESP_4, 0)
|
||||
DEF(addw_ESP_2, 0)
|
||||
DEF(addl_ESP_im, 1)
|
||||
DEF(addw_ESP_im, 1)
|
||||
DEF(rdtsc, 0)
|
||||
DEF(cpuid, 0)
|
||||
DEF(aam, 1)
|
||||
DEF(aad, 1)
|
||||
DEF(aaa, 0)
|
||||
DEF(aas, 0)
|
||||
DEF(daa, 0)
|
||||
DEF(das, 0)
|
||||
DEF(movl_seg_T0, 1)
|
||||
DEF(movl_T0_seg, 1)
|
||||
DEF(movl_A0_seg, 1)
|
||||
DEF(addl_A0_seg, 1)
|
||||
DEF(jo_cc, 2)
|
||||
DEF(jb_cc, 2)
|
||||
DEF(jz_cc, 2)
|
||||
DEF(jbe_cc, 2)
|
||||
DEF(js_cc, 2)
|
||||
DEF(jp_cc, 2)
|
||||
DEF(jl_cc, 2)
|
||||
DEF(jle_cc, 2)
|
||||
DEF(seto_T0_cc, 0)
|
||||
DEF(setb_T0_cc, 0)
|
||||
DEF(setz_T0_cc, 0)
|
||||
DEF(setbe_T0_cc, 0)
|
||||
DEF(sets_T0_cc, 0)
|
||||
DEF(setp_T0_cc, 0)
|
||||
DEF(setl_T0_cc, 0)
|
||||
DEF(setle_T0_cc, 0)
|
||||
DEF(xor_T0_1, 0)
|
||||
DEF(set_cc_op, 1)
|
||||
DEF(movl_eflags_T0, 0)
|
||||
DEF(movw_eflags_T0, 0)
|
||||
DEF(movw_eflags_T0_vm, 1)
|
||||
DEF(movl_eflags_T0_vm, 1)
|
||||
DEF(movb_eflags_T0, 0)
|
||||
DEF(movl_T0_eflags, 0)
|
||||
DEF(movl_T0_eflags_vm, 0)
|
||||
DEF(cld, 0)
|
||||
DEF(std, 0)
|
||||
DEF(clc, 0)
|
||||
DEF(stc, 0)
|
||||
DEF(cmc, 0)
|
||||
DEF(salc, 0)
|
||||
DEF(flds_FT0_A0, 0)
|
||||
DEF(fldl_FT0_A0, 0)
|
||||
DEF(fild_FT0_A0, 0)
|
||||
DEF(fildl_FT0_A0, 0)
|
||||
DEF(fildll_FT0_A0, 0)
|
||||
DEF(flds_ST0_A0, 0)
|
||||
DEF(fldl_ST0_A0, 0)
|
||||
DEF(fldt_ST0_A0, 0)
|
||||
DEF(fild_ST0_A0, 0)
|
||||
DEF(fildl_ST0_A0, 0)
|
||||
DEF(fildll_ST0_A0, 0)
|
||||
DEF(fsts_ST0_A0, 0)
|
||||
DEF(fstl_ST0_A0, 0)
|
||||
DEF(fstt_ST0_A0, 0)
|
||||
DEF(fist_ST0_A0, 0)
|
||||
DEF(fistl_ST0_A0, 0)
|
||||
DEF(fistll_ST0_A0, 0)
|
||||
DEF(fbld_ST0_A0, 0)
|
||||
DEF(fbst_ST0_A0, 0)
|
||||
DEF(fpush, 0)
|
||||
DEF(fpop, 0)
|
||||
DEF(fdecstp, 0)
|
||||
DEF(fincstp, 0)
|
||||
DEF(fmov_ST0_FT0, 0)
|
||||
DEF(fmov_FT0_STN, 1)
|
||||
DEF(fmov_ST0_STN, 1)
|
||||
DEF(fmov_STN_ST0, 1)
|
||||
DEF(fxchg_ST0_STN, 1)
|
||||
DEF(fcom_ST0_FT0, 0)
|
||||
DEF(fucom_ST0_FT0, 0)
|
||||
DEF(fadd_ST0_FT0, 0)
|
||||
DEF(fmul_ST0_FT0, 0)
|
||||
DEF(fsub_ST0_FT0, 0)
|
||||
DEF(fsubr_ST0_FT0, 0)
|
||||
DEF(fdiv_ST0_FT0, 0)
|
||||
DEF(fdivr_ST0_FT0, 0)
|
||||
DEF(fadd_STN_ST0, 1)
|
||||
DEF(fmul_STN_ST0, 1)
|
||||
DEF(fsub_STN_ST0, 1)
|
||||
DEF(fsubr_STN_ST0, 1)
|
||||
DEF(fdiv_STN_ST0, 1)
|
||||
DEF(fdivr_STN_ST0, 1)
|
||||
DEF(fchs_ST0, 0)
|
||||
DEF(fabs_ST0, 0)
|
||||
DEF(fxam_ST0, 0)
|
||||
DEF(fld1_ST0, 0)
|
||||
DEF(fldl2t_ST0, 0)
|
||||
DEF(fldl2e_ST0, 0)
|
||||
DEF(fldpi_ST0, 0)
|
||||
DEF(fldlg2_ST0, 0)
|
||||
DEF(fldln2_ST0, 0)
|
||||
DEF(fldz_ST0, 0)
|
||||
DEF(fldz_FT0, 0)
|
||||
DEF(f2xm1, 0)
|
||||
DEF(fyl2x, 0)
|
||||
DEF(fptan, 0)
|
||||
DEF(fpatan, 0)
|
||||
DEF(fxtract, 0)
|
||||
DEF(fprem1, 0)
|
||||
DEF(fprem, 0)
|
||||
DEF(fyl2xp1, 0)
|
||||
DEF(fsqrt, 0)
|
||||
DEF(fsincos, 0)
|
||||
DEF(frndint, 0)
|
||||
DEF(fscale, 0)
|
||||
DEF(fsin, 0)
|
||||
DEF(fcos, 0)
|
||||
DEF(fnstsw_A0, 0)
|
||||
DEF(fnstsw_EAX, 0)
|
||||
DEF(fnstcw_A0, 0)
|
||||
DEF(fldcw_A0, 0)
|
||||
DEF(fclex, 0)
|
||||
DEF(fninit, 0)
|
||||
DEF(lock, 0)
|
||||
DEF(unlock, 0)
|
||||
+60
-352
@@ -93,8 +93,8 @@ static int glue(compute_all_sub, SUFFIX)(void)
|
||||
{
|
||||
int cf, pf, af, zf, sf, of;
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
|
||||
pf = parity_table[(uint8_t)CC_DST];
|
||||
af = (CC_DST ^ src1 ^ src2) & 0x10;
|
||||
@@ -107,8 +107,8 @@ static int glue(compute_all_sub, SUFFIX)(void)
|
||||
static int glue(compute_c_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2, cf;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
|
||||
return cf;
|
||||
}
|
||||
@@ -117,8 +117,8 @@ static int glue(compute_all_sbb, SUFFIX)(void)
|
||||
{
|
||||
int cf, pf, af, zf, sf, of;
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST - 1;
|
||||
src1 = CC_DST + CC_SRC + 1;
|
||||
src2 = CC_SRC;
|
||||
cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
|
||||
pf = parity_table[(uint8_t)CC_DST];
|
||||
af = (CC_DST ^ src1 ^ src2) & 0x10;
|
||||
@@ -131,8 +131,8 @@ static int glue(compute_all_sbb, SUFFIX)(void)
|
||||
static int glue(compute_c_sbb, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2, cf;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST - 1;
|
||||
src1 = CC_DST + CC_SRC + 1;
|
||||
src2 = CC_SRC;
|
||||
cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
|
||||
return cf;
|
||||
}
|
||||
@@ -204,8 +204,13 @@ static int glue(compute_all_shl, SUFFIX)(void)
|
||||
return cf | pf | af | zf | sf | of;
|
||||
}
|
||||
|
||||
#if DATA_BITS == 32
|
||||
static int glue(compute_c_shl, SUFFIX)(void)
|
||||
{
|
||||
return (CC_SRC >> (DATA_BITS - 1)) & CC_C;
|
||||
}
|
||||
|
||||
#if DATA_BITS == 32
|
||||
static int glue(compute_c_sar, SUFFIX)(void)
|
||||
{
|
||||
return CC_SRC & 1;
|
||||
}
|
||||
@@ -229,70 +234,70 @@ static int glue(compute_all_sar, SUFFIX)(void)
|
||||
void OPPROTO glue(op_jb_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
if ((DATA_TYPE)src1 < (DATA_TYPE)src2)
|
||||
EIP = PARAM1;
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
else
|
||||
EIP = PARAM2;
|
||||
JUMP_TB(PARAM1, 1, PARAM3);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_jz_sub, SUFFIX)(void)
|
||||
{
|
||||
if ((DATA_TYPE)CC_DST == 0)
|
||||
EIP = PARAM1;
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
else
|
||||
EIP = PARAM2;
|
||||
JUMP_TB(PARAM1, 1, PARAM3);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_jbe_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
if ((DATA_TYPE)src1 <= (DATA_TYPE)src2)
|
||||
EIP = PARAM1;
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
else
|
||||
EIP = PARAM2;
|
||||
JUMP_TB(PARAM1, 1, PARAM3);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_js_sub, SUFFIX)(void)
|
||||
{
|
||||
if (CC_DST & SIGN_MASK)
|
||||
EIP = PARAM1;
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
else
|
||||
EIP = PARAM2;
|
||||
JUMP_TB(PARAM1, 1, PARAM3);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_jl_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
if ((DATA_STYPE)src1 < (DATA_STYPE)src2)
|
||||
EIP = PARAM1;
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
else
|
||||
EIP = PARAM2;
|
||||
JUMP_TB(PARAM1, 1, PARAM3);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_jle_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
if ((DATA_STYPE)src1 <= (DATA_STYPE)src2)
|
||||
EIP = PARAM1;
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
else
|
||||
EIP = PARAM2;
|
||||
JUMP_TB(PARAM1, 1, PARAM3);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
@@ -356,8 +361,8 @@ void OPPROTO glue(op_jecxz, SUFFIX)(void)
|
||||
void OPPROTO glue(op_setb_T0_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
T0 = ((DATA_TYPE)src1 < (DATA_TYPE)src2);
|
||||
}
|
||||
@@ -370,8 +375,8 @@ void OPPROTO glue(op_setz_T0_sub, SUFFIX)(void)
|
||||
void OPPROTO glue(op_setbe_T0_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
T0 = ((DATA_TYPE)src1 <= (DATA_TYPE)src2);
|
||||
}
|
||||
@@ -384,8 +389,8 @@ void OPPROTO glue(op_sets_T0_sub, SUFFIX)(void)
|
||||
void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
T0 = ((DATA_STYPE)src1 < (DATA_STYPE)src2);
|
||||
}
|
||||
@@ -393,135 +398,14 @@ void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void)
|
||||
void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
T0 = ((DATA_STYPE)src1 <= (DATA_STYPE)src2);
|
||||
}
|
||||
|
||||
/* shifts */
|
||||
|
||||
void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C);
|
||||
src = T0;
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
|
||||
CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
(T0 & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C);
|
||||
src = T0;
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
|
||||
CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
((T0 >> (DATA_BITS - 1)) & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, res, eflags;
|
||||
unsigned int src;
|
||||
|
||||
count = T1 & 0x1f;
|
||||
#if DATA_BITS == 16
|
||||
count = rclw_table[count];
|
||||
#elif DATA_BITS == 8
|
||||
count = rclb_table[count];
|
||||
#endif
|
||||
if (count) {
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
T0 &= DATA_MASK;
|
||||
src = T0;
|
||||
res = (T0 << count) | ((eflags & CC_C) << (count - 1));
|
||||
if (count > 1)
|
||||
res |= T0 >> (DATA_BITS + 1 - count);
|
||||
T0 = res;
|
||||
CC_SRC = (eflags & ~(CC_C | CC_O)) |
|
||||
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
((src >> (DATA_BITS - count)) & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rcr, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, res, eflags;
|
||||
unsigned int src;
|
||||
|
||||
count = T1 & 0x1f;
|
||||
#if DATA_BITS == 16
|
||||
count = rclw_table[count];
|
||||
#elif DATA_BITS == 8
|
||||
count = rclb_table[count];
|
||||
#endif
|
||||
if (count) {
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
T0 &= DATA_MASK;
|
||||
src = T0;
|
||||
res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count));
|
||||
if (count > 1)
|
||||
res |= T0 << (DATA_BITS + 1 - count);
|
||||
T0 = res;
|
||||
CC_SRC = (eflags & ~(CC_C | CC_O)) |
|
||||
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
((src >> (count - 1)) & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & 0x1f;
|
||||
if (count) {
|
||||
CC_SRC = (DATA_TYPE)T0 << (count - 1);
|
||||
T0 = T0 << count;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SHLB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
int count;
|
||||
@@ -530,20 +414,6 @@ void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void)
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & 0x1f;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
CC_SRC = T0 >> (count - 1);
|
||||
T0 = T0 >> count;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
int count;
|
||||
@@ -553,20 +423,6 @@ void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void)
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & 0x1f;
|
||||
if (count) {
|
||||
src = (DATA_STYPE)T0;
|
||||
CC_SRC = src >> (count - 1);
|
||||
T0 = src >> count;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
int count, src;
|
||||
@@ -576,166 +432,11 @@ void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void)
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
#if DATA_BITS == 16
|
||||
/* XXX: overflow flag might be incorrect in some cases in shldw */
|
||||
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res;
|
||||
count = PARAM1;
|
||||
T1 &= 0xffff;
|
||||
res = T1 | (T0 << 16);
|
||||
CC_SRC = res >> (32 - count);
|
||||
res <<= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (count - 16);
|
||||
T0 = res >> 16;
|
||||
CC_DST = T0;
|
||||
}
|
||||
#undef MEM_WRITE
|
||||
#include "ops_template_mem.h"
|
||||
|
||||
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res;
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
T1 &= 0xffff;
|
||||
res = T1 | (T0 << 16);
|
||||
CC_SRC = res >> (32 - count);
|
||||
res <<= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (count - 16);
|
||||
T0 = res >> 16;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res;
|
||||
|
||||
count = PARAM1;
|
||||
res = (T0 & 0xffff) | (T1 << 16);
|
||||
CC_SRC = res >> (count - 1);
|
||||
res >>= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (32 - count);
|
||||
T0 = res;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res;
|
||||
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
res = (T0 & 0xffff) | (T1 << 16);
|
||||
CC_SRC = res >> (count - 1);
|
||||
res >>= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (32 - count);
|
||||
T0 = res;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DATA_BITS == 32
|
||||
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = PARAM1;
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
CC_SRC = T0 << (count - 1);
|
||||
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
CC_SRC = T0 << (count - 1);
|
||||
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SHLB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = PARAM1;
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
CC_SRC = T0 >> (count - 1);
|
||||
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
CC_SRC = T0 >> (count - 1);
|
||||
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* carry add/sub (we only need to set CC_OP differently) */
|
||||
|
||||
void OPPROTO glue(glue(op_adc, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int cf;
|
||||
cf = cc_table[CC_OP].compute_c();
|
||||
CC_SRC = T0;
|
||||
T0 = T0 + T1 + cf;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_ADDB + SHIFT + cf * 3;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_sbb, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int cf;
|
||||
cf = cc_table[CC_OP].compute_c();
|
||||
CC_SRC = T0;
|
||||
T0 = T0 - T1 - cf;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SUBB + SHIFT + cf * 3;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_cmpxchg, SUFFIX), _T0_T1_EAX_cc)(void)
|
||||
{
|
||||
CC_SRC = EAX;
|
||||
CC_DST = EAX - T0;
|
||||
if ((DATA_TYPE)CC_DST == 0) {
|
||||
T0 = T1;
|
||||
} else {
|
||||
EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK);
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
#define MEM_WRITE
|
||||
#include "ops_template_mem.h"
|
||||
|
||||
/* bit operations */
|
||||
#if DATA_BITS >= 16
|
||||
@@ -751,7 +452,7 @@ void OPPROTO glue(glue(op_bts, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & SHIFT_MASK;
|
||||
CC_SRC = T0 >> count;
|
||||
T1 = T0 >> count;
|
||||
T0 |= (1 << count);
|
||||
}
|
||||
|
||||
@@ -759,7 +460,7 @@ void OPPROTO glue(glue(op_btr, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & SHIFT_MASK;
|
||||
CC_SRC = T0 >> count;
|
||||
T1 = T0 >> count;
|
||||
T0 &= ~(1 << count);
|
||||
}
|
||||
|
||||
@@ -767,7 +468,7 @@ void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & SHIFT_MASK;
|
||||
CC_SRC = T0 >> count;
|
||||
T1 = T0 >> count;
|
||||
T0 ^= (1 << count);
|
||||
}
|
||||
|
||||
@@ -809,6 +510,13 @@ void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void)
|
||||
|
||||
#endif
|
||||
|
||||
#if DATA_BITS == 32
|
||||
void OPPROTO op_update_bt_cc(void)
|
||||
{
|
||||
CC_SRC = T1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* string operations */
|
||||
/* XXX: maybe use lower level instructions to ease 16 bit / segment handling */
|
||||
|
||||
@@ -823,7 +531,7 @@ void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void)
|
||||
|
||||
#define STRING_SUFFIX _a32
|
||||
#define SI_ADDR (uint8_t *)A0 + ESI
|
||||
#define DI_ADDR env->seg_cache[R_ES].base + EDI
|
||||
#define DI_ADDR env->segs[R_ES].base + EDI
|
||||
#define INC_SI() ESI += inc
|
||||
#define INC_DI() EDI += inc
|
||||
#define CX ECX
|
||||
@@ -832,7 +540,7 @@ void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void)
|
||||
|
||||
#define STRING_SUFFIX _a16
|
||||
#define SI_ADDR (uint8_t *)A0 + (ESI & 0xffff)
|
||||
#define DI_ADDR env->seg_cache[R_ES].base + (EDI & 0xffff)
|
||||
#define DI_ADDR env->segs[R_ES].base + (EDI & 0xffff)
|
||||
#define INC_SI() ESI = (ESI & ~0xffff) | ((ESI + inc) & 0xffff)
|
||||
#define INC_DI() EDI = (EDI & ~0xffff) | ((EDI + inc) & 0xffff)
|
||||
#define CX (ECX & 0xffff)
|
||||
@@ -843,12 +551,12 @@ void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void)
|
||||
|
||||
void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
glue(cpu_x86_out, SUFFIX)(T0 & 0xffff, T1 & DATA_MASK);
|
||||
glue(cpu_x86_out, SUFFIX)(env, T0 & 0xffff, T1 & DATA_MASK);
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_in, SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
T1 = glue(cpu_x86_in, SUFFIX)(T0 & 0xffff);
|
||||
T1 = glue(cpu_x86_in, SUFFIX)(env, T0 & 0xffff);
|
||||
}
|
||||
|
||||
#undef DATA_BITS
|
||||
|
||||
@@ -0,0 +1,423 @@
|
||||
/*
|
||||
* i386 micro operations (included several times to generate
|
||||
* different operand sizes)
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifdef MEM_WRITE
|
||||
|
||||
#if DATA_BITS == 8
|
||||
#define MEM_SUFFIX b_mem
|
||||
#elif DATA_BITS == 16
|
||||
#define MEM_SUFFIX w_mem
|
||||
#elif DATA_BITS == 32
|
||||
#define MEM_SUFFIX l_mem
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define MEM_SUFFIX SUFFIX
|
||||
|
||||
#endif
|
||||
|
||||
void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
src = T0;
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) |
|
||||
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
(T0 & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
src = T0;
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) |
|
||||
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
((T0 >> (DATA_BITS - 1)) & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rcl, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, res, eflags;
|
||||
unsigned int src;
|
||||
|
||||
count = T1 & 0x1f;
|
||||
#if DATA_BITS == 16
|
||||
count = rclw_table[count];
|
||||
#elif DATA_BITS == 8
|
||||
count = rclb_table[count];
|
||||
#endif
|
||||
if (count) {
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
T0 &= DATA_MASK;
|
||||
src = T0;
|
||||
res = (T0 << count) | ((eflags & CC_C) << (count - 1));
|
||||
if (count > 1)
|
||||
res |= T0 >> (DATA_BITS + 1 - count);
|
||||
T0 = res;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = (eflags & ~(CC_C | CC_O)) |
|
||||
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
((src >> (DATA_BITS - count)) & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rcr, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, res, eflags;
|
||||
unsigned int src;
|
||||
|
||||
count = T1 & 0x1f;
|
||||
#if DATA_BITS == 16
|
||||
count = rclw_table[count];
|
||||
#elif DATA_BITS == 8
|
||||
count = rclb_table[count];
|
||||
#endif
|
||||
if (count) {
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
T0 &= DATA_MASK;
|
||||
src = T0;
|
||||
res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count));
|
||||
if (count > 1)
|
||||
res |= T0 << (DATA_BITS + 1 - count);
|
||||
T0 = res;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = (eflags & ~(CC_C | CC_O)) |
|
||||
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
((src >> (count - 1)) & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shl, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & 0x1f;
|
||||
if (count) {
|
||||
src = (DATA_TYPE)T0 << (count - 1);
|
||||
T0 = T0 << count;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = src;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SHLB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shr, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & 0x1f;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
src = T0 >> (count - 1);
|
||||
T0 = T0 >> count;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = src;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_sar, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & 0x1f;
|
||||
if (count) {
|
||||
src = (DATA_STYPE)T0;
|
||||
T0 = src >> count;
|
||||
src = src >> (count - 1);
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = src;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
#if DATA_BITS == 16
|
||||
/* XXX: overflow flag might be incorrect in some cases in shldw */
|
||||
void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res, tmp;
|
||||
count = PARAM1;
|
||||
T1 &= 0xffff;
|
||||
res = T1 | (T0 << 16);
|
||||
tmp = res >> (32 - count);
|
||||
res <<= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (count - 16);
|
||||
T0 = res >> 16;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res, tmp;
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
T1 &= 0xffff;
|
||||
res = T1 | (T0 << 16);
|
||||
tmp = res >> (32 - count);
|
||||
res <<= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (count - 16);
|
||||
T0 = res >> 16;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res, tmp;
|
||||
|
||||
count = PARAM1;
|
||||
res = (T0 & 0xffff) | (T1 << 16);
|
||||
tmp = res >> (count - 1);
|
||||
res >>= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (32 - count);
|
||||
T0 = res;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res, tmp;
|
||||
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
res = (T0 & 0xffff) | (T1 << 16);
|
||||
tmp = res >> (count - 1);
|
||||
res >>= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (32 - count);
|
||||
T0 = res;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DATA_BITS == 32
|
||||
void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count, tmp;
|
||||
count = PARAM1;
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
tmp = T0 << (count - 1);
|
||||
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count, tmp;
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
tmp = T0 << (count - 1);
|
||||
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SHLB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count, tmp;
|
||||
count = PARAM1;
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
tmp = T0 >> (count - 1);
|
||||
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count, tmp;
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
tmp = T0 >> (count - 1);
|
||||
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* carry add/sub (we only need to set CC_OP differently) */
|
||||
|
||||
void OPPROTO glue(glue(op_adc, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int cf;
|
||||
cf = cc_table[CC_OP].compute_c();
|
||||
T0 = T0 + T1 + cf;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = T1;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_ADDB + SHIFT + cf * 3;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_sbb, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int cf;
|
||||
cf = cc_table[CC_OP].compute_c();
|
||||
T0 = T0 - T1 - cf;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = T1;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SUBB + SHIFT + cf * 3;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_cmpxchg, MEM_SUFFIX), _T0_T1_EAX_cc)(void)
|
||||
{
|
||||
unsigned int src, dst;
|
||||
|
||||
src = T0;
|
||||
dst = EAX - T0;
|
||||
if ((DATA_TYPE)dst == 0) {
|
||||
T0 = T1;
|
||||
} else {
|
||||
EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK);
|
||||
}
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = src;
|
||||
CC_DST = dst;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
#undef MEM_SUFFIX
|
||||
#undef MEM_WRITE
|
||||
+631
-74
@@ -1,78 +1,140 @@
|
||||
\input texinfo @c -*- texinfo -*-
|
||||
|
||||
@settitle QEMU x86 Emulator Reference Documentation
|
||||
@settitle QEMU CPU Emulator Reference Documentation
|
||||
@titlepage
|
||||
@sp 7
|
||||
@center @titlefont{QEMU x86 Emulator Reference Documentation}
|
||||
@center @titlefont{QEMU CPU Emulator Reference Documentation}
|
||||
@sp 3
|
||||
@end titlepage
|
||||
|
||||
@chapter Introduction
|
||||
|
||||
QEMU is an x86 processor emulator. Its purpose is to run x86 Linux
|
||||
processes on non-x86 Linux architectures such as PowerPC or ARM. By
|
||||
using dynamic translation it achieves a reasonnable speed while being
|
||||
easy to port on new host CPUs. Its main goal is to be able to launch the
|
||||
@code{Wine} Windows API emulator (@url{http://www.winehq.org}) on
|
||||
non-x86 CPUs.
|
||||
@section Features
|
||||
|
||||
QEMU features:
|
||||
QEMU is a FAST! processor emulator. By using dynamic translation it
|
||||
achieves a reasonnable speed while being easy to port on new host
|
||||
CPUs.
|
||||
|
||||
QEMU has two operating modes:
|
||||
@itemize
|
||||
@item User mode emulation. In this mode, QEMU can launch Linux processes
|
||||
compiled for one CPU on another CPU. Linux system calls are converted
|
||||
because of endianness and 32/64 bit mismatches. The Wine Windows API
|
||||
emulator (@url{http://www.winehq.org}) and the DOSEMU DOS emulator
|
||||
(@url{www.dosemu.org}) are the main targets for QEMU.
|
||||
|
||||
@item Full system emulation. In this mode, QEMU emulates a full
|
||||
system, including a processor and various peripherials. Currently, it
|
||||
is only used to launch an x86 Linux kernel on an x86 Linux system. It
|
||||
enables easier testing and debugging of system code. It can also be
|
||||
used to provide virtual hosting of several virtual PCs on a single
|
||||
server.
|
||||
|
||||
@end itemize
|
||||
|
||||
As QEMU requires no host kernel patches to run, it is very safe and
|
||||
easy to use.
|
||||
|
||||
QEMU generic features:
|
||||
|
||||
@itemize
|
||||
|
||||
@item User space only x86 emulator.
|
||||
|
||||
@item Currently ported on i386, PowerPC and S390.
|
||||
@item User space only or full system emulation.
|
||||
|
||||
@item Using dynamic translation to native code for reasonnable speed.
|
||||
|
||||
@item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation.
|
||||
User space LDT and GDT are emulated. VM86 mode is also supported
|
||||
(experimental).
|
||||
@item Working on x86 and PowerPC hosts. Being tested on ARM, Sparc32, Alpha and S390.
|
||||
|
||||
@item Self-modifying code support.
|
||||
|
||||
@item Precise exceptions support.
|
||||
|
||||
@item The virtual CPU is a library (@code{libqemu}) which can be used
|
||||
in other projects.
|
||||
|
||||
@end itemize
|
||||
|
||||
QEMU user mode emulation features:
|
||||
@itemize
|
||||
@item Generic Linux system call converter, including most ioctls.
|
||||
|
||||
@item clone() emulation using native CPU clone() to use Linux scheduler for threads.
|
||||
|
||||
@item Accurate signal handling by remapping host signals to virtual x86 signals.
|
||||
@item Accurate signal handling by remapping host signals to target signals.
|
||||
@end itemize
|
||||
@end itemize
|
||||
|
||||
@item The virtual x86 CPU is a library (@code{libqemu}) which can be used
|
||||
in other projects.
|
||||
QEMU full system emulation features:
|
||||
@itemize
|
||||
@item Using mmap() system calls to simulate the MMU
|
||||
@end itemize
|
||||
|
||||
@section x86 emulation
|
||||
|
||||
QEMU x86 target features:
|
||||
|
||||
@itemize
|
||||
|
||||
@item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation.
|
||||
LDT/GDT and IDT are emulated. VM86 mode is also supported to run DOSEMU.
|
||||
|
||||
@item Support of host page sizes bigger than 4KB in user mode emulation.
|
||||
|
||||
@item QEMU can emulate itself on x86.
|
||||
|
||||
@item An extensive Linux x86 CPU test program is included @file{tests/test-i386}.
|
||||
It can be used to test other x86 virtual CPUs.
|
||||
|
||||
@end itemize
|
||||
|
||||
Current QEMU Limitations:
|
||||
Current QEMU limitations:
|
||||
|
||||
@itemize
|
||||
|
||||
@item Not all x86 exceptions are precise (yet). [Very few programs need that].
|
||||
|
||||
@item Not self virtualizable (yet). [You cannot launch qemu with qemu on the same CPU].
|
||||
|
||||
@item No support for self modifying code (yet). [Very few programs need that, a notable exception is QEMU itself !].
|
||||
|
||||
@item No SSE/MMX support (yet).
|
||||
|
||||
@item No x86-64 support.
|
||||
|
||||
@item Some Linux syscalls are missing.
|
||||
@item IPC syscalls are missing.
|
||||
|
||||
@item The x86 segment limits and access rights are not tested at every
|
||||
memory access (and will never be to have good performances).
|
||||
memory access.
|
||||
|
||||
@item On non x86 host CPUs, @code{double}s are used instead of the non standard
|
||||
10 byte @code{long double}s of x86 for floating point emulation to get
|
||||
maximum performances.
|
||||
|
||||
@item Full system emulation only works if no data are mapped above the virtual address
|
||||
0xc0000000 (yet).
|
||||
|
||||
@item Some priviledged instructions or behaviors are missing. Only the ones
|
||||
needed for proper Linux kernel operation are emulated.
|
||||
|
||||
@item No memory separation between the kernel and the user processes is done.
|
||||
It will be implemented very soon.
|
||||
|
||||
@end itemize
|
||||
|
||||
@chapter Invocation
|
||||
@section ARM emulation
|
||||
|
||||
@itemize
|
||||
|
||||
@item ARM emulation can currently launch small programs while using the
|
||||
generic dynamic code generation architecture of QEMU.
|
||||
|
||||
@item No FPU support (yet).
|
||||
|
||||
@item No automatic regression testing (yet).
|
||||
|
||||
@end itemize
|
||||
|
||||
@chapter QEMU User space emulator invocation
|
||||
|
||||
@section Quick Start
|
||||
|
||||
If you need to compile QEMU, please read the @file{README} which gives
|
||||
the related information.
|
||||
|
||||
In order to launch a Linux process, QEMU needs the process executable
|
||||
itself and all the target (x86) dynamic libraries used by it.
|
||||
|
||||
@@ -88,9 +150,14 @@ qemu -L / /bin/ls
|
||||
@code{-L /} tells that the x86 dynamic linker must be searched with a
|
||||
@file{/} prefix.
|
||||
|
||||
@item Since QEMU is also a linux process, you can launch qemu with qemu:
|
||||
|
||||
@example
|
||||
qemu -L / qemu -L / /bin/ls
|
||||
@end example
|
||||
|
||||
@item On non x86 CPUs, you need first to download at least an x86 glibc
|
||||
(@file{qemu-i386-glibc21.tar.gz} on the QEMU web page). Ensure that
|
||||
(@file{qemu-XXX-i386-glibc21.tar.gz} on the QEMU web page). Ensure that
|
||||
@code{LD_LIBRARY_PATH} is not set:
|
||||
|
||||
@example
|
||||
@@ -107,9 +174,14 @@ QEMU is automatically launched by the Linux kernel when you try to
|
||||
launch x86 executables. It requires the @code{binfmt_misc} module in the
|
||||
Linux kernel.
|
||||
|
||||
@item The x86 version of QEMU is also included. You can try weird things such as:
|
||||
@example
|
||||
qemu /usr/local/qemu-i386/bin/qemu-i386 /usr/local/qemu-i386/bin/ls-i386
|
||||
@end example
|
||||
|
||||
@end itemize
|
||||
|
||||
@section Wine launch (Currently only tested when emulating x86 on x86)
|
||||
@section Wine launch
|
||||
|
||||
@itemize
|
||||
|
||||
@@ -122,7 +194,7 @@ qemu /usr/local/qemu-i386/bin/ls-i386
|
||||
@end example
|
||||
|
||||
@item Download the binary x86 Wine install
|
||||
(@file{qemu-i386-wine.tar.gz} on the QEMU web page).
|
||||
(@file{qemu-XXX-i386-wine.tar.gz} on the QEMU web page).
|
||||
|
||||
@item Configure Wine on your account. Look at the provided script
|
||||
@file{/usr/local/qemu-i386/bin/wine-conf.sh}. Your previous
|
||||
@@ -142,38 +214,439 @@ qemu /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Fil
|
||||
usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]
|
||||
@end example
|
||||
|
||||
@table @samp
|
||||
@table @option
|
||||
@item -h
|
||||
Print the help
|
||||
@item -d
|
||||
Activate log (logfile=/tmp/qemu.log)
|
||||
@item -L path
|
||||
Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386)
|
||||
@item -s size
|
||||
Set the x86 stack size in bytes (default=524288)
|
||||
@end table
|
||||
|
||||
Debug options:
|
||||
|
||||
@table @option
|
||||
@item -d
|
||||
Activate log (logfile=/tmp/qemu.log)
|
||||
@item -p pagesize
|
||||
Act as if the host page size was 'pagesize' bytes
|
||||
@end table
|
||||
|
||||
@chapter QEMU System emulator invocation
|
||||
|
||||
@section Quick Start
|
||||
|
||||
This section explains how to launch a Linux kernel inside QEMU.
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
Download the archive @file{vl-test-xxx.tar.gz} containing a Linux
|
||||
kernel and a disk image. The archive also contains a precompiled
|
||||
version of @file{vl}, the QEMU System emulator.
|
||||
|
||||
@item Optional: If you want network support (for example to launch X11 examples), you
|
||||
must copy the script @file{vl-ifup} in @file{/etc} and configure
|
||||
properly @code{sudo} so that the command @code{ifconfig} contained in
|
||||
@file{vl-ifup} can be executed as root. You must verify that your host
|
||||
kernel supports the TUN/TAP network interfaces: the device
|
||||
@file{/dev/net/tun} must be present.
|
||||
|
||||
When network is enabled, there is a virtual network connection between
|
||||
the host kernel and the emulated kernel. The emulated kernel is seen
|
||||
from the host kernel at IP address 172.20.0.2 and the host kernel is
|
||||
seen from the emulated kernel at IP address 172.20.0.1.
|
||||
|
||||
@item Launch @code{vl.sh}. You should have the following output:
|
||||
|
||||
@example
|
||||
> ./vl.sh
|
||||
connected to host network interface: tun0
|
||||
Uncompressing Linux... Ok, booting the kernel.
|
||||
Linux version 2.4.20 (fabrice@localhost.localdomain) (gcc version 2.96 20000731 (Red Hat Linux 7.3 2.96-110)) #22 lun jui 7 13:37:41 CEST 2003
|
||||
BIOS-provided physical RAM map:
|
||||
BIOS-e801: 0000000000000000 - 000000000009f000 (usable)
|
||||
BIOS-e801: 0000000000100000 - 0000000002000000 (usable)
|
||||
32MB LOWMEM available.
|
||||
On node 0 totalpages: 8192
|
||||
zone(0): 4096 pages.
|
||||
zone(1): 4096 pages.
|
||||
zone(2): 0 pages.
|
||||
Kernel command line: root=/dev/hda ide1=noprobe ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe
|
||||
ide_setup: ide1=noprobe
|
||||
ide_setup: ide2=noprobe
|
||||
ide_setup: ide3=noprobe
|
||||
ide_setup: ide4=noprobe
|
||||
ide_setup: ide5=noprobe
|
||||
Initializing CPU#0
|
||||
Detected 501.285 MHz processor.
|
||||
Calibrating delay loop... 989.59 BogoMIPS
|
||||
Memory: 29268k/32768k available (907k kernel code, 3112k reserved, 212k data, 52k init, 0k highmem)
|
||||
Dentry cache hash table entries: 4096 (order: 3, 32768 bytes)
|
||||
Inode cache hash table entries: 2048 (order: 2, 16384 bytes)
|
||||
Mount-cache hash table entries: 512 (order: 0, 4096 bytes)
|
||||
Buffer-cache hash table entries: 1024 (order: 0, 4096 bytes)
|
||||
Page-cache hash table entries: 8192 (order: 3, 32768 bytes)
|
||||
CPU: Intel Pentium Pro stepping 03
|
||||
Checking 'hlt' instruction... OK.
|
||||
POSIX conformance testing by UNIFIX
|
||||
Linux NET4.0 for Linux 2.4
|
||||
Based upon Swansea University Computer Society NET3.039
|
||||
Initializing RT netlink socket
|
||||
apm: BIOS not found.
|
||||
Starting kswapd
|
||||
Journalled Block Device driver loaded
|
||||
pty: 256 Unix98 ptys configured
|
||||
Serial driver version 5.05c (2001-07-08) with no serial options enabled
|
||||
ttyS00 at 0x03f8 (irq = 4) is a 16450
|
||||
Uniform Multi-Platform E-IDE driver Revision: 6.31
|
||||
ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xx
|
||||
hda: QEMU HARDDISK, ATA DISK drive
|
||||
ide0 at 0x1f0-0x1f7,0x3f6 on irq 14
|
||||
hda: 12288 sectors (6 MB) w/256KiB Cache, CHS=12/16/63
|
||||
Partition check:
|
||||
hda: unknown partition table
|
||||
ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com)
|
||||
Last modified Nov 1, 2000 by Paul Gortmaker
|
||||
NE*000 ethercard probe at 0x300: 52 54 00 12 34 56
|
||||
eth0: NE2000 found at 0x300, using IRQ 9.
|
||||
RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
|
||||
NET4: Linux TCP/IP 1.0 for NET4.0
|
||||
IP Protocols: ICMP, UDP, TCP, IGMP
|
||||
IP: routing cache hash table of 512 buckets, 4Kbytes
|
||||
TCP: Hash tables configured (established 2048 bind 4096)
|
||||
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
|
||||
EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended
|
||||
VFS: Mounted root (ext2 filesystem).
|
||||
Freeing unused kernel memory: 52k freed
|
||||
sh: can't access tty; job control turned off
|
||||
#
|
||||
@end example
|
||||
|
||||
@item
|
||||
Then you can play with the kernel inside the virtual serial console. You
|
||||
can launch @code{ls} for example. Type @key{Ctrl-a h} to have an help
|
||||
about the keys you can type inside the virtual serial console. In
|
||||
particular, use @key{Ctrl-a x} to exit QEMU and use @key{Ctrl-a b} as
|
||||
the Magic SysRq key.
|
||||
|
||||
@item
|
||||
If the network is enabled, launch the script @file{/etc/linuxrc} in the
|
||||
emulator (don't forget the leading dot):
|
||||
@example
|
||||
. /etc/linuxrc
|
||||
@end example
|
||||
|
||||
Then enable X11 connections on your PC from the emulated Linux:
|
||||
@example
|
||||
xhost +172.20.0.2
|
||||
@end example
|
||||
|
||||
You can now launch @file{xterm} or @file{xlogo} and verify that you have
|
||||
a real Virtual Linux system !
|
||||
|
||||
@end enumerate
|
||||
|
||||
NOTES:
|
||||
@enumerate
|
||||
@item
|
||||
A 2.5.74 kernel is also included in the vl-test archive. Just
|
||||
replace the bzImage in vl.sh to try it.
|
||||
|
||||
@item
|
||||
vl creates a temporary file in @var{$VLTMPDIR} (@file{/tmp} is the
|
||||
default) containing all the simulated PC memory. If possible, try to use
|
||||
a temporary directory using the tmpfs filesystem to avoid too many
|
||||
unnecessary disk accesses.
|
||||
|
||||
@item
|
||||
In order to exit cleanly for vl, you can do a @emph{shutdown} inside
|
||||
vl. vl will automatically exit when the Linux shutdown is done.
|
||||
|
||||
@item
|
||||
You can boot slightly faster by disabling the probe of non present IDE
|
||||
interfaces. To do so, add the following options on the kernel command
|
||||
line:
|
||||
@example
|
||||
ide1=noprobe ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe
|
||||
@end example
|
||||
|
||||
@item
|
||||
The example disk image is a modified version of the one made by Kevin
|
||||
Lawton for the plex86 Project (@url{www.plex86.org}).
|
||||
|
||||
@end enumerate
|
||||
|
||||
@section Invocation
|
||||
|
||||
@example
|
||||
usage: vl [options] bzImage [kernel parameters...]
|
||||
@end example
|
||||
|
||||
@file{bzImage} is a Linux kernel image.
|
||||
|
||||
General options:
|
||||
@table @option
|
||||
@item -hda file
|
||||
@item -hdb file
|
||||
Use 'file' as hard disk 0 or 1 image (@xref{disk_images}).
|
||||
|
||||
@item -snapshot
|
||||
|
||||
Write to temporary files instead of disk image files. In this case,
|
||||
the raw disk image you use is not written back. You can however force
|
||||
the write back by pressing @key{C-a s} (@xref{disk_images}).
|
||||
|
||||
@item -m megs
|
||||
Set virtual RAM size to @var{megs} megabytes.
|
||||
|
||||
@item -n script
|
||||
Set network init script [default=/etc/vl-ifup]. This script is
|
||||
launched to configure the host network interface (usually tun0)
|
||||
corresponding to the virtual NE2000 card.
|
||||
|
||||
@item -initrd file
|
||||
Use 'file' as initial ram disk.
|
||||
@end table
|
||||
|
||||
Debug options:
|
||||
@table @option
|
||||
@item -s
|
||||
Wait gdb connection to port 1234.
|
||||
@item -p port
|
||||
Change gdb connection port.
|
||||
@item -d
|
||||
Output log in /tmp/vl.log
|
||||
@end table
|
||||
|
||||
During emulation, use @key{C-a h} to get terminal commands:
|
||||
|
||||
@table @key
|
||||
@item C-a h
|
||||
Print this help
|
||||
@item C-a x
|
||||
Exit emulatior
|
||||
@item C-a s
|
||||
Save disk data back to file (if -snapshot)
|
||||
@item C-a b
|
||||
Send break (magic sysrq)
|
||||
@item C-a C-a
|
||||
Send C-a
|
||||
@end table
|
||||
|
||||
@node disk_images
|
||||
@section Disk Images
|
||||
|
||||
@subsection Raw disk images
|
||||
|
||||
The disk images can simply be raw images of the hard disk. You can
|
||||
create them with the command:
|
||||
@example
|
||||
dd if=/dev/zero of=myimage bs=1024 count=mysize
|
||||
@end example
|
||||
where @var{myimage} is the image filename and @var{mysize} is its size
|
||||
in kilobytes.
|
||||
|
||||
@subsection Snapshot mode
|
||||
|
||||
If you use the option @option{-snapshot}, all disk images are
|
||||
considered as read only. When sectors in written, they are written in
|
||||
a temporary file created in @file{/tmp}. You can however force the
|
||||
write back to the raw disk images by pressing @key{C-a s}.
|
||||
|
||||
NOTE: The snapshot mode only works with raw disk images.
|
||||
|
||||
@subsection Copy On Write disk images
|
||||
|
||||
QEMU also supports user mode Linux
|
||||
(@url{http://user-mode-linux.sourceforge.net/}) Copy On Write (COW)
|
||||
disk images. The COW disk images are much smaller than normal images
|
||||
as they store only modified sectors. They also permit the use of the
|
||||
same disk image template for many users.
|
||||
|
||||
To create a COW disk images, use the command:
|
||||
|
||||
@example
|
||||
vlmkcow -f myrawimage.bin mycowimage.cow
|
||||
@end example
|
||||
|
||||
@file{myrawimage.bin} is a raw image you want to use as original disk
|
||||
image. It will never be written to.
|
||||
|
||||
@file{mycowimage.cow} is the COW disk image which is created by
|
||||
@code{vlmkcow}. You can use it directly with the @option{-hdx}
|
||||
options. You must not modify the original raw disk image if you use
|
||||
COW images, as COW images only store the modified sectors from the raw
|
||||
disk image. QEMU stores the original raw disk image name and its
|
||||
modified time in the COW disk image so that chances of mistakes are
|
||||
reduced.
|
||||
|
||||
If raw disk image is not read-only, by pressing @key{C-a s} you can
|
||||
flush the COW disk image back into the raw disk image, as in snapshot
|
||||
mode.
|
||||
|
||||
COW disk images can also be created without a corresponding raw disk
|
||||
image. It is useful to have a big initial virtual disk image without
|
||||
using much disk space. Use:
|
||||
|
||||
@example
|
||||
vlmkcow mycowimage.cow 1024
|
||||
@end example
|
||||
|
||||
to create a 1 gigabyte empty COW disk image.
|
||||
|
||||
NOTES:
|
||||
@enumerate
|
||||
@item
|
||||
COW disk images must be created on file systems supporting
|
||||
@emph{holes} such as ext2 or ext3.
|
||||
@item
|
||||
Since holes are used, the displayed size of the COW disk image is not
|
||||
the real one. To know it, use the @code{ls -ls} command.
|
||||
@end enumerate
|
||||
|
||||
@section Linux Kernel Compilation
|
||||
|
||||
You should be able to use any kernel with QEMU provided you make the
|
||||
following changes (only 2.4.x and 2.5.x were tested):
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
The kernel must be mapped at 0x90000000 (the default is
|
||||
0xc0000000). You must modify only two lines in the kernel source:
|
||||
|
||||
In @file{include/asm/page.h}, replace
|
||||
@example
|
||||
#define __PAGE_OFFSET (0xc0000000)
|
||||
@end example
|
||||
by
|
||||
@example
|
||||
#define __PAGE_OFFSET (0x90000000)
|
||||
@end example
|
||||
|
||||
And in @file{arch/i386/vmlinux.lds}, replace
|
||||
@example
|
||||
. = 0xc0000000 + 0x100000;
|
||||
@end example
|
||||
by
|
||||
@example
|
||||
. = 0x90000000 + 0x100000;
|
||||
@end example
|
||||
|
||||
@item
|
||||
If you want to enable SMP (Symmetric Multi-Processing) support, you
|
||||
must make the following change in @file{include/asm/fixmap.h}. Replace
|
||||
@example
|
||||
#define FIXADDR_TOP (0xffffX000UL)
|
||||
@end example
|
||||
by
|
||||
@example
|
||||
#define FIXADDR_TOP (0xa7ffX000UL)
|
||||
@end example
|
||||
(X is 'e' or 'f' depending on the kernel version). Although you can
|
||||
use an SMP kernel with QEMU, it only supports one CPU.
|
||||
|
||||
@item
|
||||
If you are not using a 2.5 kernel as host kernel but if you use a target
|
||||
2.5 kernel, you must also ensure that the 'HZ' define is set to 100
|
||||
(1000 is the default) as QEMU cannot currently emulate timers at
|
||||
frequencies greater than 100 Hz on host Linux systems < 2.5. In
|
||||
@file{include/asm/param.h}, replace:
|
||||
|
||||
@example
|
||||
# define HZ 1000 /* Internal kernel timer frequency */
|
||||
@end example
|
||||
by
|
||||
@example
|
||||
# define HZ 100 /* Internal kernel timer frequency */
|
||||
@end example
|
||||
|
||||
@end enumerate
|
||||
|
||||
The file config-2.x.x gives the configuration of the example kernels.
|
||||
|
||||
Just type
|
||||
@example
|
||||
make bzImage
|
||||
@end example
|
||||
|
||||
As you would do to make a real kernel. Then you can use with QEMU
|
||||
exactly the same kernel as you would boot on your PC (in
|
||||
@file{arch/i386/boot/bzImage}).
|
||||
|
||||
@section PC Emulation
|
||||
|
||||
QEMU emulates the following PC peripherials:
|
||||
|
||||
@itemize
|
||||
@item
|
||||
PIC (interrupt controler)
|
||||
@item
|
||||
PIT (timers)
|
||||
@item
|
||||
CMOS memory
|
||||
@item
|
||||
Dumb VGA (to print the @code{Uncompressing Linux} message)
|
||||
@item
|
||||
Serial port (port=0x3f8, irq=4)
|
||||
@item
|
||||
NE2000 network adapter (port=0x300, irq=9)
|
||||
@item
|
||||
IDE disk interface (port=0x1f0, irq=14)
|
||||
@end itemize
|
||||
|
||||
@section GDB usage
|
||||
|
||||
QEMU has a primitive support to work with gdb, so that you can do
|
||||
'Ctrl-C' while the kernel is running and inspect its state.
|
||||
|
||||
In order to use gdb, launch vl with the '-s' option. It will wait for a
|
||||
gdb connection:
|
||||
@example
|
||||
> vl -s arch/i386/boot/bzImage initrd-2.4.20.img root=/dev/ram0 ramdisk_size=6144
|
||||
Connected to host network interface: tun0
|
||||
Waiting gdb connection on port 1234
|
||||
@end example
|
||||
|
||||
Then launch gdb on the 'vmlinux' executable:
|
||||
@example
|
||||
> gdb vmlinux
|
||||
@end example
|
||||
|
||||
In gdb, connect to QEMU:
|
||||
@example
|
||||
(gdb) target remote locahost:1234
|
||||
@end example
|
||||
|
||||
Then you can use gdb normally. For example, type 'c' to launch the kernel:
|
||||
@example
|
||||
(gdb) c
|
||||
@end example
|
||||
|
||||
WARNING: breakpoints and single stepping are not yet supported.
|
||||
|
||||
@chapter QEMU Internals
|
||||
|
||||
@section QEMU compared to other emulators
|
||||
|
||||
Unlike bochs [3], QEMU emulates only a user space x86 CPU. It means that
|
||||
you cannot launch an operating system with it. The benefit is that it is
|
||||
simpler and faster due to the fact that some of the low level CPU state
|
||||
can be ignored (in particular, no virtual memory needs to be emulated).
|
||||
Like bochs [3], QEMU emulates an x86 CPU. But QEMU is much faster than
|
||||
bochs as it uses dynamic compilation and because it uses the host MMU to
|
||||
simulate the x86 MMU. The downside is that currently the emulation is
|
||||
not as accurate as bochs (for example, you cannot currently run Windows
|
||||
inside QEMU).
|
||||
|
||||
Like Valgrind [2], QEMU does user space emulation and dynamic
|
||||
translation. Valgrind is mainly a memory debugger while QEMU has no
|
||||
support for it (QEMU could be used to detect out of bound memory accesses
|
||||
as Valgrind, but it has no support to track uninitialised data as
|
||||
Valgrind does). Valgrind dynamic translator generates better code than
|
||||
QEMU (in particular it does register allocation) but it is closely tied
|
||||
to an x86 host.
|
||||
support for it (QEMU could be used to detect out of bound memory
|
||||
accesses as Valgrind, but it has no support to track uninitialised data
|
||||
as Valgrind does). The Valgrind dynamic translator generates better code
|
||||
than QEMU (in particular it does register allocation) but it is closely
|
||||
tied to an x86 host and target and has no support for precise exceptions
|
||||
and system emulation.
|
||||
|
||||
EM86 [4] is the closest project to QEMU (and QEMU still uses some of its
|
||||
code, in particular the ELF file loader). EM86 was limited to an alpha
|
||||
host and used a proprietary and slow interpreter (the interpreter part
|
||||
of the FX!32 Digital Win32 code translator [5]).
|
||||
EM86 [4] is the closest project to user space QEMU (and QEMU still uses
|
||||
some of its code, in particular the ELF file loader). EM86 was limited
|
||||
to an alpha host and used a proprietary and slow interpreter (the
|
||||
interpreter part of the FX!32 Digital Win32 code translator [5]).
|
||||
|
||||
TWIN [6] is a Windows API emulator like Wine. It is less accurate than
|
||||
Wine but includes a protected mode x86 interpreter to launch x86 Windows
|
||||
@@ -182,11 +655,25 @@ Windows API is executed natively but it is far more difficult to develop
|
||||
because all the data structures and function parameters exchanged
|
||||
between the API and the x86 code must be converted.
|
||||
|
||||
User mode Linux [7] was the only solution before QEMU to launch a Linux
|
||||
kernel as a process while not needing any host kernel patches. However,
|
||||
user mode Linux requires heavy kernel patches while QEMU accepts
|
||||
unpatched Linux kernels. It would be interesting to compare the
|
||||
performance of the two approaches.
|
||||
|
||||
The new Plex86 [8] PC virtualizer is done in the same spirit as the QEMU
|
||||
system emulator. It requires a patched Linux kernel to work (you cannot
|
||||
launch the same kernel on your PC), but the patches are really small. As
|
||||
it is a PC virtualizer (no emulation is done except for some priveledged
|
||||
instructions), it has the potential of being faster than QEMU. The
|
||||
downside is that a complicated (and potentially unsafe) host kernel
|
||||
patch is needed.
|
||||
|
||||
@section Portable dynamic translation
|
||||
|
||||
QEMU is a dynamic translator. When it first encounters a piece of code,
|
||||
it converts it to the host instruction set. Usually dynamic translators
|
||||
are very complicated and highly CPU dependant. QEMU uses some tricks
|
||||
are very complicated and highly CPU dependent. QEMU uses some tricks
|
||||
which make it relatively easily portable and simple while achieving good
|
||||
performances.
|
||||
|
||||
@@ -255,17 +742,59 @@ contains just a single basic block (a block of x86 instructions
|
||||
terminated by a jump or by a virtual CPU state change which the
|
||||
translator cannot deduce statically).
|
||||
|
||||
[Currently, the translated code is not patched if it jumps to another
|
||||
translated code].
|
||||
@section Direct block chaining
|
||||
|
||||
After each translated basic block is executed, QEMU uses the simulated
|
||||
Program Counter (PC) and other cpu state informations (such as the CS
|
||||
segment base value) to find the next basic block.
|
||||
|
||||
In order to accelerate the most common cases where the new simulated PC
|
||||
is known, QEMU can patch a basic block so that it jumps directly to the
|
||||
next one.
|
||||
|
||||
The most portable code uses an indirect jump. An indirect jump makes it
|
||||
easier to make the jump target modification atomic. On some
|
||||
architectures (such as PowerPC), the @code{JUMP} opcode is directly
|
||||
patched so that the block chaining has no overhead.
|
||||
|
||||
@section Self-modifying code and translated code invalidation
|
||||
|
||||
Self-modifying code is a special challenge in x86 emulation because no
|
||||
instruction cache invalidation is signaled by the application when code
|
||||
is modified.
|
||||
|
||||
When translated code is generated for a basic block, the corresponding
|
||||
host page is write protected if it is not already read-only (with the
|
||||
system call @code{mprotect()}). Then, if a write access is done to the
|
||||
page, Linux raises a SEGV signal. QEMU then invalidates all the
|
||||
translated code in the page and enables write accesses to the page.
|
||||
|
||||
Correct translated code invalidation is done efficiently by maintaining
|
||||
a linked list of every translated block contained in a given page. Other
|
||||
linked lists are also maintained to undo direct block chaining.
|
||||
|
||||
Although the overhead of doing @code{mprotect()} calls is important,
|
||||
most MSDOS programs can be emulated at reasonnable speed with QEMU and
|
||||
DOSEMU.
|
||||
|
||||
Note that QEMU also invalidates pages of translated code when it detects
|
||||
that memory mappings are modified with @code{mmap()} or @code{munmap()}.
|
||||
|
||||
@section Exception support
|
||||
|
||||
longjmp() is used when an exception such as division by zero is
|
||||
encountered. The host SIGSEGV and SIGBUS signal handlers are used to get
|
||||
invalid memory accesses.
|
||||
encountered.
|
||||
|
||||
[Currently, the virtual CPU cannot retrieve the exact CPU state in some
|
||||
exceptions, although it could except for the @code{EFLAGS} register].
|
||||
The host SIGSEGV and SIGBUS signal handlers are used to get invalid
|
||||
memory accesses. The exact CPU state can be retrieved because all the
|
||||
x86 registers are stored in fixed host registers. The simulated program
|
||||
counter is found by retranslating the corresponding basic block and by
|
||||
looking where the host program counter was at the exception point.
|
||||
|
||||
The virtual CPU cannot retrieve the exact @code{EFLAGS} register because
|
||||
in some cases it is not computed because of condition code
|
||||
optimisations. It is not a big concern because the emulated code can
|
||||
still be restarted in any cases.
|
||||
|
||||
@section Linux system call translation
|
||||
|
||||
@@ -274,6 +803,11 @@ the parameters of the system calls can be converted to fix the
|
||||
endianness and 32/64 bit issues. The IOCTLs are converted with a generic
|
||||
type description system (see @file{ioctls.h} and @file{thunk.c}).
|
||||
|
||||
QEMU supports host CPUs which have pages bigger than 4KB. It records all
|
||||
the mappings the process does and try to emulated the @code{mmap()}
|
||||
system calls in cases where the host @code{mmap()} call would fail
|
||||
because of bad page alignment.
|
||||
|
||||
@section Linux signals
|
||||
|
||||
Normal and real-time signals are queued along with their information
|
||||
@@ -302,6 +836,31 @@ thread.
|
||||
The virtual x86 CPU atomic operations are emulated with a global lock so
|
||||
that their semantic is preserved.
|
||||
|
||||
Note that currently there are still some locking issues in QEMU. In
|
||||
particular, the translated cache flush is not protected yet against
|
||||
reentrancy.
|
||||
|
||||
@section Self-virtualization
|
||||
|
||||
QEMU was conceived so that ultimately it can emulate itself. Although
|
||||
it is not very useful, it is an important test to show the power of the
|
||||
emulator.
|
||||
|
||||
Achieving self-virtualization is not easy because there may be address
|
||||
space conflicts. QEMU solves this problem by being an executable ELF
|
||||
shared object as the ld-linux.so ELF interpreter. That way, it can be
|
||||
relocated at load time.
|
||||
|
||||
@section MMU emulation
|
||||
|
||||
For system emulation, QEMU uses the mmap() system call to emulate the
|
||||
target CPU MMU. It works as long the emulated OS does not use an area
|
||||
reserved by the host OS (such as the area above 0xc0000000 on x86
|
||||
Linux).
|
||||
|
||||
It is planned to add a slower but more precise MMU emulation
|
||||
with a software MMU.
|
||||
|
||||
@section Bibliography
|
||||
|
||||
@table @asis
|
||||
@@ -332,18 +891,31 @@ Chernoff and Ray Hookway.
|
||||
@url{http://www.willows.com/}, Windows API library emulation from
|
||||
Willows Software.
|
||||
|
||||
@item [7]
|
||||
@url{http://user-mode-linux.sourceforge.net/},
|
||||
The User-mode Linux Kernel.
|
||||
|
||||
@item [8]
|
||||
@url{http://www.plex86.org/},
|
||||
The new Plex86 project.
|
||||
|
||||
@end table
|
||||
|
||||
@chapter Regression Tests
|
||||
|
||||
In the directory @file{tests/}, various interesting x86 testing programs
|
||||
In the directory @file{tests/}, various interesting testing programs
|
||||
are available. There are used for regression testing.
|
||||
|
||||
@section @file{hello}
|
||||
@section @file{hello-i386}
|
||||
|
||||
Very simple statically linked x86 program, just to test QEMU during a
|
||||
port to a new host CPU.
|
||||
|
||||
@section @file{hello-arm}
|
||||
|
||||
Very simple statically linked ARM program, just to test QEMU during a
|
||||
port to a new host CPU.
|
||||
|
||||
@section @file{test-i386}
|
||||
|
||||
This program executes most of the 16 bit and 32 bit x86 instructions and
|
||||
@@ -354,19 +926,10 @@ program and a @code{diff} on the generated output.
|
||||
The Linux system call @code{modify_ldt()} is used to create x86 selectors
|
||||
to test some 16 bit addressing and 32 bit with segmentation cases.
|
||||
|
||||
@section @file{testsig}
|
||||
The Linux system call @code{vm86()} is used to test vm86 emulation.
|
||||
|
||||
This program tests various signal cases, including SIGFPE, SIGSEGV and
|
||||
SIGILL.
|
||||
|
||||
@section @file{testclone}
|
||||
|
||||
Tests the @code{clone()} system call (basic test).
|
||||
|
||||
@section @file{testthread}
|
||||
|
||||
Tests the glibc threads (more complicated than @code{clone()} because signals
|
||||
are also used).
|
||||
Various exceptions are raised to test most of the x86 user space
|
||||
exception reporting.
|
||||
|
||||
@section @file{sha1}
|
||||
|
||||
@@ -374,9 +937,3 @@ It is a simple benchmark. Care must be taken to interpret the results
|
||||
because it mostly tests the ability of the virtual CPU to optimize the
|
||||
@code{rol} x86 instruction and the condition code computations.
|
||||
|
||||
@section @file{runcom}
|
||||
|
||||
A very simple MSDOS emulator to test the Linux vm86() system call
|
||||
emulation. The excellent 54 byte @file{pi_10.com} PI number calculator
|
||||
can be launched with it. @file{pi_10.com} was written by Bertram
|
||||
Felgenhauer (more information at @url{http://www.boo.net/~jasonp/pipage.html}).
|
||||
@@ -0,0 +1,204 @@
|
||||
OUTPUT_FORMAT("elf32-s390", "elf32-s390",
|
||||
"elf32-s390")
|
||||
OUTPUT_ARCH(s390:31-bit)
|
||||
ENTRY(_start)
|
||||
SEARCH_DIR("/usr/s390-redhat-linux/lib"); SEARCH_DIR("/usr/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib");
|
||||
/* Do we need any of these for elf?
|
||||
__DYNAMIC = 0; */
|
||||
SECTIONS
|
||||
{
|
||||
/* Read-only sections, merged into text segment: */
|
||||
. = 0x60000000 + SIZEOF_HEADERS;
|
||||
.interp : { *(.interp) }
|
||||
.hash : { *(.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
.rel.dyn :
|
||||
{
|
||||
*(.rel.init)
|
||||
*(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
|
||||
*(.rel.fini)
|
||||
*(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
|
||||
*(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
|
||||
*(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
|
||||
*(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
|
||||
*(.rel.ctors)
|
||||
*(.rel.dtors)
|
||||
*(.rel.got)
|
||||
*(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*)
|
||||
*(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*)
|
||||
*(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*)
|
||||
*(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*)
|
||||
*(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
|
||||
}
|
||||
.rela.dyn :
|
||||
{
|
||||
*(.rela.init)
|
||||
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
|
||||
*(.rela.fini)
|
||||
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
|
||||
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
|
||||
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
|
||||
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
|
||||
*(.rela.ctors)
|
||||
*(.rela.dtors)
|
||||
*(.rela.got)
|
||||
*(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
|
||||
*(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
|
||||
*(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
|
||||
*(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
|
||||
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
|
||||
}
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.init :
|
||||
{
|
||||
KEEP (*(.init))
|
||||
} =0x07070707
|
||||
.plt : { *(.plt) }
|
||||
.text :
|
||||
{
|
||||
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||
*(.gnu.warning)
|
||||
} =0x07070707
|
||||
.fini :
|
||||
{
|
||||
KEEP (*(.fini))
|
||||
} =0x07070707
|
||||
PROVIDE (__etext = .);
|
||||
PROVIDE (_etext = .);
|
||||
PROVIDE (etext = .);
|
||||
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
|
||||
.sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
|
||||
.eh_frame_hdr : { *(.eh_frame_hdr) }
|
||||
/* Adjust the address for the data segment. We want to adjust up to
|
||||
the same address within the page on the next page up. */
|
||||
. = ALIGN(0x1000) + (. & (0x1000 - 1));
|
||||
/* Ensure the __preinit_array_start label is properly aligned. We
|
||||
could instead move the label definition inside the section, but
|
||||
the linker would then create the section even if it turns out to
|
||||
be empty, which isn't pretty. */
|
||||
. = ALIGN(32 / 8);
|
||||
PROVIDE (__preinit_array_start = .);
|
||||
.preinit_array : { *(.preinit_array) }
|
||||
PROVIDE (__preinit_array_end = .);
|
||||
PROVIDE (__init_array_start = .);
|
||||
.init_array : { *(.init_array) }
|
||||
PROVIDE (__init_array_end = .);
|
||||
PROVIDE (__fini_array_start = .);
|
||||
.fini_array : { *(.fini_array) }
|
||||
PROVIDE (__fini_array_end = .);
|
||||
.data :
|
||||
{
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
SORT(CONSTRUCTORS)
|
||||
}
|
||||
.data1 : { *(.data1) }
|
||||
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
|
||||
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
|
||||
.eh_frame : { KEEP (*(.eh_frame)) }
|
||||
.gcc_except_table : { *(.gcc_except_table) }
|
||||
.dynamic : { *(.dynamic) }
|
||||
.ctors :
|
||||
{
|
||||
/* gcc uses crtbegin.o to find the start of
|
||||
the constructors, so we make sure it is
|
||||
first. Because this is a wildcard, it
|
||||
doesn't matter if the user does not
|
||||
actually link against crtbegin.o; the
|
||||
linker won't look for a file to match a
|
||||
wildcard. The wildcard also means that it
|
||||
doesn't matter which directory crtbegin.o
|
||||
is in. */
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
/* We don't want to include the .ctor section from
|
||||
from the crtend.o file until after the sorted ctors.
|
||||
The .ctor section from the crtend file contains the
|
||||
end of ctors marker and it must be last */
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
}
|
||||
.dtors :
|
||||
{
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
}
|
||||
.jcr : { KEEP (*(.jcr)) }
|
||||
.got : { *(.got.plt) *(.got) }
|
||||
/* We want the small data sections together, so single-instruction offsets
|
||||
can access them all, and initialized data all before uninitialized, so
|
||||
we can shorten the on-disk segment size. */
|
||||
.sdata :
|
||||
{
|
||||
*(.sdata .sdata.* .gnu.linkonce.s.*)
|
||||
}
|
||||
_edata = .;
|
||||
PROVIDE (edata = .);
|
||||
__bss_start = .;
|
||||
.sbss :
|
||||
{
|
||||
PROVIDE (__sbss_start = .);
|
||||
PROVIDE (___sbss_start = .);
|
||||
*(.dynsbss)
|
||||
*(.sbss .sbss.* .gnu.linkonce.sb.*)
|
||||
*(.scommon)
|
||||
PROVIDE (__sbss_end = .);
|
||||
PROVIDE (___sbss_end = .);
|
||||
}
|
||||
.bss :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
/* Align here to ensure that the .bss section occupies space up to
|
||||
_end. Align after .bss to ensure correct alignment even if the
|
||||
.bss section disappears because there are no input sections. */
|
||||
. = ALIGN(32 / 8);
|
||||
}
|
||||
. = ALIGN(32 / 8);
|
||||
_end = .;
|
||||
PROVIDE (end = .);
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
}
|
||||
|
||||
+3214
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,128 @@
|
||||
OUTPUT_FORMAT("elf32-sparc", "elf32-sparc",
|
||||
"elf32-sparc")
|
||||
OUTPUT_ARCH(sparc)
|
||||
SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
/* Read-only sections, merged into text segment: */
|
||||
. = 0x60000000 + SIZEOF_HEADERS;
|
||||
.interp : { *(.interp) }
|
||||
.hash : { *(.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
.rel.text :
|
||||
{ *(.rel.text) *(.rel.gnu.linkonce.t*) }
|
||||
.rela.text :
|
||||
{ *(.rela.text) *(.rela.gnu.linkonce.t*) }
|
||||
.rel.data :
|
||||
{ *(.rel.data) *(.rel.gnu.linkonce.d*) }
|
||||
.rela.data :
|
||||
{ *(.rela.data) *(.rela.gnu.linkonce.d*) }
|
||||
.rel.rodata :
|
||||
{ *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
|
||||
.rela.rodata :
|
||||
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
|
||||
.rel.got : { *(.rel.got) }
|
||||
.rela.got : { *(.rela.got) }
|
||||
.rel.ctors : { *(.rel.ctors) }
|
||||
.rela.ctors : { *(.rela.ctors) }
|
||||
.rel.dtors : { *(.rel.dtors) }
|
||||
.rela.dtors : { *(.rela.dtors) }
|
||||
.rel.init : { *(.rel.init) }
|
||||
.rela.init : { *(.rela.init) }
|
||||
.rel.fini : { *(.rel.fini) }
|
||||
.rela.fini : { *(.rela.fini) }
|
||||
.rel.bss : { *(.rel.bss) }
|
||||
.rela.bss : { *(.rela.bss) }
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.init : { *(.init) } =0x47ff041f
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||
*(.gnu.warning)
|
||||
*(.gnu.linkonce.t*)
|
||||
} =0x47ff041f
|
||||
_etext = .;
|
||||
PROVIDE (etext = .);
|
||||
.fini : { *(.fini) } =0x47ff041f
|
||||
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.reginfo : { *(.reginfo) }
|
||||
/* Adjust the address for the data segment. We want to adjust up to
|
||||
the same address within the page on the next page up. */
|
||||
. = ALIGN(0x100000) + (. & (0x100000 - 1));
|
||||
.data :
|
||||
{
|
||||
*(.data)
|
||||
*(.gnu.linkonce.d*)
|
||||
CONSTRUCTORS
|
||||
}
|
||||
.data1 : { *(.data1) }
|
||||
.ctors :
|
||||
{
|
||||
*(.ctors)
|
||||
}
|
||||
.dtors :
|
||||
{
|
||||
*(.dtors)
|
||||
}
|
||||
.plt : { *(.plt) }
|
||||
.got : { *(.got.plt) *(.got) }
|
||||
.dynamic : { *(.dynamic) }
|
||||
/* We want the small data sections together, so single-instruction offsets
|
||||
can access them all, and initialized data all before uninitialized, so
|
||||
we can shorten the on-disk segment size. */
|
||||
.sdata : { *(.sdata) }
|
||||
_edata = .;
|
||||
PROVIDE (edata = .);
|
||||
__bss_start = .;
|
||||
.sbss : { *(.sbss) *(.scommon) }
|
||||
.bss :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
}
|
||||
_end = . ;
|
||||
PROVIDE (end = .);
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
/* These must appear regardless of . */
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
/* this struct defines the way the registers are stored on the
|
||||
stack during a system call. */
|
||||
|
||||
struct target_pt_regs {
|
||||
target_long uregs[18];
|
||||
};
|
||||
|
||||
#define ARM_cpsr uregs[16]
|
||||
#define ARM_pc uregs[15]
|
||||
#define ARM_lr uregs[14]
|
||||
#define ARM_sp uregs[13]
|
||||
#define ARM_ip uregs[12]
|
||||
#define ARM_fp uregs[11]
|
||||
#define ARM_r10 uregs[10]
|
||||
#define ARM_r9 uregs[9]
|
||||
#define ARM_r8 uregs[8]
|
||||
#define ARM_r7 uregs[7]
|
||||
#define ARM_r6 uregs[6]
|
||||
#define ARM_r5 uregs[5]
|
||||
#define ARM_r4 uregs[4]
|
||||
#define ARM_r3 uregs[3]
|
||||
#define ARM_r2 uregs[2]
|
||||
#define ARM_r1 uregs[1]
|
||||
#define ARM_r0 uregs[0]
|
||||
#define ARM_ORIG_r0 uregs[17]
|
||||
|
||||
+7
-856
@@ -1,467 +1,3 @@
|
||||
/* from linux/unistd.h */
|
||||
|
||||
#define TARGET_NR_exit 1
|
||||
#define TARGET_NR_fork 2
|
||||
#define TARGET_NR_read 3
|
||||
#define TARGET_NR_write 4
|
||||
#define TARGET_NR_open 5
|
||||
#define TARGET_NR_close 6
|
||||
#define TARGET_NR_waitpid 7
|
||||
#define TARGET_NR_creat 8
|
||||
#define TARGET_NR_link 9
|
||||
#define TARGET_NR_unlink 10
|
||||
#define TARGET_NR_execve 11
|
||||
#define TARGET_NR_chdir 12
|
||||
#define TARGET_NR_time 13
|
||||
#define TARGET_NR_mknod 14
|
||||
#define TARGET_NR_chmod 15
|
||||
#define TARGET_NR_lchown 16
|
||||
#define TARGET_NR_break 17
|
||||
#define TARGET_NR_oldstat 18
|
||||
#define TARGET_NR_lseek 19
|
||||
#define TARGET_NR_getpid 20
|
||||
#define TARGET_NR_mount 21
|
||||
#define TARGET_NR_umount 22
|
||||
#define TARGET_NR_setuid 23
|
||||
#define TARGET_NR_getuid 24
|
||||
#define TARGET_NR_stime 25
|
||||
#define TARGET_NR_ptrace 26
|
||||
#define TARGET_NR_alarm 27
|
||||
#define TARGET_NR_oldfstat 28
|
||||
#define TARGET_NR_pause 29
|
||||
#define TARGET_NR_utime 30
|
||||
#define TARGET_NR_stty 31
|
||||
#define TARGET_NR_gtty 32
|
||||
#define TARGET_NR_access 33
|
||||
#define TARGET_NR_nice 34
|
||||
#define TARGET_NR_ftime 35
|
||||
#define TARGET_NR_sync 36
|
||||
#define TARGET_NR_kill 37
|
||||
#define TARGET_NR_rename 38
|
||||
#define TARGET_NR_mkdir 39
|
||||
#define TARGET_NR_rmdir 40
|
||||
#define TARGET_NR_dup 41
|
||||
#define TARGET_NR_pipe 42
|
||||
#define TARGET_NR_times 43
|
||||
#define TARGET_NR_prof 44
|
||||
#define TARGET_NR_brk 45
|
||||
#define TARGET_NR_setgid 46
|
||||
#define TARGET_NR_getgid 47
|
||||
#define TARGET_NR_signal 48
|
||||
#define TARGET_NR_geteuid 49
|
||||
#define TARGET_NR_getegid 50
|
||||
#define TARGET_NR_acct 51
|
||||
#define TARGET_NR_umount2 52
|
||||
#define TARGET_NR_lock 53
|
||||
#define TARGET_NR_ioctl 54
|
||||
#define TARGET_NR_fcntl 55
|
||||
#define TARGET_NR_mpx 56
|
||||
#define TARGET_NR_setpgid 57
|
||||
#define TARGET_NR_ulimit 58
|
||||
#define TARGET_NR_oldolduname 59
|
||||
#define TARGET_NR_umask 60
|
||||
#define TARGET_NR_chroot 61
|
||||
#define TARGET_NR_ustat 62
|
||||
#define TARGET_NR_dup2 63
|
||||
#define TARGET_NR_getppid 64
|
||||
#define TARGET_NR_getpgrp 65
|
||||
#define TARGET_NR_setsid 66
|
||||
#define TARGET_NR_sigaction 67
|
||||
#define TARGET_NR_sgetmask 68
|
||||
#define TARGET_NR_ssetmask 69
|
||||
#define TARGET_NR_setreuid 70
|
||||
#define TARGET_NR_setregid 71
|
||||
#define TARGET_NR_sigsuspend 72
|
||||
#define TARGET_NR_sigpending 73
|
||||
#define TARGET_NR_sethostname 74
|
||||
#define TARGET_NR_setrlimit 75
|
||||
#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
|
||||
#define TARGET_NR_getrusage 77
|
||||
#define TARGET_NR_gettimeofday 78
|
||||
#define TARGET_NR_settimeofday 79
|
||||
#define TARGET_NR_getgroups 80
|
||||
#define TARGET_NR_setgroups 81
|
||||
#define TARGET_NR_select 82
|
||||
#define TARGET_NR_symlink 83
|
||||
#define TARGET_NR_oldlstat 84
|
||||
#define TARGET_NR_readlink 85
|
||||
#define TARGET_NR_uselib 86
|
||||
#define TARGET_NR_swapon 87
|
||||
#define TARGET_NR_reboot 88
|
||||
#define TARGET_NR_readdir 89
|
||||
#define TARGET_NR_mmap 90
|
||||
#define TARGET_NR_munmap 91
|
||||
#define TARGET_NR_truncate 92
|
||||
#define TARGET_NR_ftruncate 93
|
||||
#define TARGET_NR_fchmod 94
|
||||
#define TARGET_NR_fchown 95
|
||||
#define TARGET_NR_getpriority 96
|
||||
#define TARGET_NR_setpriority 97
|
||||
#define TARGET_NR_profil 98
|
||||
#define TARGET_NR_statfs 99
|
||||
#define TARGET_NR_fstatfs 100
|
||||
#define TARGET_NR_ioperm 101
|
||||
#define TARGET_NR_socketcall 102
|
||||
#define TARGET_NR_syslog 103
|
||||
#define TARGET_NR_setitimer 104
|
||||
#define TARGET_NR_getitimer 105
|
||||
#define TARGET_NR_stat 106
|
||||
#define TARGET_NR_lstat 107
|
||||
#define TARGET_NR_fstat 108
|
||||
#define TARGET_NR_olduname 109
|
||||
#define TARGET_NR_iopl 110
|
||||
#define TARGET_NR_vhangup 111
|
||||
#define TARGET_NR_idle 112
|
||||
#define TARGET_NR_vm86old 113
|
||||
#define TARGET_NR_wait4 114
|
||||
#define TARGET_NR_swapoff 115
|
||||
#define TARGET_NR_sysinfo 116
|
||||
#define TARGET_NR_ipc 117
|
||||
#define TARGET_NR_fsync 118
|
||||
#define TARGET_NR_sigreturn 119
|
||||
#define TARGET_NR_clone 120
|
||||
#define TARGET_NR_setdomainname 121
|
||||
#define TARGET_NR_uname 122
|
||||
#define TARGET_NR_modify_ldt 123
|
||||
#define TARGET_NR_adjtimex 124
|
||||
#define TARGET_NR_mprotect 125
|
||||
#define TARGET_NR_sigprocmask 126
|
||||
#define TARGET_NR_create_module 127
|
||||
#define TARGET_NR_init_module 128
|
||||
#define TARGET_NR_delete_module 129
|
||||
#define TARGET_NR_get_kernel_syms 130
|
||||
#define TARGET_NR_quotactl 131
|
||||
#define TARGET_NR_getpgid 132
|
||||
#define TARGET_NR_fchdir 133
|
||||
#define TARGET_NR_bdflush 134
|
||||
#define TARGET_NR_sysfs 135
|
||||
#define TARGET_NR_personality 136
|
||||
#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
|
||||
#define TARGET_NR_setfsuid 138
|
||||
#define TARGET_NR_setfsgid 139
|
||||
#define TARGET_NR__llseek 140
|
||||
#define TARGET_NR_getdents 141
|
||||
#define TARGET_NR__newselect 142
|
||||
#define TARGET_NR_flock 143
|
||||
#define TARGET_NR_msync 144
|
||||
#define TARGET_NR_readv 145
|
||||
#define TARGET_NR_writev 146
|
||||
#define TARGET_NR_getsid 147
|
||||
#define TARGET_NR_fdatasync 148
|
||||
#define TARGET_NR__sysctl 149
|
||||
#define TARGET_NR_mlock 150
|
||||
#define TARGET_NR_munlock 151
|
||||
#define TARGET_NR_mlockall 152
|
||||
#define TARGET_NR_munlockall 153
|
||||
#define TARGET_NR_sched_setparam 154
|
||||
#define TARGET_NR_sched_getparam 155
|
||||
#define TARGET_NR_sched_setscheduler 156
|
||||
#define TARGET_NR_sched_getscheduler 157
|
||||
#define TARGET_NR_sched_yield 158
|
||||
#define TARGET_NR_sched_get_priority_max 159
|
||||
#define TARGET_NR_sched_get_priority_min 160
|
||||
#define TARGET_NR_sched_rr_get_interval 161
|
||||
#define TARGET_NR_nanosleep 162
|
||||
#define TARGET_NR_mremap 163
|
||||
#define TARGET_NR_setresuid 164
|
||||
#define TARGET_NR_getresuid 165
|
||||
#define TARGET_NR_vm86 166
|
||||
#define TARGET_NR_query_module 167
|
||||
#define TARGET_NR_poll 168
|
||||
#define TARGET_NR_nfsservctl 169
|
||||
#define TARGET_NR_setresgid 170
|
||||
#define TARGET_NR_getresgid 171
|
||||
#define TARGET_NR_prctl 172
|
||||
#define TARGET_NR_rt_sigreturn 173
|
||||
#define TARGET_NR_rt_sigaction 174
|
||||
#define TARGET_NR_rt_sigprocmask 175
|
||||
#define TARGET_NR_rt_sigpending 176
|
||||
#define TARGET_NR_rt_sigtimedwait 177
|
||||
#define TARGET_NR_rt_sigqueueinfo 178
|
||||
#define TARGET_NR_rt_sigsuspend 179
|
||||
#define TARGET_NR_pread 180
|
||||
#define TARGET_NR_pwrite 181
|
||||
#define TARGET_NR_chown 182
|
||||
#define TARGET_NR_getcwd 183
|
||||
#define TARGET_NR_capget 184
|
||||
#define TARGET_NR_capset 185
|
||||
#define TARGET_NR_sigaltstack 186
|
||||
#define TARGET_NR_sendfile 187
|
||||
#define TARGET_NR_getpmsg 188 /* some people actually want streams */
|
||||
#define TARGET_NR_putpmsg 189 /* some people actually want streams */
|
||||
#define TARGET_NR_vfork 190
|
||||
#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */
|
||||
#define TARGET_NR_mmap2 192
|
||||
#define TARGET_NR_truncate64 193
|
||||
#define TARGET_NR_ftruncate64 194
|
||||
#define TARGET_NR_stat64 195
|
||||
#define TARGET_NR_lstat64 196
|
||||
#define TARGET_NR_fstat64 197
|
||||
#define TARGET_NR_lchown32 198
|
||||
#define TARGET_NR_getuid32 199
|
||||
#define TARGET_NR_getgid32 200
|
||||
#define TARGET_NR_geteuid32 201
|
||||
#define TARGET_NR_getegid32 202
|
||||
#define TARGET_NR_setreuid32 203
|
||||
#define TARGET_NR_setregid32 204
|
||||
#define TARGET_NR_getgroups32 205
|
||||
#define TARGET_NR_setgroups32 206
|
||||
#define TARGET_NR_fchown32 207
|
||||
#define TARGET_NR_setresuid32 208
|
||||
#define TARGET_NR_getresuid32 209
|
||||
#define TARGET_NR_setresgid32 210
|
||||
#define TARGET_NR_getresgid32 211
|
||||
#define TARGET_NR_chown32 212
|
||||
#define TARGET_NR_setuid32 213
|
||||
#define TARGET_NR_setgid32 214
|
||||
#define TARGET_NR_setfsuid32 215
|
||||
#define TARGET_NR_setfsgid32 216
|
||||
#define TARGET_NR_pivot_root 217
|
||||
#define TARGET_NR_mincore 218
|
||||
#define TARGET_NR_madvise 219
|
||||
#define TARGET_NR_madvise1 219 /* delete when C lib stub is removed */
|
||||
#define TARGET_NR_getdents64 220
|
||||
#define TARGET_NR_fcntl64 221
|
||||
#define TARGET_NR_security 223 /* syscall for security modules */
|
||||
#define TARGET_NR_gettid 224
|
||||
#define TARGET_NR_readahead 225
|
||||
#define TARGET_NR_setxattr 226
|
||||
#define TARGET_NR_lsetxattr 227
|
||||
#define TARGET_NR_fsetxattr 228
|
||||
#define TARGET_NR_getxattr 229
|
||||
#define TARGET_NR_lgetxattr 230
|
||||
#define TARGET_NR_fgetxattr 231
|
||||
#define TARGET_NR_listxattr 232
|
||||
#define TARGET_NR_llistxattr 233
|
||||
#define TARGET_NR_flistxattr 234
|
||||
#define TARGET_NR_removexattr 235
|
||||
#define TARGET_NR_lremovexattr 236
|
||||
#define TARGET_NR_fremovexattr 237
|
||||
#define TARGET_NR_tkill 238
|
||||
#define TARGET_NR_sendfile64 239
|
||||
#define TARGET_NR_futex 240
|
||||
#define TARGET_NR_sched_setaffinity 241
|
||||
#define TARGET_NR_sched_getaffinity 242
|
||||
#define TARGET_NR_set_thread_area 243
|
||||
#define TARGET_NR_get_thread_area 244
|
||||
#define TARGET_NR_io_setup 245
|
||||
#define TARGET_NR_io_destroy 246
|
||||
#define TARGET_NR_io_getevents 247
|
||||
#define TARGET_NR_io_submit 248
|
||||
#define TARGET_NR_io_cancel 249
|
||||
#define TARGET_NR_fadvise64 250
|
||||
|
||||
#define TARGET_NR_exit_group 252
|
||||
#define TARGET_NR_lookup_dcookie 253
|
||||
#define TARGET_NR_epoll_create 254
|
||||
#define TARGET_NR_epoll_ctl 255
|
||||
#define TARGET_NR_epoll_wait 256
|
||||
#define TARGET_NR_remap_file_pages 257
|
||||
#define TARGET_NR_set_tid_address 258
|
||||
#define TARGET_NR_timer_create 259
|
||||
#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1)
|
||||
#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2)
|
||||
#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3)
|
||||
#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4)
|
||||
#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5)
|
||||
#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6)
|
||||
#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7)
|
||||
#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8)
|
||||
|
||||
#define TARGET_SIG_BLOCK 0 /* for blocking signals */
|
||||
#define TARGET_SIG_UNBLOCK 1 /* for unblocking signals */
|
||||
#define TARGET_SIG_SETMASK 2 /* for setting the signal mask */
|
||||
|
||||
struct target_stat {
|
||||
unsigned short st_dev;
|
||||
unsigned short __pad1;
|
||||
target_ulong st_ino;
|
||||
unsigned short st_mode;
|
||||
unsigned short st_nlink;
|
||||
unsigned short st_uid;
|
||||
unsigned short st_gid;
|
||||
unsigned short st_rdev;
|
||||
unsigned short __pad2;
|
||||
target_ulong st_size;
|
||||
target_ulong st_blksize;
|
||||
target_ulong st_blocks;
|
||||
target_ulong target_st_atime;
|
||||
target_ulong __unused1;
|
||||
target_ulong target_st_mtime;
|
||||
target_ulong __unused2;
|
||||
target_ulong target_st_ctime;
|
||||
target_ulong __unused3;
|
||||
target_ulong __unused4;
|
||||
target_ulong __unused5;
|
||||
};
|
||||
|
||||
/* This matches struct stat64 in glibc2.1, hence the absolutely
|
||||
* insane amounts of padding around dev_t's.
|
||||
*/
|
||||
struct target_stat64 {
|
||||
unsigned short st_dev;
|
||||
unsigned char __pad0[10];
|
||||
|
||||
#define STAT64_HAS_BROKEN_ST_INO 1
|
||||
target_ulong __st_ino;
|
||||
|
||||
unsigned int st_mode;
|
||||
unsigned int st_nlink;
|
||||
|
||||
target_ulong st_uid;
|
||||
target_ulong st_gid;
|
||||
|
||||
unsigned short st_rdev;
|
||||
unsigned char __pad3[10];
|
||||
|
||||
long long st_size;
|
||||
target_ulong st_blksize;
|
||||
|
||||
target_ulong st_blocks; /* Number 512-byte blocks allocated. */
|
||||
target_ulong __pad4; /* future possible st_blocks high bits */
|
||||
|
||||
target_ulong target_st_atime;
|
||||
target_ulong __pad5;
|
||||
|
||||
target_ulong target_st_mtime;
|
||||
target_ulong __pad6;
|
||||
|
||||
target_ulong target_st_ctime;
|
||||
target_ulong __pad7; /* will be high 32 bits of ctime someday */
|
||||
|
||||
unsigned long long st_ino;
|
||||
};
|
||||
|
||||
#define TARGET_SA_NOCLDSTOP 0x00000001
|
||||
#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */
|
||||
#define TARGET_SA_SIGINFO 0x00000004
|
||||
#define TARGET_SA_ONSTACK 0x08000000
|
||||
#define TARGET_SA_RESTART 0x10000000
|
||||
#define TARGET_SA_NODEFER 0x40000000
|
||||
#define TARGET_SA_RESETHAND 0x80000000
|
||||
#define TARGET_SA_RESTORER 0x04000000
|
||||
|
||||
#define TARGET_SIGHUP 1
|
||||
#define TARGET_SIGINT 2
|
||||
#define TARGET_SIGQUIT 3
|
||||
#define TARGET_SIGILL 4
|
||||
#define TARGET_SIGTRAP 5
|
||||
#define TARGET_SIGABRT 6
|
||||
#define TARGET_SIGIOT 6
|
||||
#define TARGET_SIGBUS 7
|
||||
#define TARGET_SIGFPE 8
|
||||
#define TARGET_SIGKILL 9
|
||||
#define TARGET_SIGUSR1 10
|
||||
#define TARGET_SIGSEGV 11
|
||||
#define TARGET_SIGUSR2 12
|
||||
#define TARGET_SIGPIPE 13
|
||||
#define TARGET_SIGALRM 14
|
||||
#define TARGET_SIGTERM 15
|
||||
#define TARGET_SIGSTKFLT 16
|
||||
#define TARGET_SIGCHLD 17
|
||||
#define TARGET_SIGCONT 18
|
||||
#define TARGET_SIGSTOP 19
|
||||
#define TARGET_SIGTSTP 20
|
||||
#define TARGET_SIGTTIN 21
|
||||
#define TARGET_SIGTTOU 22
|
||||
#define TARGET_SIGURG 23
|
||||
#define TARGET_SIGXCPU 24
|
||||
#define TARGET_SIGXFSZ 25
|
||||
#define TARGET_SIGVTALRM 26
|
||||
#define TARGET_SIGPROF 27
|
||||
#define TARGET_SIGWINCH 28
|
||||
#define TARGET_SIGIO 29
|
||||
#define TARGET_SIGRTMIN 32
|
||||
|
||||
struct target_old_sigaction {
|
||||
target_ulong _sa_handler;
|
||||
target_ulong sa_mask;
|
||||
target_ulong sa_flags;
|
||||
target_ulong sa_restorer;
|
||||
};
|
||||
|
||||
struct target_sigaction {
|
||||
target_ulong _sa_handler;
|
||||
target_ulong sa_flags;
|
||||
target_ulong sa_restorer;
|
||||
target_sigset_t sa_mask;
|
||||
};
|
||||
|
||||
typedef union target_sigval {
|
||||
int sival_int;
|
||||
target_ulong sival_ptr;
|
||||
} target_sigval_t;
|
||||
|
||||
#define TARGET_SI_MAX_SIZE 128
|
||||
#define TARGET_SI_PAD_SIZE ((TARGET_SI_MAX_SIZE/sizeof(int)) - 3)
|
||||
|
||||
typedef struct target_siginfo {
|
||||
int si_signo;
|
||||
int si_errno;
|
||||
int si_code;
|
||||
|
||||
union {
|
||||
int _pad[TARGET_SI_PAD_SIZE];
|
||||
|
||||
/* kill() */
|
||||
struct {
|
||||
pid_t _pid; /* sender's pid */
|
||||
uid_t _uid; /* sender's uid */
|
||||
} _kill;
|
||||
|
||||
/* POSIX.1b timers */
|
||||
struct {
|
||||
unsigned int _timer1;
|
||||
unsigned int _timer2;
|
||||
} _timer;
|
||||
|
||||
/* POSIX.1b signals */
|
||||
struct {
|
||||
pid_t _pid; /* sender's pid */
|
||||
uid_t _uid; /* sender's uid */
|
||||
target_sigval_t _sigval;
|
||||
} _rt;
|
||||
|
||||
/* SIGCHLD */
|
||||
struct {
|
||||
pid_t _pid; /* which child */
|
||||
uid_t _uid; /* sender's uid */
|
||||
int _status; /* exit code */
|
||||
target_clock_t _utime;
|
||||
target_clock_t _stime;
|
||||
} _sigchld;
|
||||
|
||||
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
|
||||
struct {
|
||||
target_ulong _addr; /* faulting insn/memory ref. */
|
||||
} _sigfault;
|
||||
|
||||
/* SIGPOLL */
|
||||
struct {
|
||||
int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
|
||||
int _fd;
|
||||
} _sigpoll;
|
||||
} _sifields;
|
||||
} target_siginfo_t;
|
||||
|
||||
/*
|
||||
* SIGILL si_codes
|
||||
*/
|
||||
#define TARGET_ILL_ILLOPN (2) /* illegal operand */
|
||||
|
||||
/*
|
||||
* SIGFPE si_codes
|
||||
*/
|
||||
#define TARGET_FPE_INTDIV (1) /* integer divide by zero */
|
||||
#define TARGET_FPE_INTOVF (2) /* integer overflow */
|
||||
#define TARGET_FPE_FLTDIV (3) /* floating point divide by zero */
|
||||
#define TARGET_FPE_FLTOVF (4) /* floating point overflow */
|
||||
#define TARGET_FPE_FLTUND (5) /* floating point underflow */
|
||||
#define TARGET_FPE_FLTRES (6) /* floating point inexact result */
|
||||
#define TARGET_FPE_FLTINV (7) /* floating point invalid operation */
|
||||
#define TARGET_FPE_FLTSUB (8) /* subscript out of range */
|
||||
#define TARGET_NSIGFPE 8
|
||||
|
||||
/* default linux values for the selectors */
|
||||
#define __USER_CS (0x23)
|
||||
#define __USER_DS (0x2B)
|
||||
@@ -486,261 +22,6 @@ struct target_pt_regs {
|
||||
|
||||
/* ioctls */
|
||||
|
||||
/*
|
||||
* The following is for compatibility across the various Linux
|
||||
* platforms. The i386 ioctl numbering scheme doesn't really enforce
|
||||
* a type field. De facto, however, the top 8 bits of the lower 16
|
||||
* bits are indeed used as a type field, so we might just as well make
|
||||
* this explicit here. Please be sure to use the decoding macros
|
||||
* below from now on.
|
||||
*/
|
||||
#define TARGET_IOC_NRBITS 8
|
||||
#define TARGET_IOC_TYPEBITS 8
|
||||
#define TARGET_IOC_SIZEBITS 14
|
||||
#define TARGET_IOC_DIRBITS 2
|
||||
|
||||
#define TARGET_IOC_NRMASK ((1 << TARGET_IOC_NRBITS)-1)
|
||||
#define TARGET_IOC_TYPEMASK ((1 << TARGET_IOC_TYPEBITS)-1)
|
||||
#define TARGET_IOC_SIZEMASK ((1 << TARGET_IOC_SIZEBITS)-1)
|
||||
#define TARGET_IOC_DIRMASK ((1 << TARGET_IOC_DIRBITS)-1)
|
||||
|
||||
#define TARGET_IOC_NRSHIFT 0
|
||||
#define TARGET_IOC_TYPESHIFT (TARGET_IOC_NRSHIFT+TARGET_IOC_NRBITS)
|
||||
#define TARGET_IOC_SIZESHIFT (TARGET_IOC_TYPESHIFT+TARGET_IOC_TYPEBITS)
|
||||
#define TARGET_IOC_DIRSHIFT (TARGET_IOC_SIZESHIFT+TARGET_IOC_SIZEBITS)
|
||||
|
||||
/*
|
||||
* Direction bits.
|
||||
*/
|
||||
#define TARGET_IOC_NONE 0U
|
||||
#define TARGET_IOC_WRITE 1U
|
||||
#define TARGET_IOC_READ 2U
|
||||
|
||||
#define TARGET_IOC(dir,type,nr,size) \
|
||||
(((dir) << TARGET_IOC_DIRSHIFT) | \
|
||||
((type) << TARGET_IOC_TYPESHIFT) | \
|
||||
((nr) << TARGET_IOC_NRSHIFT) | \
|
||||
((size) << TARGET_IOC_SIZESHIFT))
|
||||
|
||||
/* used to create numbers */
|
||||
#define TARGET_IO(type,nr) TARGET_IOC(TARGET_IOC_NONE,(type),(nr),0)
|
||||
#define TARGET_IOR(type,nr,size) TARGET_IOC(TARGET_IOC_READ,(type),(nr),sizeof(size))
|
||||
#define TARGET_IOW(type,nr,size) TARGET_IOC(TARGET_IOC_WRITE,(type),(nr),sizeof(size))
|
||||
#define TARGET_IOWR(type,nr,size) TARGET_IOC(TARGET_IOC_READ|TARGET_IOC_WRITE,(type),(nr),sizeof(size))
|
||||
|
||||
/* 0x54 is just a magic number to make these relatively unique ('T') */
|
||||
|
||||
#define TARGET_TCGETS 0x5401
|
||||
#define TARGET_TCSETS 0x5402
|
||||
#define TARGET_TCSETSW 0x5403
|
||||
#define TARGET_TCSETSF 0x5404
|
||||
#define TARGET_TCGETA 0x5405
|
||||
#define TARGET_TCSETA 0x5406
|
||||
#define TARGET_TCSETAW 0x5407
|
||||
#define TARGET_TCSETAF 0x5408
|
||||
#define TARGET_TCSBRK 0x5409
|
||||
#define TARGET_TCXONC 0x540A
|
||||
#define TARGET_TCFLSH 0x540B
|
||||
#define TARGET_TIOCEXCL 0x540C
|
||||
#define TARGET_TIOCNXCL 0x540D
|
||||
#define TARGET_TIOCSCTTY 0x540E
|
||||
#define TARGET_TIOCGPGRP 0x540F
|
||||
#define TARGET_TIOCSPGRP 0x5410
|
||||
#define TARGET_TIOCOUTQ 0x5411
|
||||
#define TARGET_TIOCSTI 0x5412
|
||||
#define TARGET_TIOCGWINSZ 0x5413
|
||||
#define TARGET_TIOCSWINSZ 0x5414
|
||||
#define TARGET_TIOCMGET 0x5415
|
||||
#define TARGET_TIOCMBIS 0x5416
|
||||
#define TARGET_TIOCMBIC 0x5417
|
||||
#define TARGET_TIOCMSET 0x5418
|
||||
#define TARGET_TIOCGSOFTCAR 0x5419
|
||||
#define TARGET_TIOCSSOFTCAR 0x541A
|
||||
#define TARGET_FIONREAD 0x541B
|
||||
#define TARGET_TIOCINQ FIONREAD
|
||||
#define TARGET_TIOCLINUX 0x541C
|
||||
#define TARGET_TIOCCONS 0x541D
|
||||
#define TARGET_TIOCGSERIAL 0x541E
|
||||
#define TARGET_TIOCSSERIAL 0x541F
|
||||
#define TARGET_TIOCPKT 0x5420
|
||||
#define TARGET_FIONBIO 0x5421
|
||||
#define TARGET_TIOCNOTTY 0x5422
|
||||
#define TARGET_TIOCSETD 0x5423
|
||||
#define TARGET_TIOCGETD 0x5424
|
||||
#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
|
||||
#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
|
||||
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
|
||||
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
|
||||
#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
|
||||
#define TARGET_TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
|
||||
#define TARGET_TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
|
||||
|
||||
#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
|
||||
#define TARGET_FIOCLEX 0x5451
|
||||
#define TARGET_FIOASYNC 0x5452
|
||||
#define TARGET_TIOCSERCONFIG 0x5453
|
||||
#define TARGET_TIOCSERGWILD 0x5454
|
||||
#define TARGET_TIOCSERSWILD 0x5455
|
||||
#define TARGET_TIOCGLCKTRMIOS 0x5456
|
||||
#define TARGET_TIOCSLCKTRMIOS 0x5457
|
||||
#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
|
||||
#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
|
||||
#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
|
||||
#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
|
||||
|
||||
#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
|
||||
#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
|
||||
#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
|
||||
#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
|
||||
|
||||
/* Used for packet mode */
|
||||
#define TARGET_TIOCPKT_DATA 0
|
||||
#define TARGET_TIOCPKT_FLUSHREAD 1
|
||||
#define TARGET_TIOCPKT_FLUSHWRITE 2
|
||||
#define TARGET_TIOCPKT_STOP 4
|
||||
#define TARGET_TIOCPKT_START 8
|
||||
#define TARGET_TIOCPKT_NOSTOP 16
|
||||
#define TARGET_TIOCPKT_DOSTOP 32
|
||||
|
||||
#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
|
||||
|
||||
/* from asm/termbits.h */
|
||||
|
||||
#define TARGET_NCCS 19
|
||||
|
||||
struct target_termios {
|
||||
unsigned int c_iflag; /* input mode flags */
|
||||
unsigned int c_oflag; /* output mode flags */
|
||||
unsigned int c_cflag; /* control mode flags */
|
||||
unsigned int c_lflag; /* local mode flags */
|
||||
unsigned char c_line; /* line discipline */
|
||||
unsigned char c_cc[TARGET_NCCS]; /* control characters */
|
||||
};
|
||||
|
||||
/* c_iflag bits */
|
||||
#define TARGET_IGNBRK 0000001
|
||||
#define TARGET_BRKINT 0000002
|
||||
#define TARGET_IGNPAR 0000004
|
||||
#define TARGET_PARMRK 0000010
|
||||
#define TARGET_INPCK 0000020
|
||||
#define TARGET_ISTRIP 0000040
|
||||
#define TARGET_INLCR 0000100
|
||||
#define TARGET_IGNCR 0000200
|
||||
#define TARGET_ICRNL 0000400
|
||||
#define TARGET_IUCLC 0001000
|
||||
#define TARGET_IXON 0002000
|
||||
#define TARGET_IXANY 0004000
|
||||
#define TARGET_IXOFF 0010000
|
||||
#define TARGET_IMAXBEL 0020000
|
||||
|
||||
/* c_oflag bits */
|
||||
#define TARGET_OPOST 0000001
|
||||
#define TARGET_OLCUC 0000002
|
||||
#define TARGET_ONLCR 0000004
|
||||
#define TARGET_OCRNL 0000010
|
||||
#define TARGET_ONOCR 0000020
|
||||
#define TARGET_ONLRET 0000040
|
||||
#define TARGET_OFILL 0000100
|
||||
#define TARGET_OFDEL 0000200
|
||||
#define TARGET_NLDLY 0000400
|
||||
#define TARGET_NL0 0000000
|
||||
#define TARGET_NL1 0000400
|
||||
#define TARGET_CRDLY 0003000
|
||||
#define TARGET_CR0 0000000
|
||||
#define TARGET_CR1 0001000
|
||||
#define TARGET_CR2 0002000
|
||||
#define TARGET_CR3 0003000
|
||||
#define TARGET_TABDLY 0014000
|
||||
#define TARGET_TAB0 0000000
|
||||
#define TARGET_TAB1 0004000
|
||||
#define TARGET_TAB2 0010000
|
||||
#define TARGET_TAB3 0014000
|
||||
#define TARGET_XTABS 0014000
|
||||
#define TARGET_BSDLY 0020000
|
||||
#define TARGET_BS0 0000000
|
||||
#define TARGET_BS1 0020000
|
||||
#define TARGET_VTDLY 0040000
|
||||
#define TARGET_VT0 0000000
|
||||
#define TARGET_VT1 0040000
|
||||
#define TARGET_FFDLY 0100000
|
||||
#define TARGET_FF0 0000000
|
||||
#define TARGET_FF1 0100000
|
||||
|
||||
/* c_cflag bit meaning */
|
||||
#define TARGET_CBAUD 0010017
|
||||
#define TARGET_B0 0000000 /* hang up */
|
||||
#define TARGET_B50 0000001
|
||||
#define TARGET_B75 0000002
|
||||
#define TARGET_B110 0000003
|
||||
#define TARGET_B134 0000004
|
||||
#define TARGET_B150 0000005
|
||||
#define TARGET_B200 0000006
|
||||
#define TARGET_B300 0000007
|
||||
#define TARGET_B600 0000010
|
||||
#define TARGET_B1200 0000011
|
||||
#define TARGET_B1800 0000012
|
||||
#define TARGET_B2400 0000013
|
||||
#define TARGET_B4800 0000014
|
||||
#define TARGET_B9600 0000015
|
||||
#define TARGET_B19200 0000016
|
||||
#define TARGET_B38400 0000017
|
||||
#define TARGET_EXTA B19200
|
||||
#define TARGET_EXTB B38400
|
||||
#define TARGET_CSIZE 0000060
|
||||
#define TARGET_CS5 0000000
|
||||
#define TARGET_CS6 0000020
|
||||
#define TARGET_CS7 0000040
|
||||
#define TARGET_CS8 0000060
|
||||
#define TARGET_CSTOPB 0000100
|
||||
#define TARGET_CREAD 0000200
|
||||
#define TARGET_PARENB 0000400
|
||||
#define TARGET_PARODD 0001000
|
||||
#define TARGET_HUPCL 0002000
|
||||
#define TARGET_CLOCAL 0004000
|
||||
#define TARGET_CBAUDEX 0010000
|
||||
#define TARGET_B57600 0010001
|
||||
#define TARGET_B115200 0010002
|
||||
#define TARGET_B230400 0010003
|
||||
#define TARGET_B460800 0010004
|
||||
#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */
|
||||
#define TARGET_CRTSCTS 020000000000 /* flow control */
|
||||
|
||||
/* c_lflag bits */
|
||||
#define TARGET_ISIG 0000001
|
||||
#define TARGET_ICANON 0000002
|
||||
#define TARGET_XCASE 0000004
|
||||
#define TARGET_ECHO 0000010
|
||||
#define TARGET_ECHOE 0000020
|
||||
#define TARGET_ECHOK 0000040
|
||||
#define TARGET_ECHONL 0000100
|
||||
#define TARGET_NOFLSH 0000200
|
||||
#define TARGET_TOSTOP 0000400
|
||||
#define TARGET_ECHOCTL 0001000
|
||||
#define TARGET_ECHOPRT 0002000
|
||||
#define TARGET_ECHOKE 0004000
|
||||
#define TARGET_FLUSHO 0010000
|
||||
#define TARGET_PENDIN 0040000
|
||||
#define TARGET_IEXTEN 0100000
|
||||
|
||||
/* c_cc character offsets */
|
||||
#define TARGET_VINTR 0
|
||||
#define TARGET_VQUIT 1
|
||||
#define TARGET_VERASE 2
|
||||
#define TARGET_VKILL 3
|
||||
#define TARGET_VEOF 4
|
||||
#define TARGET_VTIME 5
|
||||
#define TARGET_VMIN 6
|
||||
#define TARGET_VSWTC 7
|
||||
#define TARGET_VSTART 8
|
||||
#define TARGET_VSTOP 9
|
||||
#define TARGET_VSUSP 10
|
||||
#define TARGET_VEOL 11
|
||||
#define TARGET_VREPRINT 12
|
||||
#define TARGET_VDISCARD 13
|
||||
#define TARGET_VWERASE 14
|
||||
#define TARGET_VLNEXT 15
|
||||
#define TARGET_VEOL2 16
|
||||
|
||||
#define TARGET_LDT_ENTRIES 8192
|
||||
#define TARGET_LDT_ENTRY_SIZE 8
|
||||
|
||||
@@ -755,11 +36,17 @@ struct target_modify_ldt_ldt_s {
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
|
||||
/* vm86 defines */
|
||||
|
||||
#define TARGET_BIOSSEG 0x0f000
|
||||
|
||||
#define TARGET_CPU_086 0
|
||||
#define TARGET_CPU_186 1
|
||||
#define TARGET_CPU_286 2
|
||||
#define TARGET_CPU_386 3
|
||||
#define TARGET_CPU_486 4
|
||||
#define TARGET_CPU_586 5
|
||||
|
||||
#define TARGET_VM86_SIGNAL 0 /* return due to signal */
|
||||
#define TARGET_VM86_UNKNOWN 1 /* unhandled GP fault - IO-instruction or similar */
|
||||
#define TARGET_VM86_INTx 2 /* int3/int x instruction (ARG = x) */
|
||||
@@ -879,11 +166,6 @@ struct target_ipc_kludge {
|
||||
int msgtyp;
|
||||
};
|
||||
|
||||
struct alpha_msgbuf {
|
||||
long mtype;
|
||||
char mtext[4096];
|
||||
};
|
||||
|
||||
struct target_ipc_perm {
|
||||
int key;
|
||||
unsigned short uid;
|
||||
@@ -936,134 +218,3 @@ union target_semun {
|
||||
unsigned int __pad; /* really void* */
|
||||
};
|
||||
|
||||
/* soundcard defines (XXX: move them to generic file syscall_defs.h) */
|
||||
|
||||
#define TARGET_SNDCTL_COPR_HALT 0xc0144307
|
||||
#define TARGET_SNDCTL_COPR_LOAD 0xcfb04301
|
||||
#define TARGET_SNDCTL_COPR_RCODE 0xc0144303
|
||||
#define TARGET_SNDCTL_COPR_RCVMSG 0x8fa44309
|
||||
#define TARGET_SNDCTL_COPR_RDATA 0xc0144302
|
||||
#define TARGET_SNDCTL_COPR_RESET 0x00004300
|
||||
#define TARGET_SNDCTL_COPR_RUN 0xc0144306
|
||||
#define TARGET_SNDCTL_COPR_SENDMSG 0xcfa44308
|
||||
#define TARGET_SNDCTL_COPR_WCODE 0x40144305
|
||||
#define TARGET_SNDCTL_COPR_WDATA 0x40144304
|
||||
#define TARGET_SNDCTL_DSP_CHANNELS 0xc0045006
|
||||
#define TARGET_SNDCTL_DSP_GETBLKSIZE 0xc0045004
|
||||
#define TARGET_SNDCTL_DSP_GETCAPS 0x8004500f
|
||||
#define TARGET_SNDCTL_DSP_GETFMTS 0x8004500b
|
||||
#define TARGET_SNDCTL_DSP_GETIPTR 0x800c5011
|
||||
#define TARGET_SNDCTL_DSP_GETISPACE 0x8010500d
|
||||
#define TARGET_SNDCTL_DSP_GETOPTR 0x800c5012
|
||||
#define TARGET_SNDCTL_DSP_GETOSPACE 0x8010500c
|
||||
#define TARGET_SNDCTL_DSP_GETTRIGGER 0x80045010
|
||||
#define TARGET_SNDCTL_DSP_MAPINBUF 0x80085013
|
||||
#define TARGET_SNDCTL_DSP_MAPOUTBUF 0x80085014
|
||||
#define TARGET_SNDCTL_DSP_NONBLOCK 0x0000500e
|
||||
#define TARGET_SNDCTL_DSP_POST 0x00005008
|
||||
#define TARGET_SNDCTL_DSP_RESET 0x00005000
|
||||
#define TARGET_SNDCTL_DSP_SAMPLESIZE 0xc0045005
|
||||
#define TARGET_SNDCTL_DSP_SETDUPLEX 0x00005016
|
||||
#define TARGET_SNDCTL_DSP_SETFMT 0xc0045005
|
||||
#define TARGET_SNDCTL_DSP_SETFRAGMENT 0xc004500a
|
||||
#define TARGET_SNDCTL_DSP_SETSYNCRO 0x00005015
|
||||
#define TARGET_SNDCTL_DSP_SETTRIGGER 0x40045010
|
||||
#define TARGET_SNDCTL_DSP_SPEED 0xc0045002
|
||||
#define TARGET_SNDCTL_DSP_STEREO 0xc0045003
|
||||
#define TARGET_SNDCTL_DSP_SUBDIVIDE 0xc0045009
|
||||
#define TARGET_SNDCTL_DSP_SYNC 0x00005001
|
||||
#define TARGET_SNDCTL_FM_4OP_ENABLE 0x4004510f
|
||||
#define TARGET_SNDCTL_FM_LOAD_INSTR 0x40285107
|
||||
#define TARGET_SNDCTL_MIDI_INFO 0xc074510c
|
||||
#define TARGET_SNDCTL_MIDI_MPUCMD 0xc0216d02
|
||||
#define TARGET_SNDCTL_MIDI_MPUMODE 0xc0046d01
|
||||
#define TARGET_SNDCTL_MIDI_PRETIME 0xc0046d00
|
||||
#define TARGET_SNDCTL_PMGR_ACCESS 0xcfb85110
|
||||
#define TARGET_SNDCTL_PMGR_IFACE 0xcfb85001
|
||||
#define TARGET_SNDCTL_SEQ_CTRLRATE 0xc0045103
|
||||
#define TARGET_SNDCTL_SEQ_GETINCOUNT 0x80045105
|
||||
#define TARGET_SNDCTL_SEQ_GETOUTCOUNT 0x80045104
|
||||
#define TARGET_SNDCTL_SEQ_NRMIDIS 0x8004510b
|
||||
#define TARGET_SNDCTL_SEQ_NRSYNTHS 0x8004510a
|
||||
#define TARGET_SNDCTL_SEQ_OUTOFBAND 0x40085112
|
||||
#define TARGET_SNDCTL_SEQ_PANIC 0x00005111
|
||||
#define TARGET_SNDCTL_SEQ_PERCMODE 0x40045106
|
||||
#define TARGET_SNDCTL_SEQ_RESET 0x00005100
|
||||
#define TARGET_SNDCTL_SEQ_RESETSAMPLES 0x40045109
|
||||
#define TARGET_SNDCTL_SEQ_SYNC 0x00005101
|
||||
#define TARGET_SNDCTL_SEQ_TESTMIDI 0x40045108
|
||||
#define TARGET_SNDCTL_SEQ_THRESHOLD 0x4004510d
|
||||
#define TARGET_SNDCTL_SEQ_TRESHOLD 0x4004510d
|
||||
#define TARGET_SNDCTL_SYNTH_INFO 0xc08c5102
|
||||
#define TARGET_SNDCTL_SYNTH_MEMAVL 0xc004510e
|
||||
#define TARGET_SNDCTL_TMR_CONTINUE 0x00005404
|
||||
#define TARGET_SNDCTL_TMR_METRONOME 0x40045407
|
||||
#define TARGET_SNDCTL_TMR_SELECT 0x40045408
|
||||
#define TARGET_SNDCTL_TMR_SOURCE 0xc0045406
|
||||
#define TARGET_SNDCTL_TMR_START 0x00005402
|
||||
#define TARGET_SNDCTL_TMR_STOP 0x00005403
|
||||
#define TARGET_SNDCTL_TMR_TEMPO 0xc0045405
|
||||
#define TARGET_SNDCTL_TMR_TIMEBASE 0xc0045401
|
||||
#define TARGET_SOUND_PCM_WRITE_FILTER 0xc0045007
|
||||
#define TARGET_SOUND_PCM_READ_RATE 0x80045002
|
||||
#define TARGET_SOUND_PCM_READ_CHANNELS 0x80045006
|
||||
#define TARGET_SOUND_PCM_READ_BITS 0x80045005
|
||||
#define TARGET_SOUND_PCM_READ_FILTER 0x80045007
|
||||
#define TARGET_SOUND_MIXER_INFO 0x80304d65
|
||||
#define TARGET_SOUND_MIXER_ACCESS 0xc0804d66
|
||||
#define TARGET_SOUND_MIXER_PRIVATE1 0xc0044d6f
|
||||
#define TARGET_SOUND_MIXER_PRIVATE2 0xc0044d70
|
||||
#define TARGET_SOUND_MIXER_PRIVATE3 0xc0044d71
|
||||
#define TARGET_SOUND_MIXER_PRIVATE4 0xc0044d72
|
||||
#define TARGET_SOUND_MIXER_PRIVATE5 0xc0044d73
|
||||
#define TARGET_SOUND_MIXER_READ_VOLUME 0x80044d00
|
||||
#define TARGET_SOUND_MIXER_READ_BASS 0x80044d01
|
||||
#define TARGET_SOUND_MIXER_READ_TREBLE 0x80044d02
|
||||
#define TARGET_SOUND_MIXER_READ_SYNTH 0x80044d03
|
||||
#define TARGET_SOUND_MIXER_READ_PCM 0x80044d04
|
||||
#define TARGET_SOUND_MIXER_READ_SPEAKER 0x80044d05
|
||||
#define TARGET_SOUND_MIXER_READ_LINE 0x80044d06
|
||||
#define TARGET_SOUND_MIXER_READ_MIC 0x80044d07
|
||||
#define TARGET_SOUND_MIXER_READ_CD 0x80044d08
|
||||
#define TARGET_SOUND_MIXER_READ_IMIX 0x80044d09
|
||||
#define TARGET_SOUND_MIXER_READ_ALTPCM 0x80044d0a
|
||||
#define TARGET_SOUND_MIXER_READ_RECLEV 0x80044d0b
|
||||
#define TARGET_SOUND_MIXER_READ_IGAIN 0x80044d0c
|
||||
#define TARGET_SOUND_MIXER_READ_OGAIN 0x80044d0d
|
||||
#define TARGET_SOUND_MIXER_READ_LINE1 0x80044d0e
|
||||
#define TARGET_SOUND_MIXER_READ_LINE2 0x80044d0f
|
||||
#define TARGET_SOUND_MIXER_READ_LINE3 0x80044d10
|
||||
#define TARGET_SOUND_MIXER_READ_MUTE 0x80044d1f
|
||||
#define TARGET_SOUND_MIXER_READ_ENHANCE 0x80044d1f
|
||||
#define TARGET_SOUND_MIXER_READ_LOUD 0x80044d1f
|
||||
#define TARGET_SOUND_MIXER_READ_RECSRC 0x80044dff
|
||||
#define TARGET_SOUND_MIXER_READ_DEVMASK 0x80044dfe
|
||||
#define TARGET_SOUND_MIXER_READ_RECMASK 0x80044dfd
|
||||
#define TARGET_SOUND_MIXER_READ_STEREODEVS 0x80044dfb
|
||||
#define TARGET_SOUND_MIXER_READ_CAPS 0x80044dfc
|
||||
#define TARGET_SOUND_MIXER_WRITE_VOLUME 0xc0044d00
|
||||
#define TARGET_SOUND_MIXER_WRITE_BASS 0xc0044d01
|
||||
#define TARGET_SOUND_MIXER_WRITE_TREBLE 0xc0044d02
|
||||
#define TARGET_SOUND_MIXER_WRITE_SYNTH 0xc0044d03
|
||||
#define TARGET_SOUND_MIXER_WRITE_PCM 0xc0044d04
|
||||
#define TARGET_SOUND_MIXER_WRITE_SPEAKER 0xc0044d05
|
||||
#define TARGET_SOUND_MIXER_WRITE_LINE 0xc0044d06
|
||||
#define TARGET_SOUND_MIXER_WRITE_MIC 0xc0044d07
|
||||
#define TARGET_SOUND_MIXER_WRITE_CD 0xc0044d08
|
||||
#define TARGET_SOUND_MIXER_WRITE_IMIX 0xc0044d09
|
||||
#define TARGET_SOUND_MIXER_WRITE_ALTPCM 0xc0044d0a
|
||||
#define TARGET_SOUND_MIXER_WRITE_RECLEV 0xc0044d0b
|
||||
#define TARGET_SOUND_MIXER_WRITE_IGAIN 0xc0044d0c
|
||||
#define TARGET_SOUND_MIXER_WRITE_OGAIN 0xc0044d0d
|
||||
#define TARGET_SOUND_MIXER_WRITE_LINE1 0xc0044d0e
|
||||
#define TARGET_SOUND_MIXER_WRITE_LINE2 0xc0044d0f
|
||||
#define TARGET_SOUND_MIXER_WRITE_LINE3 0xc0044d10
|
||||
#define TARGET_SOUND_MIXER_WRITE_MUTE 0xc0044d1f
|
||||
#define TARGET_SOUND_MIXER_WRITE_ENHANCE 0xc0044d1f
|
||||
#define TARGET_SOUND_MIXER_WRITE_LOUD 0xc0044d1f
|
||||
#define TARGET_SOUND_MIXER_WRITE_RECSRC 0xc0044dff
|
||||
|
||||
#define TARGET_VFAT_IOCTL_READDIR_BOTH 0x82187201
|
||||
#define TARGET_VFAT_IOCTL_READDIR_SHORT 0x82187202
|
||||
|
||||
#define TARGET_SIOCATMARK 0x8905
|
||||
@@ -0,0 +1,23 @@
|
||||
gmon.out
|
||||
testsig
|
||||
hello-i386
|
||||
hello-arm
|
||||
sha1.test.c
|
||||
sha1.c
|
||||
test-i386
|
||||
sha1
|
||||
testclone
|
||||
.gdb_history
|
||||
testthread
|
||||
test-i386.s
|
||||
test-i386.ref
|
||||
sha1-i386
|
||||
runcom
|
||||
debug.com
|
||||
test-i386.out
|
||||
speed.txt
|
||||
test-i386.ref.P3
|
||||
pi_10.com
|
||||
test-i386.ref.P4
|
||||
ldso.c
|
||||
test_path
|
||||
+20
-6
@@ -6,15 +6,15 @@ LDFLAGS=
|
||||
ifeq ($(ARCH),i386)
|
||||
TESTS=testclone testsig testthread sha1-i386 test-i386 runcom
|
||||
endif
|
||||
TESTS+=sha1
|
||||
TESTS+=sha1 test_path
|
||||
|
||||
QEMU=../qemu
|
||||
|
||||
all: $(TESTS)
|
||||
|
||||
hello: hello.c
|
||||
hello-i386: hello-i386.c
|
||||
$(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
|
||||
strip hello
|
||||
strip $@
|
||||
|
||||
testclone: testclone.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
|
||||
@@ -25,14 +25,21 @@ testsig: testsig.c
|
||||
testthread: testthread.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread
|
||||
|
||||
test_path: test_path.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
|
||||
./$@ || { rm $@; exit 1; }
|
||||
|
||||
# i386 emulation test (test various opcodes) */
|
||||
test-i386: test-i386.c test-i386-code16.S \
|
||||
test-i386: test-i386.c test-i386-code16.S test-i386-vm86.S \
|
||||
test-i386.h test-i386-shift.h test-i386-muldiv.h
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ test-i386.c test-i386-code16.S -lm
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ test-i386.c \
|
||||
test-i386-code16.S test-i386-vm86.S -lm
|
||||
|
||||
test: test-i386
|
||||
ifeq ($(ARCH),i386)
|
||||
test: test-i386
|
||||
./test-i386 > test-i386.ref
|
||||
else
|
||||
test:
|
||||
endif
|
||||
$(QEMU) test-i386 > test-i386.out
|
||||
@if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi
|
||||
@@ -52,5 +59,12 @@ speed: sha1 sha1-i386
|
||||
runcom: runcom.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
||||
# arm test
|
||||
hello-arm: hello-arm.o
|
||||
arm-linux-ld -o $@ $<
|
||||
|
||||
hello-arm.o: hello-arm.c
|
||||
arm-linux-gcc -Wall -g -O2 -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f *~ *.o $(TESTS)
|
||||
@@ -0,0 +1,113 @@
|
||||
#define __NR_SYSCALL_BASE 0x900000
|
||||
#define __NR_exit1 (__NR_SYSCALL_BASE+ 1)
|
||||
#define __NR_write (__NR_SYSCALL_BASE+ 4)
|
||||
|
||||
#define __sys2(x) #x
|
||||
#define __sys1(x) __sys2(x)
|
||||
|
||||
#ifndef __syscall
|
||||
#define __syscall(name) "swi\t" __sys1(__NR_##name) "\n\t"
|
||||
#endif
|
||||
|
||||
#define __syscall_return(type, res) \
|
||||
do { \
|
||||
return (type) (res); \
|
||||
} while (0)
|
||||
|
||||
#define _syscall0(type,name) \
|
||||
type name(void) { \
|
||||
long __res; \
|
||||
__asm__ __volatile__ ( \
|
||||
__syscall(name) \
|
||||
"mov %0,r0" \
|
||||
:"=r" (__res) : : "r0","lr"); \
|
||||
__syscall_return(type,__res); \
|
||||
}
|
||||
|
||||
#define _syscall1(type,name,type1,arg1) \
|
||||
type name(type1 arg1) { \
|
||||
long __res; \
|
||||
__asm__ __volatile__ ( \
|
||||
"mov\tr0,%1\n\t" \
|
||||
__syscall(name) \
|
||||
"mov %0,r0" \
|
||||
: "=r" (__res) \
|
||||
: "r" ((long)(arg1)) \
|
||||
: "r0","lr"); \
|
||||
__syscall_return(type,__res); \
|
||||
}
|
||||
|
||||
#define _syscall2(type,name,type1,arg1,type2,arg2) \
|
||||
type name(type1 arg1,type2 arg2) { \
|
||||
long __res; \
|
||||
__asm__ __volatile__ ( \
|
||||
"mov\tr0,%1\n\t" \
|
||||
"mov\tr1,%2\n\t" \
|
||||
__syscall(name) \
|
||||
"mov\t%0,r0" \
|
||||
: "=r" (__res) \
|
||||
: "r" ((long)(arg1)),"r" ((long)(arg2)) \
|
||||
: "r0","r1","lr"); \
|
||||
__syscall_return(type,__res); \
|
||||
}
|
||||
|
||||
|
||||
#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
|
||||
type name(type1 arg1,type2 arg2,type3 arg3) { \
|
||||
long __res; \
|
||||
__asm__ __volatile__ ( \
|
||||
"mov\tr0,%1\n\t" \
|
||||
"mov\tr1,%2\n\t" \
|
||||
"mov\tr2,%3\n\t" \
|
||||
__syscall(name) \
|
||||
"mov\t%0,r0" \
|
||||
: "=r" (__res) \
|
||||
: "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)) \
|
||||
: "r0","r1","r2","lr"); \
|
||||
__syscall_return(type,__res); \
|
||||
}
|
||||
|
||||
|
||||
#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
|
||||
type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
|
||||
long __res; \
|
||||
__asm__ __volatile__ ( \
|
||||
"mov\tr0,%1\n\t" \
|
||||
"mov\tr1,%2\n\t" \
|
||||
"mov\tr2,%3\n\t" \
|
||||
"mov\tr3,%4\n\t" \
|
||||
__syscall(name) \
|
||||
"mov\t%0,r0" \
|
||||
: "=r" (__res) \
|
||||
: "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4)) \
|
||||
: "r0","r1","r2","r3","lr"); \
|
||||
__syscall_return(type,__res); \
|
||||
}
|
||||
|
||||
|
||||
#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \
|
||||
type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \
|
||||
long __res; \
|
||||
__asm__ __volatile__ ( \
|
||||
"mov\tr0,%1\n\t" \
|
||||
"mov\tr1,%2\n\t" \
|
||||
"mov\tr2,%3\n\t" \
|
||||
"mov\tr3,%4\n\t" \
|
||||
"mov\tr4,%5\n\t" \
|
||||
__syscall(name) \
|
||||
"mov\t%0,r0" \
|
||||
: "=r" (__res) \
|
||||
: "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4)), \
|
||||
"r" ((long)(arg5)) \
|
||||
: "r0","r1","r2","r3","r4","lr"); \
|
||||
__syscall_return(type,__res); \
|
||||
}
|
||||
|
||||
_syscall1(int,exit1,int,status);
|
||||
_syscall3(int,write,int,fd,const char *,buf, int, len);
|
||||
|
||||
void _start(void)
|
||||
{
|
||||
write(1, "Hello World\n", 12);
|
||||
exit1(0);
|
||||
}
|
||||
@@ -19,7 +19,7 @@ extern inline int write(int fd, const char * buf, int len)
|
||||
: "0" (__NR_write),"S" ((long)(fd)),"c" ((long)(buf)),"d" ((long)(len)));
|
||||
}
|
||||
|
||||
void _startup(void)
|
||||
void _start(void)
|
||||
{
|
||||
write(1, "Hello World\n", 12);
|
||||
exit(0);
|
||||
+8
-1
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
@@ -14,6 +15,12 @@
|
||||
|
||||
//#define SIGTEST
|
||||
|
||||
#undef __syscall_return
|
||||
#define __syscall_return(type, res) \
|
||||
do { \
|
||||
return (type) (res); \
|
||||
} while (0)
|
||||
|
||||
_syscall2(int, vm86, int, func, struct vm86plus_struct *, v86)
|
||||
|
||||
#define COM_BASE_ADDR 0x10100
|
||||
@@ -118,7 +125,7 @@ int main(int argc, char **argv)
|
||||
r->es = seg;
|
||||
r->fs = seg;
|
||||
r->gs = seg;
|
||||
r->eflags = (IF_MASK | IOPL_MASK);
|
||||
r->eflags = VIF_MASK;
|
||||
|
||||
/* put return code */
|
||||
set_bit((uint8_t *)&ctx.int_revectored, 0x21);
|
||||
|
||||
@@ -77,4 +77,21 @@ myfunc2:
|
||||
|
||||
|
||||
code16_end:
|
||||
|
||||
|
||||
/* other 32 bits tests */
|
||||
.code32
|
||||
|
||||
.globl func_lret32
|
||||
func_lret32:
|
||||
movl $0x87654321, %eax
|
||||
lret
|
||||
|
||||
.globl func_iret32
|
||||
func_iret32:
|
||||
movl $0xabcd4321, %eax
|
||||
iret
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -108,7 +108,12 @@ void exec_opb(int s0, int s1, int iflags)
|
||||
void exec_op(int s2, int s0, int s1)
|
||||
{
|
||||
exec_opl(s2, s0, s1, 0);
|
||||
#ifdef OP_SHIFTD
|
||||
if (s1 <= 15)
|
||||
exec_opw(s2, s0, s1, 0);
|
||||
#else
|
||||
exec_opw(s2, s0, s1, 0);
|
||||
#endif
|
||||
#ifndef OP_NOBYTE
|
||||
exec_opb(s0, s1, 0);
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
.code16
|
||||
.globl vm86_code_start
|
||||
.globl vm86_code_end
|
||||
|
||||
#define GET_OFFSET(x) ((x) - vm86_code_start + 0x100)
|
||||
|
||||
vm86_code_start:
|
||||
movw $GET_OFFSET(hello_world), %dx
|
||||
movb $0x09, %ah
|
||||
int $0x21
|
||||
|
||||
/* prepare int 0x90 vector */
|
||||
xorw %ax, %ax
|
||||
movw %ax, %es
|
||||
es movw $GET_OFFSET(int90_test), 0x90 * 4
|
||||
es movw %cs, 0x90 * 4 + 2
|
||||
|
||||
/* launch int 0x90 */
|
||||
|
||||
int $0x90
|
||||
|
||||
/* test IF support */
|
||||
movw $GET_OFFSET(IF_msg), %dx
|
||||
movb $0x09, %ah
|
||||
int $0x21
|
||||
|
||||
pushf
|
||||
popw %dx
|
||||
movb $0xff, %ah
|
||||
int $0x21
|
||||
|
||||
cli
|
||||
pushf
|
||||
popw %dx
|
||||
movb $0xff, %ah
|
||||
int $0x21
|
||||
|
||||
sti
|
||||
pushfl
|
||||
popl %edx
|
||||
movb $0xff, %ah
|
||||
int $0x21
|
||||
|
||||
#if 0
|
||||
movw $GET_OFFSET(IF_msg1), %dx
|
||||
movb $0x09, %ah
|
||||
int $0x21
|
||||
|
||||
pushf
|
||||
movw %sp, %bx
|
||||
andw $~0x200, (%bx)
|
||||
popf
|
||||
#else
|
||||
cli
|
||||
#endif
|
||||
|
||||
pushf
|
||||
popw %dx
|
||||
movb $0xff, %ah
|
||||
int $0x21
|
||||
|
||||
pushfl
|
||||
movw %sp, %bx
|
||||
orw $0x200, (%bx)
|
||||
popfl
|
||||
|
||||
pushfl
|
||||
popl %edx
|
||||
movb $0xff, %ah
|
||||
int $0x21
|
||||
|
||||
movb $0x00, %ah
|
||||
int $0x21
|
||||
|
||||
int90_test:
|
||||
pushf
|
||||
pop %dx
|
||||
movb $0xff, %ah
|
||||
int $0x21
|
||||
|
||||
movw %sp, %bx
|
||||
movw 4(%bx), %dx
|
||||
movb $0xff, %ah
|
||||
int $0x21
|
||||
|
||||
movw $GET_OFFSET(int90_msg), %dx
|
||||
movb $0x09, %ah
|
||||
int $0x21
|
||||
iret
|
||||
|
||||
int90_msg:
|
||||
.string "INT90 started\n$"
|
||||
|
||||
hello_world:
|
||||
.string "Hello VM86 world\n$"
|
||||
|
||||
IF_msg:
|
||||
.string "VM86 IF test\n$"
|
||||
|
||||
IF_msg1:
|
||||
.string "If you see a diff here, your Linux kernel is buggy, please update to 2.4.20 kernel\n$"
|
||||
|
||||
vm86_code_end:
|
||||
|
||||
+482
-5
@@ -1,9 +1,17 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
#include <sys/ucontext.h>
|
||||
#include <sys/mman.h>
|
||||
#include <asm/vm86.h>
|
||||
|
||||
#define TEST_CMOV 0
|
||||
#define TEST_CMOV 0
|
||||
#define TEST_FCOMI 0
|
||||
|
||||
#define xglue(x, y) x ## y
|
||||
#define glue(x, y) xglue(x, y)
|
||||
@@ -504,12 +512,28 @@ void test_fcmp(double a, double b)
|
||||
a, b, a > b);
|
||||
printf("(%f<=%f)=%d\n",
|
||||
a, b, a >= b);
|
||||
if (TEST_FCOMI) {
|
||||
unsigned int eflags;
|
||||
/* test f(u)comi instruction */
|
||||
asm("fcomi %2, %1\n"
|
||||
"pushf\n"
|
||||
"pop %0\n"
|
||||
: "=r" (eflags)
|
||||
: "t" (a), "u" (b));
|
||||
printf("fcomi(%f %f)=%08x\n", a, b, eflags & (CC_Z | CC_P | CC_C));
|
||||
}
|
||||
}
|
||||
|
||||
void test_fcvt(double a)
|
||||
{
|
||||
float fa;
|
||||
long double la;
|
||||
int16_t fpuc;
|
||||
int i;
|
||||
int64_t lla;
|
||||
int ia;
|
||||
int16_t wa;
|
||||
double ra;
|
||||
|
||||
fa = a;
|
||||
la = a;
|
||||
@@ -518,9 +542,21 @@ void test_fcvt(double a)
|
||||
printf("a=%016Lx\n", *(long long *)&a);
|
||||
printf("la=%016Lx %04x\n", *(long long *)&la,
|
||||
*(unsigned short *)((char *)(&la) + 8));
|
||||
printf("a=%f floor(a)=%f\n", a, floor(a));
|
||||
printf("a=%f ceil(a)=%f\n", a, ceil(a));
|
||||
printf("a=%f rint(a)=%f\n", a, rint(a));
|
||||
|
||||
/* test all roundings */
|
||||
asm volatile ("fstcw %0" : "=m" (fpuc));
|
||||
for(i=0;i<4;i++) {
|
||||
asm volatile ("fldcw %0" : : "m" ((fpuc & ~0x0c00) | (i << 10)));
|
||||
asm volatile ("fist %0" : "=m" (wa) : "t" (a));
|
||||
asm volatile ("fistl %0" : "=m" (ia) : "t" (a));
|
||||
asm volatile ("fistpll %0" : "=m" (lla) : "t" (a) : "st");
|
||||
asm volatile ("frndint ; fstl %0" : "=m" (ra) : "t" (a));
|
||||
asm volatile ("fldcw %0" : : "m" (fpuc));
|
||||
printf("(short)a = %d\n", wa);
|
||||
printf("(int)a = %d\n", ia);
|
||||
printf("(int64_t)a = %Ld\n", lla);
|
||||
printf("rint(a) = %f\n", ra);
|
||||
}
|
||||
}
|
||||
|
||||
#define TEST(N) \
|
||||
@@ -550,6 +586,57 @@ void test_fbcd(double a)
|
||||
a, bcd[4], bcd[3], bcd[2], bcd[1], bcd[0], b);
|
||||
}
|
||||
|
||||
#define TEST_ENV(env, prefix)\
|
||||
{\
|
||||
memset((env), 0xaa, sizeof(*(env)));\
|
||||
asm("fld1\n"\
|
||||
prefix "fnstenv %1\n"\
|
||||
prefix "fldenv %1\n"\
|
||||
: "=t" (res) : "m" (*(env)));\
|
||||
printf("res=%f\n", res);\
|
||||
printf("fpuc=%04x fpus=%04x fptag=%04x\n",\
|
||||
(env)->fpuc,\
|
||||
(env)->fpus & 0xff00,\
|
||||
(env)->fptag);\
|
||||
memset((env), 0xaa, sizeof(*(env)));\
|
||||
asm("fld1\n"\
|
||||
prefix "fnsave %1\n"\
|
||||
prefix "frstor %1\n"\
|
||||
: "=t" (res) : "m" (*(env)));\
|
||||
printf("res=%f\n", res);\
|
||||
printf("fpuc=%04x fpus=%04x fptag=%04x\n",\
|
||||
(env)->fpuc,\
|
||||
(env)->fpus & 0xff00,\
|
||||
(env)->fptag);\
|
||||
printf("ST(0) = %Lf\n",\
|
||||
(env)->fpregs[0]);\
|
||||
}
|
||||
|
||||
void test_fenv(void)
|
||||
{
|
||||
struct __attribute__((packed)) {
|
||||
uint16_t fpuc;
|
||||
uint16_t dummy1;
|
||||
uint16_t fpus;
|
||||
uint16_t dummy2;
|
||||
uint16_t fptag;
|
||||
uint16_t dummy3;
|
||||
uint32_t ignored[4];
|
||||
long double fpregs[8];
|
||||
} float_env32;
|
||||
struct __attribute__((packed)) {
|
||||
uint16_t fpuc;
|
||||
uint16_t fpus;
|
||||
uint16_t fptag;
|
||||
uint16_t ignored[4];
|
||||
long double fpregs[8];
|
||||
} float_env16;
|
||||
double res;
|
||||
|
||||
TEST_ENV(&float_env16, "data16 ");
|
||||
TEST_ENV(&float_env32, "");
|
||||
}
|
||||
|
||||
void test_floats(void)
|
||||
{
|
||||
test_fops(2, 3);
|
||||
@@ -557,12 +644,16 @@ void test_floats(void)
|
||||
test_fcmp(2, -1);
|
||||
test_fcmp(2, 2);
|
||||
test_fcmp(2, 3);
|
||||
test_fcvt(0.5);
|
||||
test_fcvt(-0.5);
|
||||
test_fcvt(1.0/7.0);
|
||||
test_fcvt(-1.0/9.0);
|
||||
test_fcvt(1e30);
|
||||
test_fcvt(32768);
|
||||
test_fcvt(-1e20);
|
||||
test_fconst();
|
||||
test_fbcd(1234567890123456);
|
||||
test_fbcd(-123451234567890);
|
||||
test_fenv();
|
||||
}
|
||||
|
||||
/**********************************************/
|
||||
@@ -707,6 +798,19 @@ uint8_t seg_data2[4096];
|
||||
|
||||
#define MK_SEL(n) (((n) << 3) | 7)
|
||||
|
||||
#define TEST_LR(op, size, seg, mask)\
|
||||
{\
|
||||
int res, res2;\
|
||||
res = 0x12345678;\
|
||||
asm (op " %" size "2, %" size "0\n" \
|
||||
"movl $0, %1\n"\
|
||||
"jnz 1f\n"\
|
||||
"movl $1, %1\n"\
|
||||
"1:\n"\
|
||||
: "=r" (res), "=r" (res2) : "m" (seg), "0" (res));\
|
||||
printf(op ": Z=%d %08x\n", res2, res & ~(mask));\
|
||||
}
|
||||
|
||||
/* NOTE: we use Linux modify_ldt syscall */
|
||||
void test_segs(void)
|
||||
{
|
||||
@@ -784,6 +888,16 @@ void test_segs(void)
|
||||
: "=r" (res), "=g" (res2)
|
||||
: "m" (segoff));
|
||||
printf("FS:reg = %04x:%08x\n", res2, res);
|
||||
|
||||
TEST_LR("larw", "w", MK_SEL(2), 0x0100);
|
||||
TEST_LR("larl", "", MK_SEL(2), 0x0100);
|
||||
TEST_LR("lslw", "w", MK_SEL(2), 0);
|
||||
TEST_LR("lsll", "", MK_SEL(2), 0);
|
||||
|
||||
TEST_LR("larw", "w", 0xfff8, 0);
|
||||
TEST_LR("larl", "", 0xfff8, 0);
|
||||
TEST_LR("lslw", "w", 0xfff8, 0);
|
||||
TEST_LR("lsll", "", 0xfff8, 0);
|
||||
}
|
||||
|
||||
/* 16 bit code test */
|
||||
@@ -824,6 +938,9 @@ void test_code16(void)
|
||||
printf("func3() = 0x%08x\n", res);
|
||||
}
|
||||
|
||||
extern char func_lret32;
|
||||
extern char func_iret32;
|
||||
|
||||
void test_misc(void)
|
||||
{
|
||||
char table[256];
|
||||
@@ -833,6 +950,21 @@ void test_misc(void)
|
||||
res = 0x12345678;
|
||||
asm ("xlat" : "=a" (res) : "b" (table), "0" (res));
|
||||
printf("xlat: EAX=%08x\n", res);
|
||||
|
||||
asm volatile ("pushl %%cs ; call %1"
|
||||
: "=a" (res)
|
||||
: "m" (func_lret32): "memory", "cc");
|
||||
printf("func_lret32=%x\n", res);
|
||||
|
||||
asm volatile ("pushfl ; pushl %%cs ; call %1"
|
||||
: "=a" (res)
|
||||
: "m" (func_iret32): "memory", "cc");
|
||||
printf("func_iret32=%x\n", res);
|
||||
|
||||
/* specific popl test */
|
||||
asm volatile ("pushl $12345432 ; pushl $0x9abcdef ; popl (%%esp) ; popl %0"
|
||||
: "=g" (res));
|
||||
printf("popl esp=%x\n", res);
|
||||
}
|
||||
|
||||
uint8_t str_buffer[4096];
|
||||
@@ -890,6 +1022,348 @@ void test_string(void)
|
||||
TEST_STRING(cmps, "repnz ");
|
||||
}
|
||||
|
||||
/* VM86 test */
|
||||
|
||||
static inline void set_bit(uint8_t *a, unsigned int bit)
|
||||
{
|
||||
a[bit / 8] |= (1 << (bit % 8));
|
||||
}
|
||||
|
||||
static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg)
|
||||
{
|
||||
return (uint8_t *)((seg << 4) + (reg & 0xffff));
|
||||
}
|
||||
|
||||
static inline void pushw(struct vm86_regs *r, int val)
|
||||
{
|
||||
r->esp = (r->esp & ~0xffff) | ((r->esp - 2) & 0xffff);
|
||||
*(uint16_t *)seg_to_linear(r->ss, r->esp) = val;
|
||||
}
|
||||
|
||||
#undef __syscall_return
|
||||
#define __syscall_return(type, res) \
|
||||
do { \
|
||||
return (type) (res); \
|
||||
} while (0)
|
||||
|
||||
_syscall2(int, vm86, int, func, struct vm86plus_struct *, v86)
|
||||
|
||||
extern char vm86_code_start;
|
||||
extern char vm86_code_end;
|
||||
|
||||
#define VM86_CODE_CS 0x100
|
||||
#define VM86_CODE_IP 0x100
|
||||
|
||||
void test_vm86(void)
|
||||
{
|
||||
struct vm86plus_struct ctx;
|
||||
struct vm86_regs *r;
|
||||
uint8_t *vm86_mem;
|
||||
int seg, ret;
|
||||
|
||||
vm86_mem = mmap((void *)0x00000000, 0x110000,
|
||||
PROT_WRITE | PROT_READ | PROT_EXEC,
|
||||
MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
if (vm86_mem == MAP_FAILED) {
|
||||
printf("ERROR: could not map vm86 memory");
|
||||
return;
|
||||
}
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
|
||||
/* init basic registers */
|
||||
r = &ctx.regs;
|
||||
r->eip = VM86_CODE_IP;
|
||||
r->esp = 0xfffe;
|
||||
seg = VM86_CODE_CS;
|
||||
r->cs = seg;
|
||||
r->ss = seg;
|
||||
r->ds = seg;
|
||||
r->es = seg;
|
||||
r->fs = seg;
|
||||
r->gs = seg;
|
||||
r->eflags = VIF_MASK;
|
||||
|
||||
/* move code to proper address. We use the same layout as a .com
|
||||
dos program. */
|
||||
memcpy(vm86_mem + (VM86_CODE_CS << 4) + VM86_CODE_IP,
|
||||
&vm86_code_start, &vm86_code_end - &vm86_code_start);
|
||||
|
||||
/* mark int 0x21 as being emulated */
|
||||
set_bit((uint8_t *)&ctx.int_revectored, 0x21);
|
||||
|
||||
for(;;) {
|
||||
ret = vm86(VM86_ENTER, &ctx);
|
||||
switch(VM86_TYPE(ret)) {
|
||||
case VM86_INTx:
|
||||
{
|
||||
int int_num, ah;
|
||||
|
||||
int_num = VM86_ARG(ret);
|
||||
if (int_num != 0x21)
|
||||
goto unknown_int;
|
||||
ah = (r->eax >> 8) & 0xff;
|
||||
switch(ah) {
|
||||
case 0x00: /* exit */
|
||||
goto the_end;
|
||||
case 0x02: /* write char */
|
||||
{
|
||||
uint8_t c = r->edx;
|
||||
putchar(c);
|
||||
}
|
||||
break;
|
||||
case 0x09: /* write string */
|
||||
{
|
||||
uint8_t c, *ptr;
|
||||
ptr = seg_to_linear(r->ds, r->edx);
|
||||
for(;;) {
|
||||
c = *ptr++;
|
||||
if (c == '$')
|
||||
break;
|
||||
putchar(c);
|
||||
}
|
||||
r->eax = (r->eax & ~0xff) | '$';
|
||||
}
|
||||
break;
|
||||
case 0xff: /* extension: write hex number in edx */
|
||||
printf("%08x\n", (int)r->edx);
|
||||
break;
|
||||
default:
|
||||
unknown_int:
|
||||
printf("unsupported int 0x%02x\n", int_num);
|
||||
goto the_end;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VM86_SIGNAL:
|
||||
/* a signal came, we just ignore that */
|
||||
break;
|
||||
case VM86_STI:
|
||||
break;
|
||||
default:
|
||||
printf("ERROR: unhandled vm86 return code (0x%x)\n", ret);
|
||||
goto the_end;
|
||||
}
|
||||
}
|
||||
the_end:
|
||||
printf("VM86 end\n");
|
||||
munmap(vm86_mem, 0x110000);
|
||||
}
|
||||
|
||||
/* exception tests */
|
||||
#ifndef REG_EAX
|
||||
#define REG_EAX EAX
|
||||
#define REG_EBX EBX
|
||||
#define REG_ECX ECX
|
||||
#define REG_EDX EDX
|
||||
#define REG_ESI ESI
|
||||
#define REG_EDI EDI
|
||||
#define REG_EBP EBP
|
||||
#define REG_ESP ESP
|
||||
#define REG_EIP EIP
|
||||
#define REG_EFL EFL
|
||||
#define REG_TRAPNO TRAPNO
|
||||
#define REG_ERR ERR
|
||||
#endif
|
||||
|
||||
jmp_buf jmp_env;
|
||||
int v1;
|
||||
int tab[2];
|
||||
|
||||
void sig_handler(int sig, siginfo_t *info, void *puc)
|
||||
{
|
||||
struct ucontext *uc = puc;
|
||||
|
||||
printf("si_signo=%d si_errno=%d si_code=%d",
|
||||
info->si_signo, info->si_errno, info->si_code);
|
||||
printf(" si_addr=0x%08lx",
|
||||
(unsigned long)info->si_addr);
|
||||
printf("\n");
|
||||
|
||||
printf("trapno=0x%02x err=0x%08x",
|
||||
uc->uc_mcontext.gregs[REG_TRAPNO],
|
||||
uc->uc_mcontext.gregs[REG_ERR]);
|
||||
printf(" EIP=0x%08x", uc->uc_mcontext.gregs[REG_EIP]);
|
||||
printf("\n");
|
||||
longjmp(jmp_env, 1);
|
||||
}
|
||||
|
||||
void test_exceptions(void)
|
||||
{
|
||||
struct modify_ldt_ldt_s ldt;
|
||||
struct sigaction act;
|
||||
volatile int val;
|
||||
|
||||
act.sa_sigaction = sig_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
sigaction(SIGFPE, &act, NULL);
|
||||
sigaction(SIGILL, &act, NULL);
|
||||
sigaction(SIGSEGV, &act, NULL);
|
||||
sigaction(SIGBUS, &act, NULL);
|
||||
sigaction(SIGTRAP, &act, NULL);
|
||||
|
||||
/* test division by zero reporting */
|
||||
printf("DIVZ exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* now divide by zero */
|
||||
v1 = 0;
|
||||
v1 = 2 / v1;
|
||||
}
|
||||
|
||||
printf("BOUND exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* bound exception */
|
||||
tab[0] = 1;
|
||||
tab[1] = 10;
|
||||
asm volatile ("bound %0, %1" : : "r" (11), "m" (tab));
|
||||
}
|
||||
|
||||
printf("segment exceptions:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* load an invalid segment */
|
||||
asm volatile ("movl %0, %%fs" : : "r" ((0x1234 << 3) | 1));
|
||||
}
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* null data segment is valid */
|
||||
asm volatile ("movl %0, %%fs" : : "r" (3));
|
||||
/* null stack segment */
|
||||
asm volatile ("movl %0, %%ss" : : "r" (3));
|
||||
}
|
||||
|
||||
ldt.entry_number = 1;
|
||||
ldt.base_addr = (unsigned long)&seg_data1;
|
||||
ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12;
|
||||
ldt.seg_32bit = 1;
|
||||
ldt.contents = MODIFY_LDT_CONTENTS_DATA;
|
||||
ldt.read_exec_only = 0;
|
||||
ldt.limit_in_pages = 1;
|
||||
ldt.seg_not_present = 1;
|
||||
ldt.useable = 1;
|
||||
modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
|
||||
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* segment not present */
|
||||
asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1)));
|
||||
}
|
||||
|
||||
/* test SEGV reporting */
|
||||
printf("PF exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
val = 1;
|
||||
/* now store in an invalid address */
|
||||
*(char *)0x1234 = 1;
|
||||
}
|
||||
|
||||
/* test SEGV reporting */
|
||||
printf("PF exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
val = 1;
|
||||
/* read from an invalid address */
|
||||
v1 = *(char *)0x1234;
|
||||
}
|
||||
|
||||
/* test illegal instruction reporting */
|
||||
printf("UD2 exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* now execute an invalid instruction */
|
||||
asm volatile("ud2");
|
||||
}
|
||||
|
||||
printf("INT exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("int $0xfd");
|
||||
}
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("int $0x01");
|
||||
}
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile (".byte 0xcd, 0x03");
|
||||
}
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("int $0x04");
|
||||
}
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("int $0x05");
|
||||
}
|
||||
|
||||
printf("INT3 exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("int3");
|
||||
}
|
||||
|
||||
printf("CLI exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("cli");
|
||||
}
|
||||
|
||||
printf("STI exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("cli");
|
||||
}
|
||||
|
||||
printf("INTO exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* overflow exception */
|
||||
asm volatile ("addl $1, %0 ; into" : : "r" (0x7fffffff));
|
||||
}
|
||||
|
||||
printf("OUTB exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("outb %%al, %%dx" : : "d" (0x4321), "a" (0));
|
||||
}
|
||||
|
||||
printf("INB exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("inb %%dx, %%al" : "=a" (val) : "d" (0x4321));
|
||||
}
|
||||
|
||||
printf("REP OUTSB exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("rep outsb" : : "d" (0x4321), "S" (tab), "c" (1));
|
||||
}
|
||||
|
||||
printf("REP INSB exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("rep insb" : : "d" (0x4321), "D" (tab), "c" (1));
|
||||
}
|
||||
|
||||
printf("HLT exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("hlt");
|
||||
}
|
||||
|
||||
printf("single step exception:\n");
|
||||
val = 0;
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("pushf\n"
|
||||
"orl $0x00100, (%%esp)\n"
|
||||
"popf\n"
|
||||
"movl $0xabcd, %0\n"
|
||||
"movl $0x0, %0\n" : "=m" (val) : : "cc", "memory");
|
||||
}
|
||||
printf("val=0x%x\n", val);
|
||||
}
|
||||
|
||||
/* self modifying code test */
|
||||
uint8_t code[] = {
|
||||
0xb8, 0x1, 0x00, 0x00, 0x00, /* movl $1, %eax */
|
||||
0xc3, /* ret */
|
||||
};
|
||||
|
||||
typedef int FuncType(void);
|
||||
|
||||
void test_self_modifying_code(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("self modifying code:\n");
|
||||
printf("func1 = 0x%x\n", ((FuncType *)code)());
|
||||
for(i = 2; i <= 4; i++) {
|
||||
code[1] = i;
|
||||
printf("func%d = 0x%x\n", i, ((FuncType *)code)());
|
||||
}
|
||||
}
|
||||
|
||||
static void *call_end __init_call = NULL;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
@@ -913,5 +1387,8 @@ int main(int argc, char **argv)
|
||||
test_lea();
|
||||
test_segs();
|
||||
test_code16();
|
||||
test_vm86();
|
||||
test_exceptions();
|
||||
test_self_modifying_code();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/* Test path override code */
|
||||
#define _GNU_SOURCE
|
||||
#include "../path.c"
|
||||
#include <stdarg.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
/* Any log message kills the test. */
|
||||
void gemu_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf(stderr, "FATAL: ");
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#define NO_CHANGE(_path) \
|
||||
do { \
|
||||
if (strcmp(path(_path), _path) != 0) return __LINE__; \
|
||||
} while(0)
|
||||
|
||||
#define CHANGE_TO(_path, _newpath) \
|
||||
do { \
|
||||
if (strcmp(path(_path), _newpath) != 0) return __LINE__; \
|
||||
} while(0)
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||
unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE2");
|
||||
unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE3");
|
||||
unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE4");
|
||||
unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE5");
|
||||
rmdir("/tmp/qemu-test_path/DIR1/DIR2");
|
||||
rmdir("/tmp/qemu-test_path/DIR1/DIR3");
|
||||
rmdir("/tmp/qemu-test_path/DIR1");
|
||||
rmdir("/tmp/qemu-test_path");
|
||||
}
|
||||
|
||||
static unsigned int do_test(void)
|
||||
{
|
||||
if (mkdir("/tmp/qemu-test_path", 0700) != 0)
|
||||
return __LINE__;
|
||||
|
||||
if (mkdir("/tmp/qemu-test_path/DIR1", 0700) != 0)
|
||||
return __LINE__;
|
||||
|
||||
if (mkdir("/tmp/qemu-test_path/DIR1/DIR2", 0700) != 0)
|
||||
return __LINE__;
|
||||
|
||||
if (mkdir("/tmp/qemu-test_path/DIR1/DIR3", 0700) != 0)
|
||||
return __LINE__;
|
||||
|
||||
if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE", 0600)) != 0)
|
||||
return __LINE__;
|
||||
|
||||
if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE2", 0600)) != 0)
|
||||
return __LINE__;
|
||||
|
||||
if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE3", 0600)) != 0)
|
||||
return __LINE__;
|
||||
|
||||
if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE4", 0600)) != 0)
|
||||
return __LINE__;
|
||||
|
||||
if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE5", 0600)) != 0)
|
||||
return __LINE__;
|
||||
|
||||
init_paths("/tmp/qemu-test_path");
|
||||
|
||||
NO_CHANGE("/tmp");
|
||||
NO_CHANGE("/tmp/");
|
||||
NO_CHANGE("/tmp/qemu-test_path");
|
||||
NO_CHANGE("/tmp/qemu-test_path/");
|
||||
NO_CHANGE("/tmp/qemu-test_path/D");
|
||||
NO_CHANGE("/tmp/qemu-test_path/DI");
|
||||
NO_CHANGE("/tmp/qemu-test_path/DIR");
|
||||
NO_CHANGE("/tmp/qemu-test_path/DIR1");
|
||||
NO_CHANGE("/tmp/qemu-test_path/DIR1/");
|
||||
|
||||
NO_CHANGE("/D");
|
||||
NO_CHANGE("/DI");
|
||||
NO_CHANGE("/DIR");
|
||||
NO_CHANGE("/DIR2");
|
||||
NO_CHANGE("/DIR1.");
|
||||
|
||||
CHANGE_TO("/DIR1", "/tmp/qemu-test_path/DIR1");
|
||||
CHANGE_TO("/DIR1/", "/tmp/qemu-test_path/DIR1");
|
||||
|
||||
NO_CHANGE("/DIR1/D");
|
||||
NO_CHANGE("/DIR1/DI");
|
||||
NO_CHANGE("/DIR1/DIR");
|
||||
NO_CHANGE("/DIR1/DIR1");
|
||||
|
||||
CHANGE_TO("/DIR1/DIR2", "/tmp/qemu-test_path/DIR1/DIR2");
|
||||
CHANGE_TO("/DIR1/DIR2/", "/tmp/qemu-test_path/DIR1/DIR2");
|
||||
|
||||
CHANGE_TO("/DIR1/DIR3", "/tmp/qemu-test_path/DIR1/DIR3");
|
||||
CHANGE_TO("/DIR1/DIR3/", "/tmp/qemu-test_path/DIR1/DIR3");
|
||||
|
||||
NO_CHANGE("/DIR1/DIR2/F");
|
||||
NO_CHANGE("/DIR1/DIR2/FI");
|
||||
NO_CHANGE("/DIR1/DIR2/FIL");
|
||||
NO_CHANGE("/DIR1/DIR2/FIL.");
|
||||
|
||||
CHANGE_TO("/DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||
CHANGE_TO("/DIR1/DIR2/FILE2", "/tmp/qemu-test_path/DIR1/DIR2/FILE2");
|
||||
CHANGE_TO("/DIR1/DIR2/FILE3", "/tmp/qemu-test_path/DIR1/DIR2/FILE3");
|
||||
CHANGE_TO("/DIR1/DIR2/FILE4", "/tmp/qemu-test_path/DIR1/DIR2/FILE4");
|
||||
CHANGE_TO("/DIR1/DIR2/FILE5", "/tmp/qemu-test_path/DIR1/DIR2/FILE5");
|
||||
|
||||
NO_CHANGE("/DIR1/DIR2/FILE6");
|
||||
NO_CHANGE("/DIR1/DIR2/FILE/X");
|
||||
|
||||
CHANGE_TO("/DIR1/../DIR1", "/tmp/qemu-test_path/DIR1");
|
||||
CHANGE_TO("/DIR1/../DIR1/", "/tmp/qemu-test_path/DIR1");
|
||||
CHANGE_TO("/../DIR1", "/tmp/qemu-test_path/DIR1");
|
||||
CHANGE_TO("/../DIR1/", "/tmp/qemu-test_path/DIR1");
|
||||
CHANGE_TO("/DIR1/DIR2/../DIR2", "/tmp/qemu-test_path/DIR1/DIR2");
|
||||
CHANGE_TO("/DIR1/DIR2/../DIR2/../../DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||
CHANGE_TO("/DIR1/DIR2/../DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||
|
||||
NO_CHANGE("/DIR1/DIR2/../DIR1");
|
||||
NO_CHANGE("/DIR1/DIR2/../FILE");
|
||||
|
||||
CHANGE_TO("/./DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||
CHANGE_TO("/././DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||
CHANGE_TO("/DIR1/./DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||
CHANGE_TO("/DIR1/././DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||
CHANGE_TO("/DIR1/DIR2/./FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||
CHANGE_TO("/DIR1/DIR2/././FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||
CHANGE_TO("/./DIR1/./DIR2/./FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = do_test();
|
||||
cleanup();
|
||||
if (ret) {
|
||||
fprintf(stderr, "test_path: failed on line %i\n", ret);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
+110
-26
@@ -26,13 +26,15 @@ void alarm_handler(int sig)
|
||||
#define REG_ESP ESP
|
||||
#define REG_EIP EIP
|
||||
#define REG_EFL EFL
|
||||
#define REG_TRAPNO TRAPNO
|
||||
#define REG_ERR ERR
|
||||
#endif
|
||||
|
||||
void dump_regs(struct ucontext *uc)
|
||||
{
|
||||
printf("EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
|
||||
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
|
||||
"EFL=%08x EIP=%08x\n",
|
||||
"EFL=%08x EIP=%08x trapno=%02x err=%08x\n",
|
||||
uc->uc_mcontext.gregs[REG_EAX],
|
||||
uc->uc_mcontext.gregs[REG_EBX],
|
||||
uc->uc_mcontext.gregs[REG_ECX],
|
||||
@@ -42,7 +44,9 @@ void dump_regs(struct ucontext *uc)
|
||||
uc->uc_mcontext.gregs[REG_EBP],
|
||||
uc->uc_mcontext.gregs[REG_ESP],
|
||||
uc->uc_mcontext.gregs[REG_EFL],
|
||||
uc->uc_mcontext.gregs[REG_EIP]);
|
||||
uc->uc_mcontext.gregs[REG_EIP],
|
||||
uc->uc_mcontext.gregs[REG_TRAPNO],
|
||||
uc->uc_mcontext.gregs[REG_ERR]);
|
||||
}
|
||||
|
||||
void sig_handler(int sig, siginfo_t *info, void *puc)
|
||||
@@ -58,19 +62,23 @@ void sig_handler(int sig, siginfo_t *info, void *puc)
|
||||
}
|
||||
|
||||
int v1;
|
||||
int tab[2];
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct sigaction act;
|
||||
int i;
|
||||
volatile int val;
|
||||
|
||||
act.sa_sigaction = sig_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
sigaction(SIGFPE, &act, NULL);
|
||||
sigaction(SIGILL, &act, NULL);
|
||||
sigaction(SIGSEGV, &act, NULL);
|
||||
sigaction(SIGTRAP, &act, NULL);
|
||||
|
||||
/* test division by zero reporting */
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
act.sa_sigaction = sig_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO | SA_ONESHOT;
|
||||
sigaction(SIGFPE, &act, NULL);
|
||||
|
||||
/* now divide by zero */
|
||||
v1 = 0;
|
||||
v1 = 2 / v1;
|
||||
@@ -78,33 +86,109 @@ int main(int argc, char **argv)
|
||||
|
||||
/* test illegal instruction reporting */
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
act.sa_sigaction = sig_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO | SA_ONESHOT;
|
||||
sigaction(SIGILL, &act, NULL);
|
||||
|
||||
/* now execute an invalid instruction */
|
||||
asm volatile("ud2");
|
||||
}
|
||||
|
||||
/* test SEGV reporting */
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
act.sa_sigaction = sig_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO | SA_ONESHOT;
|
||||
sigaction(SIGSEGV, &act, NULL);
|
||||
|
||||
/* now store in an invalid address */
|
||||
*(char *)0x1234 = 1;
|
||||
}
|
||||
|
||||
act.sa_handler = alarm_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
sigaction(SIGALRM, &act, NULL);
|
||||
alarm(1);
|
||||
for(i = 0;i < 2; i++) {
|
||||
sleep(1);
|
||||
|
||||
/* test SEGV reporting */
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* read from an invalid address */
|
||||
v1 = *(char *)0x1234;
|
||||
}
|
||||
|
||||
printf("segment GPF exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* load an invalid segment */
|
||||
asm volatile ("movl %0, %%fs" : : "r" ((0x1234 << 3) | 0));
|
||||
}
|
||||
|
||||
printf("INT exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("int $0xfd");
|
||||
}
|
||||
|
||||
printf("INT3 exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("int3");
|
||||
}
|
||||
|
||||
printf("CLI exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("cli");
|
||||
}
|
||||
|
||||
printf("STI exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("cli");
|
||||
}
|
||||
|
||||
printf("INTO exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* overflow exception */
|
||||
asm volatile ("addl $1, %0 ; into" : : "r" (0x7fffffff));
|
||||
}
|
||||
|
||||
printf("BOUND exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* bound exception */
|
||||
tab[0] = 1;
|
||||
tab[1] = 10;
|
||||
asm volatile ("bound %0, %1" : : "r" (11), "m" (tab));
|
||||
}
|
||||
|
||||
printf("OUTB exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("outb %%al, %%dx" : : "d" (0x4321), "a" (0));
|
||||
}
|
||||
|
||||
printf("INB exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("inb %%dx, %%al" : "=a" (val) : "d" (0x4321));
|
||||
}
|
||||
|
||||
printf("REP OUTSB exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("rep outsb" : : "d" (0x4321), "S" (tab), "c" (1));
|
||||
}
|
||||
|
||||
printf("REP INSB exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("rep insb" : : "d" (0x4321), "D" (tab), "c" (1));
|
||||
}
|
||||
|
||||
printf("HLT exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("hlt");
|
||||
}
|
||||
|
||||
printf("single step exception:\n");
|
||||
val = 0;
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("pushf\n"
|
||||
"orl $0x00100, (%%esp)\n"
|
||||
"popf\n"
|
||||
"movl $0xabcd, %0\n" : "=m" (val) : : "cc", "memory");
|
||||
}
|
||||
printf("val=0x%x\n", val);
|
||||
|
||||
#if 1
|
||||
{
|
||||
int i;
|
||||
act.sa_handler = alarm_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
sigaction(SIGALRM, &act, NULL);
|
||||
alarm(1);
|
||||
for(i = 0;i < 2; i++) {
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
@@ -29,80 +29,7 @@
|
||||
#define MAX_STRUCTS 128
|
||||
|
||||
/* XXX: make it dynamic */
|
||||
static StructEntry struct_entries[MAX_STRUCTS];
|
||||
|
||||
static inline int thunk_type_size(const argtype *type_ptr, int is_host)
|
||||
{
|
||||
int type, size;
|
||||
const StructEntry *se;
|
||||
|
||||
type = *type_ptr;
|
||||
switch(type) {
|
||||
case TYPE_CHAR:
|
||||
return 1;
|
||||
case TYPE_SHORT:
|
||||
return 2;
|
||||
case TYPE_INT:
|
||||
return 4;
|
||||
case TYPE_LONGLONG:
|
||||
case TYPE_ULONGLONG:
|
||||
return 8;
|
||||
case TYPE_LONG:
|
||||
case TYPE_ULONG:
|
||||
case TYPE_PTRVOID:
|
||||
case TYPE_PTR:
|
||||
if (is_host) {
|
||||
return HOST_LONG_SIZE;
|
||||
} else {
|
||||
return TARGET_LONG_SIZE;
|
||||
}
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
size = type_ptr[1];
|
||||
return size * thunk_type_size(type_ptr + 2, is_host);
|
||||
case TYPE_STRUCT:
|
||||
se = struct_entries + type_ptr[1];
|
||||
return se->size[is_host];
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int thunk_type_align(const argtype *type_ptr, int is_host)
|
||||
{
|
||||
int type;
|
||||
const StructEntry *se;
|
||||
|
||||
type = *type_ptr;
|
||||
switch(type) {
|
||||
case TYPE_CHAR:
|
||||
return 1;
|
||||
case TYPE_SHORT:
|
||||
return 2;
|
||||
case TYPE_INT:
|
||||
return 4;
|
||||
case TYPE_LONGLONG:
|
||||
case TYPE_ULONGLONG:
|
||||
return 8;
|
||||
case TYPE_LONG:
|
||||
case TYPE_ULONG:
|
||||
case TYPE_PTRVOID:
|
||||
case TYPE_PTR:
|
||||
if (is_host) {
|
||||
return HOST_LONG_SIZE;
|
||||
} else {
|
||||
return TARGET_LONG_SIZE;
|
||||
}
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
return thunk_type_align(type_ptr + 2, is_host);
|
||||
case TYPE_STRUCT:
|
||||
se = struct_entries + type_ptr[1];
|
||||
return se->align[is_host];
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
StructEntry struct_entries[MAX_STRUCTS];
|
||||
|
||||
static inline const argtype *thunk_type_next(const argtype *type_ptr)
|
||||
{
|
||||
@@ -167,6 +94,7 @@ void thunk_register_struct(int id, const char *name, const argtype *types)
|
||||
offset += size;
|
||||
if (align > max_align)
|
||||
max_align = align;
|
||||
type_ptr = thunk_type_next(type_ptr);
|
||||
}
|
||||
offset = (offset + max_align - 1) & ~(max_align - 1);
|
||||
se->size[i] = offset;
|
||||
|
||||
@@ -61,23 +61,21 @@
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
|
||||
#define BSWAP_NEEDED
|
||||
#endif
|
||||
|
||||
/* XXX: autoconf */
|
||||
#define TARGET_I386
|
||||
#define TARGET_LONG_BITS 32
|
||||
|
||||
|
||||
#if defined(__alpha__)
|
||||
#if defined(__alpha__) || defined (__ia64__)
|
||||
#define HOST_LONG_BITS 64
|
||||
#else
|
||||
#define HOST_LONG_BITS 32
|
||||
#endif
|
||||
|
||||
#define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8)
|
||||
#define HOST_LONG_SIZE (TARGET_LONG_BITS / 8)
|
||||
#define HOST_LONG_SIZE (HOST_LONG_BITS / 8)
|
||||
|
||||
static inline uint16_t bswap16(uint16_t x)
|
||||
{
|
||||
@@ -94,17 +92,17 @@ static inline uint64_t bswap64(uint64_t x)
|
||||
return bswap_64(x);
|
||||
}
|
||||
|
||||
static void inline bswap16s(uint16_t *s)
|
||||
static inline void bswap16s(uint16_t *s)
|
||||
{
|
||||
*s = bswap16(*s);
|
||||
}
|
||||
|
||||
static void inline bswap32s(uint32_t *s)
|
||||
static inline void bswap32s(uint32_t *s)
|
||||
{
|
||||
*s = bswap32(*s);
|
||||
}
|
||||
|
||||
static void inline bswap64s(uint64_t *s)
|
||||
static inline void bswap64s(uint64_t *s)
|
||||
{
|
||||
*s = bswap64(*s);
|
||||
}
|
||||
@@ -126,17 +124,17 @@ static inline uint64_t tswap64(uint64_t s)
|
||||
return bswap64(s);
|
||||
}
|
||||
|
||||
static void inline tswap16s(uint16_t *s)
|
||||
static inline void tswap16s(uint16_t *s)
|
||||
{
|
||||
*s = bswap16(*s);
|
||||
}
|
||||
|
||||
static void inline tswap32s(uint32_t *s)
|
||||
static inline void tswap32s(uint32_t *s)
|
||||
{
|
||||
*s = bswap32(*s);
|
||||
}
|
||||
|
||||
static void inline tswap64s(uint64_t *s)
|
||||
static inline void tswap64s(uint64_t *s)
|
||||
{
|
||||
*s = bswap64(*s);
|
||||
}
|
||||
@@ -158,15 +156,15 @@ static inline uint64_t tswap64(uint64_t s)
|
||||
return s;
|
||||
}
|
||||
|
||||
static void inline tswap16s(uint16_t *s)
|
||||
static inline void tswap16s(uint16_t *s)
|
||||
{
|
||||
}
|
||||
|
||||
static void inline tswap32s(uint32_t *s)
|
||||
static inline void tswap32s(uint32_t *s)
|
||||
{
|
||||
}
|
||||
|
||||
static void inline tswap64s(uint64_t *s)
|
||||
static inline void tswap64s(uint64_t *s)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -238,6 +236,84 @@ void thunk_register_struct(int id, const char *name, const argtype *types);
|
||||
void thunk_register_struct_direct(int id, const char *name, StructEntry *se1);
|
||||
const argtype *thunk_convert(void *dst, const void *src,
|
||||
const argtype *type_ptr, int to_host);
|
||||
#ifndef NO_THUNK_TYPE_SIZE
|
||||
|
||||
extern StructEntry struct_entries[];
|
||||
|
||||
static inline int thunk_type_size(const argtype *type_ptr, int is_host)
|
||||
{
|
||||
int type, size;
|
||||
const StructEntry *se;
|
||||
|
||||
type = *type_ptr;
|
||||
switch(type) {
|
||||
case TYPE_CHAR:
|
||||
return 1;
|
||||
case TYPE_SHORT:
|
||||
return 2;
|
||||
case TYPE_INT:
|
||||
return 4;
|
||||
case TYPE_LONGLONG:
|
||||
case TYPE_ULONGLONG:
|
||||
return 8;
|
||||
case TYPE_LONG:
|
||||
case TYPE_ULONG:
|
||||
case TYPE_PTRVOID:
|
||||
case TYPE_PTR:
|
||||
if (is_host) {
|
||||
return HOST_LONG_SIZE;
|
||||
} else {
|
||||
return TARGET_LONG_SIZE;
|
||||
}
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
size = type_ptr[1];
|
||||
return size * thunk_type_size(type_ptr + 2, is_host);
|
||||
case TYPE_STRUCT:
|
||||
se = struct_entries + type_ptr[1];
|
||||
return se->size[is_host];
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int thunk_type_align(const argtype *type_ptr, int is_host)
|
||||
{
|
||||
int type;
|
||||
const StructEntry *se;
|
||||
|
||||
type = *type_ptr;
|
||||
switch(type) {
|
||||
case TYPE_CHAR:
|
||||
return 1;
|
||||
case TYPE_SHORT:
|
||||
return 2;
|
||||
case TYPE_INT:
|
||||
return 4;
|
||||
case TYPE_LONGLONG:
|
||||
case TYPE_ULONGLONG:
|
||||
return 8;
|
||||
case TYPE_LONG:
|
||||
case TYPE_ULONG:
|
||||
case TYPE_PTRVOID:
|
||||
case TYPE_PTR:
|
||||
if (is_host) {
|
||||
return HOST_LONG_SIZE;
|
||||
} else {
|
||||
return TARGET_LONG_SIZE;
|
||||
}
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
return thunk_type_align(type_ptr + 2, is_host);
|
||||
case TYPE_STRUCT:
|
||||
se = struct_entries + type_ptr[1];
|
||||
return se->align[is_host];
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* NO_THUNK_TYPE_SIZE */
|
||||
|
||||
unsigned int target_to_host_bitmask(unsigned int x86_mask,
|
||||
bitmask_transtbl * trans_tbl);
|
||||
|
||||
+760
@@ -0,0 +1,760 @@
|
||||
/*
|
||||
* ARM translation
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "cpu-arm.h"
|
||||
#include "exec.h"
|
||||
#include "disas.h"
|
||||
|
||||
/* internal defines */
|
||||
typedef struct DisasContext {
|
||||
uint8_t *pc;
|
||||
int is_jmp;
|
||||
struct TranslationBlock *tb;
|
||||
} DisasContext;
|
||||
|
||||
/* XXX: move that elsewhere */
|
||||
static uint16_t *gen_opc_ptr;
|
||||
static uint32_t *gen_opparam_ptr;
|
||||
extern FILE *logfile;
|
||||
extern int loglevel;
|
||||
|
||||
enum {
|
||||
#define DEF(s, n, copy_size) INDEX_op_ ## s,
|
||||
#include "opc-arm.h"
|
||||
#undef DEF
|
||||
NB_OPS,
|
||||
};
|
||||
|
||||
#include "gen-op-arm.h"
|
||||
|
||||
typedef void (GenOpFunc)(void);
|
||||
typedef void (GenOpFunc1)(long);
|
||||
typedef void (GenOpFunc2)(long, long);
|
||||
typedef void (GenOpFunc3)(long, long, long);
|
||||
|
||||
static GenOpFunc2 *gen_test_cc[14] = {
|
||||
gen_op_test_eq,
|
||||
gen_op_test_ne,
|
||||
gen_op_test_cs,
|
||||
gen_op_test_cc,
|
||||
gen_op_test_mi,
|
||||
gen_op_test_pl,
|
||||
gen_op_test_vs,
|
||||
gen_op_test_vc,
|
||||
gen_op_test_hi,
|
||||
gen_op_test_ls,
|
||||
gen_op_test_ge,
|
||||
gen_op_test_lt,
|
||||
gen_op_test_gt,
|
||||
gen_op_test_le,
|
||||
};
|
||||
|
||||
const uint8_t table_logic_cc[16] = {
|
||||
1, /* and */
|
||||
1, /* xor */
|
||||
0, /* sub */
|
||||
0, /* rsb */
|
||||
0, /* add */
|
||||
0, /* adc */
|
||||
0, /* sbc */
|
||||
0, /* rsc */
|
||||
1, /* andl */
|
||||
1, /* xorl */
|
||||
0, /* cmp */
|
||||
0, /* cmn */
|
||||
1, /* orr */
|
||||
1, /* mov */
|
||||
1, /* bic */
|
||||
1, /* mvn */
|
||||
};
|
||||
|
||||
static GenOpFunc1 *gen_shift_T1_im[4] = {
|
||||
gen_op_shll_T1_im,
|
||||
gen_op_shrl_T1_im,
|
||||
gen_op_sarl_T1_im,
|
||||
gen_op_rorl_T1_im,
|
||||
};
|
||||
|
||||
static GenOpFunc1 *gen_shift_T2_im[4] = {
|
||||
gen_op_shll_T2_im,
|
||||
gen_op_shrl_T2_im,
|
||||
gen_op_sarl_T2_im,
|
||||
gen_op_rorl_T2_im,
|
||||
};
|
||||
|
||||
static GenOpFunc1 *gen_shift_T1_im_cc[4] = {
|
||||
gen_op_shll_T1_im_cc,
|
||||
gen_op_shrl_T1_im_cc,
|
||||
gen_op_sarl_T1_im_cc,
|
||||
gen_op_rorl_T1_im_cc,
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_shift_T1_T0[4] = {
|
||||
gen_op_shll_T1_T0,
|
||||
gen_op_shrl_T1_T0,
|
||||
gen_op_sarl_T1_T0,
|
||||
gen_op_rorl_T1_T0,
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_shift_T1_T0_cc[4] = {
|
||||
gen_op_shll_T1_T0_cc,
|
||||
gen_op_shrl_T1_T0_cc,
|
||||
gen_op_sarl_T1_T0_cc,
|
||||
gen_op_rorl_T1_T0_cc,
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_op_movl_TN_reg[3][16] = {
|
||||
{
|
||||
gen_op_movl_T0_r0,
|
||||
gen_op_movl_T0_r1,
|
||||
gen_op_movl_T0_r2,
|
||||
gen_op_movl_T0_r3,
|
||||
gen_op_movl_T0_r4,
|
||||
gen_op_movl_T0_r5,
|
||||
gen_op_movl_T0_r6,
|
||||
gen_op_movl_T0_r7,
|
||||
gen_op_movl_T0_r8,
|
||||
gen_op_movl_T0_r9,
|
||||
gen_op_movl_T0_r10,
|
||||
gen_op_movl_T0_r11,
|
||||
gen_op_movl_T0_r12,
|
||||
gen_op_movl_T0_r13,
|
||||
gen_op_movl_T0_r14,
|
||||
gen_op_movl_T0_r15,
|
||||
},
|
||||
{
|
||||
gen_op_movl_T1_r0,
|
||||
gen_op_movl_T1_r1,
|
||||
gen_op_movl_T1_r2,
|
||||
gen_op_movl_T1_r3,
|
||||
gen_op_movl_T1_r4,
|
||||
gen_op_movl_T1_r5,
|
||||
gen_op_movl_T1_r6,
|
||||
gen_op_movl_T1_r7,
|
||||
gen_op_movl_T1_r8,
|
||||
gen_op_movl_T1_r9,
|
||||
gen_op_movl_T1_r10,
|
||||
gen_op_movl_T1_r11,
|
||||
gen_op_movl_T1_r12,
|
||||
gen_op_movl_T1_r13,
|
||||
gen_op_movl_T1_r14,
|
||||
gen_op_movl_T1_r15,
|
||||
},
|
||||
{
|
||||
gen_op_movl_T2_r0,
|
||||
gen_op_movl_T2_r1,
|
||||
gen_op_movl_T2_r2,
|
||||
gen_op_movl_T2_r3,
|
||||
gen_op_movl_T2_r4,
|
||||
gen_op_movl_T2_r5,
|
||||
gen_op_movl_T2_r6,
|
||||
gen_op_movl_T2_r7,
|
||||
gen_op_movl_T2_r8,
|
||||
gen_op_movl_T2_r9,
|
||||
gen_op_movl_T2_r10,
|
||||
gen_op_movl_T2_r11,
|
||||
gen_op_movl_T2_r12,
|
||||
gen_op_movl_T2_r13,
|
||||
gen_op_movl_T2_r14,
|
||||
gen_op_movl_T2_r15,
|
||||
},
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_op_movl_reg_TN[2][16] = {
|
||||
{
|
||||
gen_op_movl_r0_T0,
|
||||
gen_op_movl_r1_T0,
|
||||
gen_op_movl_r2_T0,
|
||||
gen_op_movl_r3_T0,
|
||||
gen_op_movl_r4_T0,
|
||||
gen_op_movl_r5_T0,
|
||||
gen_op_movl_r6_T0,
|
||||
gen_op_movl_r7_T0,
|
||||
gen_op_movl_r8_T0,
|
||||
gen_op_movl_r9_T0,
|
||||
gen_op_movl_r10_T0,
|
||||
gen_op_movl_r11_T0,
|
||||
gen_op_movl_r12_T0,
|
||||
gen_op_movl_r13_T0,
|
||||
gen_op_movl_r14_T0,
|
||||
gen_op_movl_r15_T0,
|
||||
},
|
||||
{
|
||||
gen_op_movl_r0_T1,
|
||||
gen_op_movl_r1_T1,
|
||||
gen_op_movl_r2_T1,
|
||||
gen_op_movl_r3_T1,
|
||||
gen_op_movl_r4_T1,
|
||||
gen_op_movl_r5_T1,
|
||||
gen_op_movl_r6_T1,
|
||||
gen_op_movl_r7_T1,
|
||||
gen_op_movl_r8_T1,
|
||||
gen_op_movl_r9_T1,
|
||||
gen_op_movl_r10_T1,
|
||||
gen_op_movl_r11_T1,
|
||||
gen_op_movl_r12_T1,
|
||||
gen_op_movl_r13_T1,
|
||||
gen_op_movl_r14_T1,
|
||||
gen_op_movl_r15_T1,
|
||||
},
|
||||
};
|
||||
|
||||
static GenOpFunc1 *gen_op_movl_TN_im[3] = {
|
||||
gen_op_movl_T0_im,
|
||||
gen_op_movl_T1_im,
|
||||
gen_op_movl_T2_im,
|
||||
};
|
||||
|
||||
static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t)
|
||||
{
|
||||
int val;
|
||||
|
||||
if (reg == 15) {
|
||||
/* normaly, since we updated PC, we need only to add 4 */
|
||||
val = (long)s->pc + 4;
|
||||
gen_op_movl_TN_im[t](val);
|
||||
} else {
|
||||
gen_op_movl_TN_reg[t][reg]();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gen_movl_T0_reg(DisasContext *s, int reg)
|
||||
{
|
||||
gen_movl_TN_reg(s, reg, 0);
|
||||
}
|
||||
|
||||
static inline void gen_movl_T1_reg(DisasContext *s, int reg)
|
||||
{
|
||||
gen_movl_TN_reg(s, reg, 1);
|
||||
}
|
||||
|
||||
static inline void gen_movl_T2_reg(DisasContext *s, int reg)
|
||||
{
|
||||
gen_movl_TN_reg(s, reg, 2);
|
||||
}
|
||||
|
||||
static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t)
|
||||
{
|
||||
gen_op_movl_reg_TN[t][reg]();
|
||||
if (reg == 15) {
|
||||
s->is_jmp = DISAS_JUMP;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gen_movl_reg_T0(DisasContext *s, int reg)
|
||||
{
|
||||
gen_movl_reg_TN(s, reg, 0);
|
||||
}
|
||||
|
||||
static inline void gen_movl_reg_T1(DisasContext *s, int reg)
|
||||
{
|
||||
gen_movl_reg_TN(s, reg, 1);
|
||||
}
|
||||
|
||||
static inline void gen_add_data_offset(DisasContext *s, unsigned int insn)
|
||||
{
|
||||
int val, rm, shift;
|
||||
|
||||
if (!(insn & (1 << 25))) {
|
||||
/* immediate */
|
||||
val = insn & 0xfff;
|
||||
if (!(insn & (1 << 23)))
|
||||
val = -val;
|
||||
gen_op_addl_T1_im(val);
|
||||
} else {
|
||||
/* shift/register */
|
||||
rm = (insn) & 0xf;
|
||||
shift = (insn >> 7) & 0x1f;
|
||||
gen_movl_T2_reg(s, rm);
|
||||
if (shift != 0) {
|
||||
gen_shift_T2_im[(insn >> 5) & 3](shift);
|
||||
}
|
||||
if (!(insn & (1 << 23)))
|
||||
gen_op_subl_T1_T2();
|
||||
else
|
||||
gen_op_addl_T1_T2();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn)
|
||||
{
|
||||
int val, rm;
|
||||
|
||||
if (insn & (1 << 22)) {
|
||||
/* immediate */
|
||||
val = (insn & 0xf) | ((insn >> 4) & 0xf0);
|
||||
if (!(insn & (1 << 23)))
|
||||
val = -val;
|
||||
gen_op_addl_T1_im(val);
|
||||
} else {
|
||||
/* register */
|
||||
rm = (insn) & 0xf;
|
||||
gen_movl_T2_reg(s, rm);
|
||||
if (!(insn & (1 << 23)))
|
||||
gen_op_subl_T1_T2();
|
||||
else
|
||||
gen_op_addl_T1_T2();
|
||||
}
|
||||
}
|
||||
|
||||
static void disas_arm_insn(DisasContext *s)
|
||||
{
|
||||
unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
|
||||
|
||||
insn = ldl(s->pc);
|
||||
s->pc += 4;
|
||||
|
||||
cond = insn >> 28;
|
||||
if (cond == 0xf)
|
||||
goto illegal_op;
|
||||
if (cond != 0xe) {
|
||||
/* if not always execute, we generate a conditional jump to
|
||||
next instruction */
|
||||
gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
|
||||
s->is_jmp = 1;
|
||||
}
|
||||
if ((insn & 0x0c000000) == 0 &&
|
||||
(insn & 0x00000090) != 0x90) {
|
||||
int set_cc, logic_cc, shiftop;
|
||||
|
||||
op1 = (insn >> 21) & 0xf;
|
||||
set_cc = (insn >> 20) & 1;
|
||||
logic_cc = table_logic_cc[op1] & set_cc;
|
||||
|
||||
/* data processing instruction */
|
||||
if (insn & (1 << 25)) {
|
||||
/* immediate operand */
|
||||
val = insn & 0xff;
|
||||
shift = ((insn >> 8) & 0xf) * 2;
|
||||
if (shift)
|
||||
val = (val >> shift) | (val << (32 - shift));
|
||||
gen_op_movl_T1_im(val);
|
||||
/* XXX: is CF modified ? */
|
||||
} else {
|
||||
/* register */
|
||||
rm = (insn) & 0xf;
|
||||
gen_movl_T1_reg(s, rm);
|
||||
shiftop = (insn >> 5) & 3;
|
||||
if (!(insn & (1 << 4))) {
|
||||
shift = (insn >> 7) & 0x1f;
|
||||
if (shift != 0) {
|
||||
if (logic_cc) {
|
||||
gen_shift_T1_im_cc[shiftop](shift);
|
||||
} else {
|
||||
gen_shift_T1_im[shiftop](shift);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rs = (insn >> 16) & 0xf;
|
||||
gen_movl_T0_reg(s, rs);
|
||||
if (logic_cc) {
|
||||
gen_shift_T1_T0_cc[shiftop]();
|
||||
} else {
|
||||
gen_shift_T1_T0[shiftop]();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (op1 != 0x0f && op1 != 0x0d) {
|
||||
rn = (insn >> 16) & 0xf;
|
||||
gen_movl_T0_reg(s, rn);
|
||||
}
|
||||
rd = (insn >> 12) & 0xf;
|
||||
switch(op1) {
|
||||
case 0x00:
|
||||
gen_op_andl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
break;
|
||||
case 0x01:
|
||||
gen_op_xorl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
break;
|
||||
case 0x02:
|
||||
if (set_cc)
|
||||
gen_op_subl_T0_T1_cc();
|
||||
else
|
||||
gen_op_subl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
break;
|
||||
case 0x03:
|
||||
if (set_cc)
|
||||
gen_op_rsbl_T0_T1_cc();
|
||||
else
|
||||
gen_op_rsbl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
break;
|
||||
case 0x04:
|
||||
if (set_cc)
|
||||
gen_op_addl_T0_T1_cc();
|
||||
else
|
||||
gen_op_addl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
break;
|
||||
case 0x05:
|
||||
if (set_cc)
|
||||
gen_op_adcl_T0_T1_cc();
|
||||
else
|
||||
gen_op_adcl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
break;
|
||||
case 0x06:
|
||||
if (set_cc)
|
||||
gen_op_sbcl_T0_T1_cc();
|
||||
else
|
||||
gen_op_sbcl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
break;
|
||||
case 0x07:
|
||||
if (set_cc)
|
||||
gen_op_rscl_T0_T1_cc();
|
||||
else
|
||||
gen_op_rscl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
break;
|
||||
case 0x08:
|
||||
if (set_cc) {
|
||||
gen_op_andl_T0_T1();
|
||||
}
|
||||
break;
|
||||
case 0x09:
|
||||
if (set_cc) {
|
||||
gen_op_xorl_T0_T1();
|
||||
}
|
||||
break;
|
||||
case 0x0a:
|
||||
if (set_cc) {
|
||||
gen_op_subl_T0_T1_cc();
|
||||
}
|
||||
break;
|
||||
case 0x0b:
|
||||
if (set_cc) {
|
||||
gen_op_addl_T0_T1_cc();
|
||||
}
|
||||
break;
|
||||
case 0x0c:
|
||||
gen_op_orl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
break;
|
||||
case 0x0d:
|
||||
gen_movl_reg_T1(s, rd);
|
||||
break;
|
||||
case 0x0e:
|
||||
gen_op_bicl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
break;
|
||||
default:
|
||||
case 0x0f:
|
||||
gen_op_notl_T1();
|
||||
gen_movl_reg_T1(s, rd);
|
||||
break;
|
||||
}
|
||||
if (logic_cc)
|
||||
gen_op_logic_cc();
|
||||
} else {
|
||||
/* other instructions */
|
||||
op1 = (insn >> 24) & 0xf;
|
||||
switch(op1) {
|
||||
case 0x0:
|
||||
case 0x1:
|
||||
sh = (insn >> 5) & 3;
|
||||
if (sh == 0) {
|
||||
if (op1 == 0x0) {
|
||||
rd = (insn >> 16) & 0xf;
|
||||
rn = (insn >> 12) & 0xf;
|
||||
rs = (insn >> 8) & 0xf;
|
||||
rm = (insn) & 0xf;
|
||||
if (!(insn & (1 << 23))) {
|
||||
/* 32 bit mul */
|
||||
gen_movl_T0_reg(s, rs);
|
||||
gen_movl_T1_reg(s, rm);
|
||||
gen_op_mul_T0_T1();
|
||||
if (insn & (1 << 21)) {
|
||||
gen_movl_T1_reg(s, rn);
|
||||
gen_op_addl_T0_T1();
|
||||
}
|
||||
if (insn & (1 << 20))
|
||||
gen_op_logic_cc();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
} else {
|
||||
/* 64 bit mul */
|
||||
gen_movl_T0_reg(s, rs);
|
||||
gen_movl_T1_reg(s, rm);
|
||||
if (insn & (1 << 22))
|
||||
gen_op_mull_T0_T1();
|
||||
else
|
||||
gen_op_imull_T0_T1();
|
||||
if (insn & (1 << 21))
|
||||
gen_op_addq_T0_T1(rn, rd);
|
||||
if (insn & (1 << 20))
|
||||
gen_op_logicq_cc();
|
||||
gen_movl_reg_T0(s, rn);
|
||||
gen_movl_reg_T1(s, rd);
|
||||
}
|
||||
} else {
|
||||
/* SWP instruction */
|
||||
rn = (insn >> 16) & 0xf;
|
||||
rd = (insn >> 12) & 0xf;
|
||||
rm = (insn) & 0xf;
|
||||
|
||||
gen_movl_T0_reg(s, rm);
|
||||
gen_movl_T1_reg(s, rn);
|
||||
if (insn & (1 << 22)) {
|
||||
gen_op_swpb_T0_T1();
|
||||
} else {
|
||||
gen_op_swpl_T0_T1();
|
||||
}
|
||||
gen_movl_reg_T0(s, rd);
|
||||
}
|
||||
} else {
|
||||
/* load/store half word */
|
||||
rn = (insn >> 16) & 0xf;
|
||||
rd = (insn >> 12) & 0xf;
|
||||
gen_movl_T1_reg(s, rn);
|
||||
if (insn & (1 << 25))
|
||||
gen_add_datah_offset(s, insn);
|
||||
if (insn & (1 << 20)) {
|
||||
/* load */
|
||||
switch(sh) {
|
||||
case 1:
|
||||
gen_op_lduw_T0_T1();
|
||||
break;
|
||||
case 2:
|
||||
gen_op_ldsb_T0_T1();
|
||||
break;
|
||||
default:
|
||||
case 3:
|
||||
gen_op_ldsw_T0_T1();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* store */
|
||||
gen_op_stw_T0_T1();
|
||||
}
|
||||
if (!(insn & (1 << 24)))
|
||||
gen_add_datah_offset(s, insn);
|
||||
if (insn & (1 << 21))
|
||||
gen_movl_reg_T1(s, rn);
|
||||
}
|
||||
break;
|
||||
case 0x4:
|
||||
case 0x5:
|
||||
case 0x6:
|
||||
case 0x7:
|
||||
/* load/store byte/word */
|
||||
rn = (insn >> 16) & 0xf;
|
||||
rd = (insn >> 12) & 0xf;
|
||||
gen_movl_T1_reg(s, rn);
|
||||
if (insn & (1 << 24))
|
||||
gen_add_data_offset(s, insn);
|
||||
if (insn & (1 << 20)) {
|
||||
/* load */
|
||||
if (insn & (1 << 22))
|
||||
gen_op_ldub_T0_T1();
|
||||
else
|
||||
gen_op_ldl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
} else {
|
||||
/* store */
|
||||
gen_movl_T0_reg(s, rd);
|
||||
if (insn & (1 << 22))
|
||||
gen_op_stb_T0_T1();
|
||||
else
|
||||
gen_op_stl_T0_T1();
|
||||
}
|
||||
if (!(insn & (1 << 24)))
|
||||
gen_add_data_offset(s, insn);
|
||||
if (insn & (1 << 21))
|
||||
gen_movl_reg_T1(s, rn);
|
||||
break;
|
||||
case 0x08:
|
||||
case 0x09:
|
||||
/* load/store multiple words */
|
||||
if (insn & (1 << 22))
|
||||
goto illegal_op; /* only usable in supervisor mode */
|
||||
rn = (insn >> 16) & 0xf;
|
||||
gen_movl_T1_reg(s, rn);
|
||||
val = 4;
|
||||
if (!(insn & (1 << 23)))
|
||||
val = -val;
|
||||
for(i=0;i<16;i++) {
|
||||
if (insn & (1 << i)) {
|
||||
if (insn & (1 << 24))
|
||||
gen_op_addl_T1_im(val);
|
||||
if (insn & (1 << 20)) {
|
||||
/* load */
|
||||
gen_op_ldl_T0_T1();
|
||||
gen_movl_reg_T0(s, i);
|
||||
} else {
|
||||
/* store */
|
||||
gen_movl_T0_reg(s, i);
|
||||
gen_op_stl_T0_T1();
|
||||
}
|
||||
if (!(insn & (1 << 24)))
|
||||
gen_op_addl_T1_im(val);
|
||||
}
|
||||
}
|
||||
if (insn & (1 << 21))
|
||||
gen_movl_reg_T1(s, rn);
|
||||
break;
|
||||
case 0xa:
|
||||
case 0xb:
|
||||
{
|
||||
int offset;
|
||||
|
||||
/* branch (and link) */
|
||||
val = (int)s->pc;
|
||||
if (insn & (1 << 24)) {
|
||||
gen_op_movl_T0_im(val);
|
||||
gen_op_movl_reg_TN[0][14]();
|
||||
}
|
||||
offset = (((int)insn << 8) >> 8);
|
||||
val += (offset << 2) + 4;
|
||||
gen_op_jmp((long)s->tb, val);
|
||||
s->is_jmp = DISAS_TB_JUMP;
|
||||
}
|
||||
break;
|
||||
case 0xf:
|
||||
/* swi */
|
||||
gen_op_movl_T0_im((long)s->pc);
|
||||
gen_op_movl_reg_TN[0][15]();
|
||||
gen_op_swi();
|
||||
s->is_jmp = DISAS_JUMP;
|
||||
break;
|
||||
default:
|
||||
illegal_op:
|
||||
gen_op_movl_T0_im((long)s->pc - 4);
|
||||
gen_op_movl_reg_TN[0][15]();
|
||||
gen_op_undef_insn();
|
||||
s->is_jmp = DISAS_JUMP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
|
||||
basic block 'tb'. If search_pc is TRUE, also generate PC
|
||||
information for each intermediate instruction. */
|
||||
static inline int gen_intermediate_code_internal(TranslationBlock *tb, int search_pc)
|
||||
{
|
||||
DisasContext dc1, *dc = &dc1;
|
||||
uint16_t *gen_opc_end;
|
||||
int j, lj;
|
||||
uint8_t *pc_start;
|
||||
|
||||
/* generate intermediate code */
|
||||
pc_start = (uint8_t *)tb->pc;
|
||||
|
||||
dc->tb = tb;
|
||||
|
||||
gen_opc_ptr = gen_opc_buf;
|
||||
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
|
||||
gen_opparam_ptr = gen_opparam_buf;
|
||||
|
||||
dc->is_jmp = DISAS_NEXT;
|
||||
dc->pc = pc_start;
|
||||
lj = -1;
|
||||
do {
|
||||
if (search_pc) {
|
||||
j = gen_opc_ptr - gen_opc_buf;
|
||||
if (lj < j) {
|
||||
lj++;
|
||||
while (lj < j)
|
||||
gen_opc_instr_start[lj++] = 0;
|
||||
gen_opc_pc[lj] = (uint32_t)dc->pc;
|
||||
gen_opc_instr_start[lj] = 1;
|
||||
}
|
||||
}
|
||||
disas_arm_insn(dc);
|
||||
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
|
||||
(dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
|
||||
/* we must store the eflags state if it is not already done */
|
||||
if (dc->is_jmp != DISAS_TB_JUMP &&
|
||||
dc->is_jmp != DISAS_JUMP) {
|
||||
gen_op_movl_T0_im((long)dc->pc - 4);
|
||||
gen_op_movl_reg_TN[0][15]();
|
||||
}
|
||||
if (dc->is_jmp != DISAS_TB_JUMP) {
|
||||
/* indicate that the hash table must be used to find the next TB */
|
||||
gen_op_movl_T0_0();
|
||||
}
|
||||
*gen_opc_ptr = INDEX_op_end;
|
||||
|
||||
#ifdef DEBUG_DISAS
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "----------------\n");
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
|
||||
disas(logfile, pc_start, dc->pc - pc_start, 0, 0);
|
||||
fprintf(logfile, "\n");
|
||||
|
||||
fprintf(logfile, "OP:\n");
|
||||
dump_ops(gen_opc_buf, gen_opparam_buf);
|
||||
fprintf(logfile, "\n");
|
||||
}
|
||||
#endif
|
||||
if (!search_pc)
|
||||
tb->size = dc->pc - pc_start;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gen_intermediate_code(TranslationBlock *tb)
|
||||
{
|
||||
return gen_intermediate_code_internal(tb, 0);
|
||||
}
|
||||
|
||||
int gen_intermediate_code_pc(TranslationBlock *tb)
|
||||
{
|
||||
return gen_intermediate_code_internal(tb, 1);
|
||||
}
|
||||
|
||||
CPUARMState *cpu_arm_init(void)
|
||||
{
|
||||
CPUARMState *env;
|
||||
|
||||
cpu_exec_init();
|
||||
|
||||
env = malloc(sizeof(CPUARMState));
|
||||
if (!env)
|
||||
return NULL;
|
||||
memset(env, 0, sizeof(CPUARMState));
|
||||
return env;
|
||||
}
|
||||
|
||||
void cpu_arm_close(CPUARMState *env)
|
||||
{
|
||||
free(env);
|
||||
}
|
||||
|
||||
void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0;i<16;i++) {
|
||||
fprintf(f, "R%02d=%08x", i, env->regs[i]);
|
||||
if ((i % 4) == 3)
|
||||
fprintf(f, "\n");
|
||||
else
|
||||
fprintf(f, " ");
|
||||
}
|
||||
fprintf(f, "CPSR=%08x", env->cpsr);
|
||||
}
|
||||
+1225
-488
File diff suppressed because it is too large.
Load diff
+205
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Host code generation
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define IN_OP_I386
|
||||
#if defined(TARGET_I386)
|
||||
#include "cpu-i386.h"
|
||||
#define OPC_CPU_H "opc-i386.h"
|
||||
#elif defined(TARGET_ARM)
|
||||
#include "cpu-arm.h"
|
||||
#define OPC_CPU_H "opc-arm.h"
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
|
||||
#include "exec.h"
|
||||
#include "disas.h"
|
||||
|
||||
enum {
|
||||
#define DEF(s, n, copy_size) INDEX_op_ ## s,
|
||||
#include OPC_CPU_H
|
||||
#undef DEF
|
||||
NB_OPS,
|
||||
};
|
||||
|
||||
#include "dyngen.h"
|
||||
#if defined(TARGET_I386)
|
||||
#include "op-i386.h"
|
||||
#elif defined(TARGET_ARM)
|
||||
#include "op-arm.h"
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
|
||||
uint16_t gen_opc_buf[OPC_BUF_SIZE];
|
||||
uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
|
||||
uint32_t gen_opc_pc[OPC_BUF_SIZE];
|
||||
uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
|
||||
#if defined(TARGET_I386)
|
||||
uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_DISAS
|
||||
static const char *op_str[] = {
|
||||
#define DEF(s, n, copy_size) #s,
|
||||
#include OPC_CPU_H
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
static uint8_t op_nb_args[] = {
|
||||
#define DEF(s, n, copy_size) n,
|
||||
#include OPC_CPU_H
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf)
|
||||
{
|
||||
const uint16_t *opc_ptr;
|
||||
const uint32_t *opparam_ptr;
|
||||
int c, n, i;
|
||||
|
||||
opc_ptr = opc_buf;
|
||||
opparam_ptr = opparam_buf;
|
||||
for(;;) {
|
||||
c = *opc_ptr++;
|
||||
n = op_nb_args[c];
|
||||
fprintf(logfile, "0x%04x: %s",
|
||||
(int)(opc_ptr - opc_buf - 1), op_str[c]);
|
||||
for(i = 0; i < n; i++) {
|
||||
fprintf(logfile, " 0x%x", opparam_ptr[i]);
|
||||
}
|
||||
fprintf(logfile, "\n");
|
||||
if (c == INDEX_op_end)
|
||||
break;
|
||||
opparam_ptr += n;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* return non zero if the very first instruction is invalid so that
|
||||
the virtual CPU can trigger an exception.
|
||||
|
||||
'*gen_code_size_ptr' contains the size of the generated code (host
|
||||
code).
|
||||
*/
|
||||
int cpu_gen_code(TranslationBlock *tb,
|
||||
int max_code_size, int *gen_code_size_ptr)
|
||||
{
|
||||
uint8_t *gen_code_buf;
|
||||
int gen_code_size;
|
||||
|
||||
if (gen_intermediate_code(tb) < 0)
|
||||
return -1;
|
||||
|
||||
/* generate machine code */
|
||||
tb->tb_next_offset[0] = 0xffff;
|
||||
tb->tb_next_offset[1] = 0xffff;
|
||||
gen_code_buf = tb->tc_ptr;
|
||||
gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset,
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
tb->tb_jmp_offset,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
gen_opc_buf, gen_opparam_buf);
|
||||
*gen_code_size_ptr = gen_code_size;
|
||||
#ifdef DEBUG_DISAS
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr);
|
||||
disas(logfile, gen_code_buf, *gen_code_size_ptr, 1, 0);
|
||||
fprintf(logfile, "\n");
|
||||
fflush(logfile);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const unsigned short opc_copy_size[] = {
|
||||
#define DEF(s, n, copy_size) copy_size,
|
||||
#include OPC_CPU_H
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
/* The cpu state corresponding to 'searched_pc' is restored.
|
||||
*/
|
||||
int cpu_restore_state(TranslationBlock *tb,
|
||||
CPUState *env, unsigned long searched_pc)
|
||||
{
|
||||
int j, c;
|
||||
unsigned long tc_ptr;
|
||||
uint16_t *opc_ptr;
|
||||
|
||||
if (gen_intermediate_code_pc(tb) < 0)
|
||||
return -1;
|
||||
|
||||
/* find opc index corresponding to search_pc */
|
||||
tc_ptr = (unsigned long)tb->tc_ptr;
|
||||
if (searched_pc < tc_ptr)
|
||||
return -1;
|
||||
j = 0;
|
||||
opc_ptr = gen_opc_buf;
|
||||
for(;;) {
|
||||
c = *opc_ptr;
|
||||
if (c == INDEX_op_end)
|
||||
return -1;
|
||||
tc_ptr += opc_copy_size[c];
|
||||
if (searched_pc < tc_ptr)
|
||||
break;
|
||||
opc_ptr++;
|
||||
}
|
||||
j = opc_ptr - gen_opc_buf;
|
||||
/* now find start of instruction before */
|
||||
while (gen_opc_instr_start[j] == 0)
|
||||
j--;
|
||||
#if defined(TARGET_I386)
|
||||
{
|
||||
int cc_op;
|
||||
#ifdef DEBUG_DISAS
|
||||
if (loglevel) {
|
||||
int i;
|
||||
for(i=0;i<=j; i++) {
|
||||
if (gen_opc_instr_start[i]) {
|
||||
fprintf(logfile, "0x%04x: 0x%08x", i, gen_opc_pc[i]);
|
||||
}
|
||||
}
|
||||
fprintf(logfile, "j=0x%x eip=0x%lx cs_base=%lx\n",
|
||||
j, gen_opc_pc[j] - tb->cs_base, tb->cs_base);
|
||||
}
|
||||
#endif
|
||||
env->eip = gen_opc_pc[j] - tb->cs_base;
|
||||
cc_op = gen_opc_cc_op[j];
|
||||
if (cc_op != CC_OP_DYNAMIC)
|
||||
env->cc_op = cc_op;
|
||||
}
|
||||
#elif defined(TARGET_ARM)
|
||||
env->regs[15] = gen_opc_pc[j];
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* QEMU System Emulator header
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef VL_H
|
||||
#define VL_H
|
||||
|
||||
/* vl.c */
|
||||
void *get_mmap_addr(unsigned long size);
|
||||
|
||||
/* block.c */
|
||||
typedef struct BlockDriverState BlockDriverState;
|
||||
|
||||
BlockDriverState *bdrv_open(const char *filename, int snapshot);
|
||||
void bdrv_close(BlockDriverState *bs);
|
||||
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors);
|
||||
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors);
|
||||
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr);
|
||||
int bdrv_commit(BlockDriverState *bs);
|
||||
|
||||
/* user mode linux compatible COW file */
|
||||
#define COW_MAGIC 0x4f4f4f4d /* MOOO */
|
||||
#define COW_VERSION 2
|
||||
|
||||
struct cow_header_v2 {
|
||||
uint32_t magic;
|
||||
uint32_t long version;
|
||||
char backing_file[1024];
|
||||
int32_t mtime;
|
||||
uint64_t size;
|
||||
uint32_t sectorsize;
|
||||
};
|
||||
|
||||
#endif /* VL_H */
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* create a COW disk image
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <malloc.h>
|
||||
#include <termios.h>
|
||||
#include <sys/poll.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
#define NO_THUNK_TYPE_SIZE
|
||||
#include "thunk.h"
|
||||
|
||||
int cow_create(int cow_fd, const char *image_filename,
|
||||
int64_t image_sectors)
|
||||
{
|
||||
struct cow_header_v2 cow_header;
|
||||
int fd;
|
||||
struct stat st;
|
||||
|
||||
memset(&cow_header, 0, sizeof(cow_header));
|
||||
cow_header.magic = htonl(COW_MAGIC);
|
||||
cow_header.version = htonl(COW_VERSION);
|
||||
if (image_filename) {
|
||||
fd = open(image_filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror(image_filename);
|
||||
exit(1);
|
||||
}
|
||||
image_sectors = lseek64(fd, 0, SEEK_END);
|
||||
if (fstat(fd, &st) != 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
image_sectors /= 512;
|
||||
cow_header.mtime = htonl(st.st_mtime);
|
||||
realpath(image_filename, cow_header.backing_file);
|
||||
}
|
||||
cow_header.sectorsize = htonl(512);
|
||||
cow_header.size = image_sectors * 512;
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
cow_header.size = bswap64(cow_header.size);
|
||||
#endif
|
||||
write(cow_fd, &cow_header, sizeof(cow_header));
|
||||
/* resize to include at least all the bitmap */
|
||||
ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3));
|
||||
lseek(cow_fd, 0, SEEK_SET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void help(void)
|
||||
{
|
||||
printf("vlmkcow version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
|
||||
"usage: vlmkcow [-h] [-f disk_image] cow_image [cow_size]\n"
|
||||
"Create a Copy On Write disk image from an optional raw disk image\n"
|
||||
"\n"
|
||||
"-f disk_image set the raw disk image name\n"
|
||||
"cow_image the created cow_image\n"
|
||||
"cow_size the create cow_image size in MB if no raw disk image is used\n"
|
||||
"\n"
|
||||
"Once the cow_image is created from a raw disk image, you must not modify the original raw disk image\n"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *image_filename, *cow_filename;
|
||||
int cow_fd, c, nb_args;
|
||||
int64_t image_size;
|
||||
|
||||
image_filename = NULL;
|
||||
image_size = 0;
|
||||
for(;;) {
|
||||
c = getopt(argc, argv, "hf:");
|
||||
if (c == -1)
|
||||
break;
|
||||
switch(c) {
|
||||
case 'h':
|
||||
help();
|
||||
break;
|
||||
case 'f':
|
||||
image_filename = optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!image_filename)
|
||||
nb_args = 2;
|
||||
else
|
||||
nb_args = 1;
|
||||
if (optind + nb_args != argc)
|
||||
help();
|
||||
|
||||
cow_filename = argv[optind];
|
||||
if (nb_args == 2) {
|
||||
image_size = (int64_t)atoi(argv[optind + 1]) * 2 * 1024;
|
||||
}
|
||||
|
||||
cow_fd = open(cow_filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
|
||||
if (!cow_fd < 0)
|
||||
return -1;
|
||||
if (cow_create(cow_fd, image_filename, image_size) < 0) {
|
||||
fprintf(stderr, "%s: error while formating\n", cow_filename);
|
||||
exit(1);
|
||||
}
|
||||
close(cow_fd);
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user