Compare commits
100 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
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 |
222
COPYING.LIB
222
COPYING.LIB
@@ -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!
|
||||
|
||||
|
||||
|
22
Changelog
22
Changelog
@@ -1,3 +1,25 @@
|
||||
version 0.2:
|
||||
|
||||
- PowerPC disassembly and ELF symbols output (Rusty Russel)
|
||||
- flock support (Rusty Russel)
|
||||
- ugetrlimit support (Rusty Russel)
|
||||
- fstat64 fix (Rusty Russel)
|
||||
- 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
|
||||
|
68
Makefile
68
Makefile
@@ -13,11 +13,15 @@ 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
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ppc)
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
@@ -29,6 +33,31 @@ OP_CFLAGS=$(CFLAGS)
|
||||
LDFLAGS+=-Wl,-T,s390.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),sparc)
|
||||
CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
|
||||
LDFLAGS+=-m32
|
||||
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
|
||||
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 -msmall-text
|
||||
LDFLAGS+=-Wl,-T,alpha.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ia64)
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
endif
|
||||
|
||||
ifeq ($(GCC_MAJOR),3)
|
||||
# very important to generate a return at the end of every operation
|
||||
OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
|
||||
@@ -45,18 +74,34 @@ LDFLAGS+=-p
|
||||
main.o: CFLAGS+=-p
|
||||
endif
|
||||
|
||||
OBJS= elfload.o main.o syscall.o signal.o path.o
|
||||
OBJS= elfload.o main.o syscall.o mmap.o signal.o vm86.o path.o
|
||||
SRCS:= $(OBJS:.o=.c)
|
||||
OBJS+= libqemu.a
|
||||
|
||||
LIBOBJS+=thunk.o translate-i386.o op-i386.o exec-i386.o
|
||||
LIBOBJS+=thunk.o translate-i386.o op-i386.o exec-i386.o exec.o
|
||||
|
||||
# NOTE: the disassembler code is only needed for debugging
|
||||
LIBOBJS+=i386-dis.o dis-buf.o
|
||||
LIBOBJS+=disas.o i386-dis.o dis-buf.o
|
||||
ifeq ($(ARCH),alpha)
|
||||
LIBOBJS+=alpha-dis.o
|
||||
endif
|
||||
ifeq ($(ARCH),ppc)
|
||||
LIBOBJS+=ppc-dis.o
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ia64)
|
||||
OBJS += ia64-syscall.o
|
||||
endif
|
||||
|
||||
all: qemu 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
|
||||
|
||||
depend: $(SRCS)
|
||||
$(CC) -MM $(CFLAGS) $^ 1>.depend
|
||||
@@ -70,11 +115,14 @@ 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-i386.o: translate-i386.c op-i386.h opc-i386.h cpu-i386.h
|
||||
|
||||
op-i386.h: op-i386.o dyngen
|
||||
./dyngen -o $@ $<
|
||||
|
||||
opc-i386.h: op-i386.o dyngen
|
||||
./dyngen -c -o $@ $<
|
||||
|
||||
op-i386.o: op-i386.c opreg_template.h ops_template.h
|
||||
$(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
@@ -96,7 +144,7 @@ test speed: qemu
|
||||
make -C tests $@
|
||||
|
||||
TAGS:
|
||||
etags *.[ch] i386/*.[ch]
|
||||
etags *.[ch] tests/*.[ch]
|
||||
|
||||
# documentation
|
||||
qemu-doc.html: qemu-doc.texi
|
||||
@@ -106,11 +154,11 @@ 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 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 path.c configure \
|
||||
elfload.c main.c signal.c thunk.h exec.h\
|
||||
cpu-i386.h qemu.h op-i386.c syscall-i386.h translate-i386.c\
|
||||
syscall.c opreg_template.h syscall_defs.h vm86.c\
|
||||
dis-asm.h dis-buf.c disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c\
|
||||
ppc.ld s390.ld exec-i386.h exec-i386.c path.c exec.c mmap.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\
|
||||
|
16
README.distrib
Normal file
16
README.distrib
Normal file
@@ -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
|
30
TODO
30
TODO
@@ -1,12 +1,22 @@
|
||||
- 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
|
||||
|
||||
- fix iret/lret/fpush not before mem load restarting
|
||||
- fix all remaining thread lock issues (must put TBs in a specific invalid
|
||||
state, find a solution for tb_flush()).
|
||||
- handle fp87 state in signals
|
||||
- add gcc 2.96 test configure (some gcc3 flags are needed)
|
||||
- optimize FPU operations (evaluate x87 stack pointer statically)
|
||||
- add IPC syscalls
|
||||
- submit a patch to fix DOSEMU coopthreads
|
||||
|
||||
lower priority:
|
||||
--------------
|
||||
- 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 (handle self modifying code, relocate stack
|
||||
and dyn loader)
|
||||
- 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
|
||||
|
1976
alpha-dis.c
Normal file
1976
alpha-dis.c
Normal file
File diff suppressed because it is too large
Load Diff
128
alpha.ld
Normal file
128
alpha.ld
Normal file
@@ -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 . */
|
||||
}
|
44
configure
vendored
44
configure
vendored
@@ -26,6 +26,7 @@ host_cc="gcc"
|
||||
ar="ar"
|
||||
make="make"
|
||||
strip="strip"
|
||||
target_cpu="x86"
|
||||
cpu=`uname -m`
|
||||
case "$cpu" in
|
||||
i386|i486|i586|i686|i86pc|BePC)
|
||||
@@ -46,6 +47,15 @@ case "$cpu" in
|
||||
s390)
|
||||
cpu="s390"
|
||||
;;
|
||||
sparc)
|
||||
cpu="sparc"
|
||||
;;
|
||||
sparc64)
|
||||
cpu="sparc64"
|
||||
;;
|
||||
ia64)
|
||||
cpu="ia64"
|
||||
;;
|
||||
*)
|
||||
cpu="unknown"
|
||||
;;
|
||||
@@ -56,22 +66,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
|
||||
|
||||
@@ -143,7 +137,7 @@ 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
|
||||
|
||||
@@ -191,8 +185,9 @@ echo "Install prefix $prefix"
|
||||
echo "Source path $source_path"
|
||||
echo "C compiler $cc"
|
||||
echo "make $make"
|
||||
echo "CPU $cpu"
|
||||
echo "host CPU $cpu"
|
||||
echo "Big Endian $bigendian"
|
||||
echo "target CPU $target_cpu"
|
||||
echo "gprof enabled $gprof"
|
||||
|
||||
echo "Creating config.mak and config.h"
|
||||
@@ -228,6 +223,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
|
||||
@@ -246,10 +250,6 @@ 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
|
||||
|
79
cpu-i386.h
79
cpu-i386.h
@@ -48,6 +48,23 @@
|
||||
#define R_FS 4
|
||||
#define R_GS 5
|
||||
|
||||
/* segment descriptor fields */
|
||||
#define DESC_G_MASK (1 << 23)
|
||||
#define DESC_B_MASK (1 << 22)
|
||||
#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
|
||||
@@ -163,7 +180,7 @@ typedef struct CPUX86State {
|
||||
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,6 +197,12 @@ 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 */
|
||||
@@ -191,6 +214,8 @@ typedef struct CPUX86State {
|
||||
/* exception/interrupt handling */
|
||||
jmp_buf jmp_env;
|
||||
int exception_index;
|
||||
int error_code;
|
||||
uint32_t cr2;
|
||||
int interrupt_request;
|
||||
|
||||
/* user data */
|
||||
@@ -395,12 +420,12 @@ static inline void stfq(void *ptr, double 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);
|
||||
@@ -418,17 +443,37 @@ struct siginfo;
|
||||
int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc);
|
||||
|
||||
/* internal functions */
|
||||
/* 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);
|
||||
|
||||
#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
|
||||
/* page related stuff */
|
||||
#define TARGET_PAGE_BITS 12
|
||||
#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)
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
#endif /* CPU_I386_H */
|
||||
|
@@ -320,6 +320,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. */
|
||||
|
81
disas.c
Normal file
81
disas.c
Normal file
@@ -0,0 +1,81 @@
|
||||
/* General "disassemble this chunk" code. Used for debugging. */
|
||||
#include "dis-asm.h"
|
||||
#include "disas.h"
|
||||
#include "elf.h"
|
||||
|
||||
/* Filled in by elfload.c. Simplistic, but will do for now. */
|
||||
unsigned int disas_num_syms;
|
||||
void *disas_symtab;
|
||||
const char *disas_strtab;
|
||||
|
||||
/* Disassemble this for me please... (debugging). */
|
||||
void disas(FILE *out, void *code, unsigned long size, enum disas_type type)
|
||||
{
|
||||
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 (type == DISAS_TARGET) {
|
||||
#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;
|
||||
#else
|
||||
fprintf(out, "Asm output not supported on this arch\n");
|
||||
return;
|
||||
#endif
|
||||
} else {
|
||||
/* Currently only source supported in x86. */
|
||||
disasm_info.endian = BFD_ENDIAN_LITTLE;
|
||||
if (type == DISAS_I386_I386)
|
||||
disasm_info.mach = bfd_mach_i386_i386;
|
||||
else
|
||||
disasm_info.mach = bfd_mach_i386_i8086;
|
||||
print_insn = print_insn_i386;
|
||||
}
|
||||
|
||||
for (pc = code; pc < (uint8_t *)code + size; pc += count) {
|
||||
fprintf(out, "0x%08lx: ", (long)pc);
|
||||
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 "";
|
||||
}
|
20
disas.h
Normal file
20
disas.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef _QEMU_DISAS_H
|
||||
#define _QEMU_DISAS_H
|
||||
|
||||
enum disas_type {
|
||||
DISAS_I386_I386,
|
||||
DISAS_I386_I8086,
|
||||
DISAS_TARGET, /* whatever host is. */
|
||||
};
|
||||
|
||||
/* Disassemble this for me please... (debugging). */
|
||||
void disas(FILE *out, void *code, unsigned long size, enum disas_type type);
|
||||
|
||||
/* 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 */
|
564
dyngen.c
564
dyngen.c
@@ -58,20 +58,43 @@
|
||||
#define elf_check_arch(x) ((x) == EM_ALPHA)
|
||||
#define ELF_USES_RELOCA
|
||||
|
||||
#elif defined(HOST_IA64)
|
||||
|
||||
#define ELF_CLASS ELFCLASS64
|
||||
#define ELF_ARCH EM_IA_64
|
||||
#define elf_check_arch(x) ((x) == EM_IA_64)
|
||||
#define ELF_USES_RELOCA
|
||||
|
||||
#elif defined(HOST_SPARC)
|
||||
|
||||
#define ELF_CLASS ELFCLASS32
|
||||
#define ELF_ARCH EM_SPARC
|
||||
#define elf_check_arch(x) ((x) == EM_SPARC || (x) == EM_SPARC32PLUS)
|
||||
#define ELF_USES_RELOCA
|
||||
|
||||
#elif defined(HOST_SPARC64)
|
||||
|
||||
#define ELF_CLASS ELFCLASS64
|
||||
#define ELF_ARCH EM_SPARCV9
|
||||
#define elf_check_arch(x) ((x) == EM_SPARCV9)
|
||||
#define ELF_USES_RELOCA
|
||||
|
||||
#else
|
||||
#error unsupported CPU - please update the code
|
||||
#endif
|
||||
|
||||
#include "elf.h"
|
||||
|
||||
#if ELF_CLASS == ELFCLASS32
|
||||
typedef int32_t host_long;
|
||||
typedef uint32_t host_ulong;
|
||||
#define swabls(x) swab32s(x)
|
||||
#else
|
||||
typedef int64_t host_long;
|
||||
typedef uint64_t host_ulong;
|
||||
#define swabls(x) swab64s(x)
|
||||
#endif
|
||||
|
||||
#include "elf.h"
|
||||
|
||||
#include "thunk.h"
|
||||
|
||||
/* all dynamically generated functions begin with this code */
|
||||
@@ -104,12 +127,6 @@ void swab64s(uint64_t *p)
|
||||
*p = bswap64(*p);
|
||||
}
|
||||
|
||||
#if ELF_CLASS == ELFCLASS32
|
||||
#define swabls(x) swab32s(x)
|
||||
#else
|
||||
#define swabls(x) swab64s(x)
|
||||
#endif
|
||||
|
||||
void elf_swap_ehdr(struct elfhdr *h)
|
||||
{
|
||||
swab16s(&h->e_type); /* Object file type */
|
||||
@@ -153,7 +170,16 @@ void elf_swap_phdr(struct elf_phdr *h)
|
||||
swabls(&h->p_align); /* Segment alignment */
|
||||
}
|
||||
|
||||
/* ELF file info */
|
||||
int do_swap;
|
||||
struct elf_shdr *shdr;
|
||||
struct elfhdr ehdr;
|
||||
ElfW(Sym) *symtab;
|
||||
int nb_syms;
|
||||
char *strtab;
|
||||
/* data section */
|
||||
uint8_t *data_data;
|
||||
int data_shndx;
|
||||
|
||||
uint16_t get16(uint16_t *p)
|
||||
{
|
||||
@@ -187,7 +213,7 @@ void put32(uint32_t *p, uint32_t val)
|
||||
*p = val;
|
||||
}
|
||||
|
||||
void __attribute__((noreturn)) error(const char *fmt, ...)
|
||||
void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
@@ -253,28 +279,37 @@ int strstart(const char *str, const char *val, const char **ptr)
|
||||
/* generate op code */
|
||||
void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
FILE *outfile, uint8_t *text, ELF_RELOC *relocs, int nb_relocs, int reloc_sh_type,
|
||||
ElfW(Sym) *symtab, char *strtab, int gen_switch)
|
||||
int gen_switch)
|
||||
{
|
||||
int copy_size = 0;
|
||||
uint8_t *p_start, *p_end;
|
||||
host_ulong start_offset;
|
||||
int nb_args, i, n;
|
||||
uint8_t args_present[MAX_ARGS];
|
||||
const char *sym_name, *p;
|
||||
ELF_RELOC *rel;
|
||||
|
||||
/* compute exact size excluding return instruction */
|
||||
/* Compute exact size excluding prologue and epilogue instructions.
|
||||
* Increment start_offset to skip epilogue instructions, then compute
|
||||
* copy_size the indicate the size of the remaining instructions (in
|
||||
* bytes).
|
||||
*/
|
||||
p_start = text + offset;
|
||||
p_end = p_start + size;
|
||||
start_offset = offset;
|
||||
switch(ELF_ARCH) {
|
||||
case EM_386:
|
||||
{
|
||||
uint8_t *p;
|
||||
p = p_end - 1;
|
||||
if (p == p_start)
|
||||
int len;
|
||||
len = p_end - p_start;
|
||||
if (len == 0)
|
||||
error("empty code for %s", name);
|
||||
if (p[0] != 0xc3)
|
||||
error("ret expected at the end of %s", name);
|
||||
copy_size = p - p_start;
|
||||
if (p_end[-1] == 0xc3) {
|
||||
len--;
|
||||
} else {
|
||||
error("ret or jmp expected at the end of %s", name);
|
||||
}
|
||||
copy_size = len;
|
||||
}
|
||||
break;
|
||||
case EM_PPC:
|
||||
@@ -295,10 +330,99 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
if (p == p_start)
|
||||
error("empty code for %s", name);
|
||||
if (get16((uint16_t *)p) != 0x07fe && get16((uint16_t *)p) != 0x07f4)
|
||||
error("br %r14 expected at the end of %s", name);
|
||||
error("br %%r14 expected at the end of %s", name);
|
||||
copy_size = p - p_start;
|
||||
}
|
||||
break;
|
||||
case EM_ALPHA:
|
||||
{
|
||||
uint8_t *p;
|
||||
p = p_end - 4;
|
||||
if (p == p_start)
|
||||
error("empty code for %s", name);
|
||||
if (get32((uint32_t *)p) != 0x6bfa8001)
|
||||
error("ret expected at the end of %s", name);
|
||||
copy_size = p - p_start;
|
||||
}
|
||||
break;
|
||||
case EM_IA_64:
|
||||
{
|
||||
uint8_t *p;
|
||||
p = (void *)(p_end - 4);
|
||||
if (p == p_start)
|
||||
error("empty code for %s", name);
|
||||
/* br.ret.sptk.many b0;; */
|
||||
/* 08 00 84 00 */
|
||||
if (get32((uint32_t *)p) != 0x00840008)
|
||||
error("br.ret.sptk.many b0;; expected at the end of %s", name);
|
||||
copy_size = p - p_start;
|
||||
}
|
||||
break;
|
||||
case EM_SPARC:
|
||||
case EM_SPARC32PLUS:
|
||||
{
|
||||
uint32_t start_insn, end_insn1, end_insn2, skip_insn;
|
||||
uint8_t *p;
|
||||
p = (void *)(p_end - 8);
|
||||
if (p <= p_start)
|
||||
error("empty code for %s", name);
|
||||
start_insn = get32((uint32_t *)(p_start + 0x0));
|
||||
end_insn1 = get32((uint32_t *)(p + 0x0));
|
||||
end_insn2 = get32((uint32_t *)(p + 0x4));
|
||||
if ((start_insn & ~0x1fff) == 0x9de3a000) {
|
||||
p_start += 0x4;
|
||||
start_offset += 0x4;
|
||||
if ((int)(start_insn | ~0x1fff) < -128)
|
||||
error("Found bogus save at the start of %s", name);
|
||||
if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000)
|
||||
error("ret; restore; not found at end of %s", name);
|
||||
} else {
|
||||
error("No save at the beginning of %s", name);
|
||||
}
|
||||
|
||||
/* Skip a preceeding nop, if present. */
|
||||
if (p > p_start) {
|
||||
skip_insn = get32((uint32_t *)(p - 0x4));
|
||||
if (skip_insn == 0x01000000)
|
||||
p -= 4;
|
||||
}
|
||||
|
||||
copy_size = p - p_start;
|
||||
}
|
||||
break;
|
||||
case EM_SPARCV9:
|
||||
{
|
||||
uint32_t start_insn, end_insn1, end_insn2, skip_insn;
|
||||
uint8_t *p;
|
||||
p = (void *)(p_end - 8);
|
||||
if (p <= p_start)
|
||||
error("empty code for %s", name);
|
||||
start_insn = get32((uint32_t *)(p_start + 0x0));
|
||||
end_insn1 = get32((uint32_t *)(p + 0x0));
|
||||
end_insn2 = get32((uint32_t *)(p + 0x4));
|
||||
if ((start_insn & ~0x1fff) == 0x9de3a000) {
|
||||
p_start += 0x4;
|
||||
start_offset += 0x4;
|
||||
if ((int)(start_insn | ~0x1fff) < -256)
|
||||
error("Found bogus save at the start of %s", name);
|
||||
if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000)
|
||||
error("ret; restore; not found at end of %s", name);
|
||||
} else {
|
||||
error("No save at the beginning of %s", name);
|
||||
}
|
||||
|
||||
/* Skip a preceeding nop, if present. */
|
||||
if (p > p_start) {
|
||||
skip_insn = get32((uint32_t *)(p - 0x4));
|
||||
if (skip_insn == 0x01000000)
|
||||
p -= 4;
|
||||
}
|
||||
|
||||
copy_size = p - p_start;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error("unknown ELF architecture");
|
||||
}
|
||||
|
||||
/* compute the number of arguments by looking at the relocations */
|
||||
@@ -306,11 +430,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
args_present[i] = 0;
|
||||
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
|
||||
if (rel->r_offset >= start_offset &&
|
||||
rel->r_offset < start_offset + copy_size) {
|
||||
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
|
||||
if (strstart(sym_name, "__op_param", &p)) {
|
||||
n = strtoul(p, NULL, 10);
|
||||
if (n >= MAX_ARGS)
|
||||
if (n > MAX_ARGS)
|
||||
error("too many arguments in %s", name);
|
||||
args_present[n - 1] = 1;
|
||||
}
|
||||
@@ -326,7 +451,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
}
|
||||
|
||||
if (gen_switch == 2) {
|
||||
fprintf(outfile, "DEF(%s, %d)\n", name + 3, nb_args);
|
||||
fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size);
|
||||
} else if (gen_switch == 1) {
|
||||
|
||||
/* output C code */
|
||||
@@ -343,15 +468,51 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
fprintf(outfile, " extern void %s();\n", name);
|
||||
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
|
||||
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
|
||||
if (!strstart(sym_name, "__op_param", &p)) {
|
||||
if (rel->r_offset >= start_offset &&
|
||||
rel->r_offset < start_offset + copy_size) {
|
||||
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
|
||||
if (*sym_name &&
|
||||
!strstart(sym_name, "__op_param", NULL) &&
|
||||
!strstart(sym_name, "__op_jmp", NULL)) {
|
||||
#if defined(HOST_SPARC)
|
||||
if (sym_name[0] == '.') {
|
||||
fprintf(outfile,
|
||||
"extern char __dot_%s __asm__(\"%s\");\n",
|
||||
sym_name+1, sym_name);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
fprintf(outfile, "extern char %s;\n", sym_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(outfile, " memcpy(gen_code_ptr, &%s, %d);\n", name, copy_size);
|
||||
fprintf(outfile, " memcpy(gen_code_ptr, (void *)((char *)&%s+%d), %d);\n", name, start_offset - offset, copy_size);
|
||||
|
||||
/* emit code offset information */
|
||||
{
|
||||
ElfW(Sym) *sym;
|
||||
const char *sym_name, *p;
|
||||
target_ulong val;
|
||||
int n;
|
||||
|
||||
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
|
||||
sym_name = strtab + sym->st_name;
|
||||
if (strstart(sym_name, "__op_label", &p)) {
|
||||
/* test if the variable refers to a label inside
|
||||
the code we are generating */
|
||||
if (sym->st_shndx != data_shndx)
|
||||
error("__op_labelN symbols must be in .data or .sdata section");
|
||||
val = *(target_ulong *)(data_data + sym->st_value);
|
||||
if (val >= start_offset && val < start_offset + copy_size) {
|
||||
n = strtol(p, NULL, 10);
|
||||
fprintf(outfile, " label_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", n, val - start_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* load parameres in variables */
|
||||
for(i = 0; i < nb_args; i++) {
|
||||
fprintf(outfile, " param%d = *opparam_ptr++;\n", i + 1);
|
||||
}
|
||||
@@ -363,8 +524,9 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
int type;
|
||||
int addend;
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
|
||||
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
|
||||
if (rel->r_offset >= start_offset &&
|
||||
rel->r_offset < start_offset + copy_size) {
|
||||
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
|
||||
if (strstart(sym_name, "__op_param", &p)) {
|
||||
snprintf(name, sizeof(name), "param%s", p);
|
||||
} else {
|
||||
@@ -375,11 +537,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
switch(type) {
|
||||
case R_386_32:
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
|
||||
rel->r_offset - offset, name, addend);
|
||||
rel->r_offset - start_offset, name, addend);
|
||||
break;
|
||||
case R_386_PC32:
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
|
||||
rel->r_offset - offset, name, rel->r_offset - offset, addend);
|
||||
rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend);
|
||||
break;
|
||||
default:
|
||||
error("unsupported i386 relocation (%d)", type);
|
||||
@@ -393,8 +555,21 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
int type;
|
||||
int addend;
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
|
||||
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
|
||||
if (rel->r_offset >= start_offset &&
|
||||
rel->r_offset < start_offset + copy_size) {
|
||||
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
|
||||
if (strstart(sym_name, "__op_jmp", &p)) {
|
||||
int n;
|
||||
n = strtol(p, NULL, 10);
|
||||
/* __op_jmp relocations are done at
|
||||
runtime to do translated block
|
||||
chaining: the offset of the instruction
|
||||
needs to be stored */
|
||||
fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
|
||||
n, rel->r_offset - start_offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strstart(sym_name, "__op_param", &p)) {
|
||||
snprintf(name, sizeof(name), "param%s", p);
|
||||
} else {
|
||||
@@ -405,24 +580,24 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
switch(type) {
|
||||
case R_PPC_ADDR32:
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
|
||||
rel->r_offset - offset, name, addend);
|
||||
rel->r_offset - start_offset, name, addend);
|
||||
break;
|
||||
case R_PPC_ADDR16_LO:
|
||||
fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n",
|
||||
rel->r_offset - offset, name, addend);
|
||||
rel->r_offset - start_offset, name, addend);
|
||||
break;
|
||||
case R_PPC_ADDR16_HI:
|
||||
fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n",
|
||||
rel->r_offset - offset, name, addend);
|
||||
rel->r_offset - start_offset, name, addend);
|
||||
break;
|
||||
case R_PPC_ADDR16_HA:
|
||||
fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n",
|
||||
rel->r_offset - offset, name, addend);
|
||||
rel->r_offset - start_offset, name, addend);
|
||||
break;
|
||||
case R_PPC_REL24:
|
||||
/* warning: must be at 32 MB distancy */
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n",
|
||||
rel->r_offset - offset, rel->r_offset - offset, name, rel->r_offset - offset, addend);
|
||||
rel->r_offset - start_offset, rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend);
|
||||
break;
|
||||
default:
|
||||
error("unsupported powerpc relocation (%d)", type);
|
||||
@@ -436,8 +611,9 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
int type;
|
||||
int addend;
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
|
||||
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
|
||||
if (rel->r_offset >= start_offset &&
|
||||
rel->r_offset < start_offset + copy_size) {
|
||||
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
|
||||
if (strstart(sym_name, "__op_param", &p)) {
|
||||
snprintf(name, sizeof(name), "param%s", p);
|
||||
} else {
|
||||
@@ -448,15 +624,15 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
switch(type) {
|
||||
case R_390_32:
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
|
||||
rel->r_offset - offset, name, addend);
|
||||
rel->r_offset - start_offset, name, addend);
|
||||
break;
|
||||
case R_390_16:
|
||||
fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n",
|
||||
rel->r_offset - offset, name, addend);
|
||||
rel->r_offset - start_offset, name, addend);
|
||||
break;
|
||||
case R_390_8:
|
||||
fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n",
|
||||
rel->r_offset - offset, name, addend);
|
||||
rel->r_offset - start_offset, name, addend);
|
||||
break;
|
||||
default:
|
||||
error("unsupported s390 relocation (%d)", type);
|
||||
@@ -464,6 +640,210 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined(HOST_ALPHA)
|
||||
{
|
||||
for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) {
|
||||
int type;
|
||||
|
||||
type = ELF64_R_TYPE(rel->r_info);
|
||||
sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
|
||||
switch (type) {
|
||||
case R_ALPHA_GPDISP:
|
||||
/* The gp is just 32 bit, and never changes, so it's easiest to emit it
|
||||
as an immediate instead of constructing it from the pv or ra. */
|
||||
fprintf(outfile, " immediate_ldah(gen_code_ptr + %ld, gp);\n",
|
||||
rel->r_offset - start_offset);
|
||||
fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, gp);\n",
|
||||
rel->r_offset - start_offset + rel->r_addend);
|
||||
break;
|
||||
case R_ALPHA_LITUSE:
|
||||
/* jsr to literal hint. Could be used to optimize to bsr. Ignore for
|
||||
now, since some called functions (libc) need pv to be set up. */
|
||||
break;
|
||||
case R_ALPHA_HINT:
|
||||
/* Branch target prediction hint. Ignore for now. Should be already
|
||||
correct for in-function jumps. */
|
||||
break;
|
||||
case R_ALPHA_LITERAL:
|
||||
/* Load a literal from the GOT relative to the gp. Since there's only a
|
||||
single gp, nothing is to be done. */
|
||||
break;
|
||||
case R_ALPHA_GPRELHIGH:
|
||||
/* Handle fake relocations against __op_param symbol. Need to emit the
|
||||
high part of the immediate value instead. Other symbols need no
|
||||
special treatment. */
|
||||
if (strstart(sym_name, "__op_param", &p))
|
||||
fprintf(outfile, " immediate_ldah(gen_code_ptr + %ld, param%s);\n",
|
||||
rel->r_offset - start_offset, p);
|
||||
break;
|
||||
case R_ALPHA_GPRELLOW:
|
||||
if (strstart(sym_name, "__op_param", &p))
|
||||
fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, param%s);\n",
|
||||
rel->r_offset - start_offset, p);
|
||||
break;
|
||||
case R_ALPHA_BRSGP:
|
||||
/* PC-relative jump. Tweak offset to skip the two instructions that try to
|
||||
set up the gp from the pv. */
|
||||
fprintf(outfile, " fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld) + 4);\n",
|
||||
rel->r_offset - start_offset, sym_name, rel->r_offset - start_offset);
|
||||
break;
|
||||
default:
|
||||
error("unsupported Alpha relocation (%d)", type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined(HOST_IA64)
|
||||
{
|
||||
char name[256];
|
||||
int type;
|
||||
int addend;
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) {
|
||||
sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
|
||||
if (strstart(sym_name, "__op_param", &p)) {
|
||||
snprintf(name, sizeof(name), "param%s", p);
|
||||
} else {
|
||||
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
|
||||
}
|
||||
type = ELF64_R_TYPE(rel->r_info);
|
||||
addend = rel->r_addend;
|
||||
switch(type) {
|
||||
case R_IA64_LTOFF22:
|
||||
error("must implemnt R_IA64_LTOFF22 relocation");
|
||||
case R_IA64_PCREL21B:
|
||||
error("must implemnt R_IA64_PCREL21B relocation");
|
||||
default:
|
||||
error("unsupported ia64 relocation (%d)", type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined(HOST_SPARC)
|
||||
{
|
||||
char name[256];
|
||||
int type;
|
||||
int addend;
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset >= start_offset &&
|
||||
rel->r_offset < start_offset + copy_size) {
|
||||
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
|
||||
if (strstart(sym_name, "__op_param", &p)) {
|
||||
snprintf(name, sizeof(name), "param%s", p);
|
||||
} else {
|
||||
if (sym_name[0] == '.')
|
||||
snprintf(name, sizeof(name),
|
||||
"(long)(&__dot_%s)",
|
||||
sym_name + 1);
|
||||
else
|
||||
snprintf(name, sizeof(name),
|
||||
"(long)(&%s)", sym_name);
|
||||
}
|
||||
type = ELF32_R_TYPE(rel->r_info);
|
||||
addend = rel->r_addend;
|
||||
switch(type) {
|
||||
case R_SPARC_32:
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
|
||||
rel->r_offset - start_offset, name, addend);
|
||||
break;
|
||||
case R_SPARC_HI22:
|
||||
fprintf(outfile,
|
||||
" *(uint32_t *)(gen_code_ptr + %d) = "
|
||||
"((*(uint32_t *)(gen_code_ptr + %d)) "
|
||||
" & ~0x3fffff) "
|
||||
" | (((%s + %d) >> 10) & 0x3fffff);\n",
|
||||
rel->r_offset - start_offset,
|
||||
rel->r_offset - start_offset,
|
||||
name, addend);
|
||||
break;
|
||||
case R_SPARC_LO10:
|
||||
fprintf(outfile,
|
||||
" *(uint32_t *)(gen_code_ptr + %d) = "
|
||||
"((*(uint32_t *)(gen_code_ptr + %d)) "
|
||||
" & ~0x3ff) "
|
||||
" | ((%s + %d) & 0x3ff);\n",
|
||||
rel->r_offset - start_offset,
|
||||
rel->r_offset - start_offset,
|
||||
name, addend);
|
||||
break;
|
||||
case R_SPARC_WDISP30:
|
||||
fprintf(outfile,
|
||||
" *(uint32_t *)(gen_code_ptr + %d) = "
|
||||
"((*(uint32_t *)(gen_code_ptr + %d)) "
|
||||
" & ~0x3fffffff) "
|
||||
" | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
|
||||
" & 0x3fffffff);\n",
|
||||
rel->r_offset - start_offset,
|
||||
rel->r_offset - start_offset,
|
||||
name, addend,
|
||||
rel->r_offset - start_offset);
|
||||
break;
|
||||
default:
|
||||
error("unsupported sparc relocation (%d)", type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined(HOST_SPARC64)
|
||||
{
|
||||
char name[256];
|
||||
int type;
|
||||
int addend;
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset >= start_offset &&
|
||||
rel->r_offset < start_offset + copy_size) {
|
||||
sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
|
||||
if (strstart(sym_name, "__op_param", &p)) {
|
||||
snprintf(name, sizeof(name), "param%s", p);
|
||||
} else {
|
||||
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
|
||||
}
|
||||
type = ELF64_R_TYPE(rel->r_info);
|
||||
addend = rel->r_addend;
|
||||
switch(type) {
|
||||
case R_SPARC_32:
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
|
||||
rel->r_offset - start_offset, name, addend);
|
||||
break;
|
||||
case R_SPARC_HI22:
|
||||
fprintf(outfile,
|
||||
" *(uint32_t *)(gen_code_ptr + %d) = "
|
||||
"((*(uint32_t *)(gen_code_ptr + %d)) "
|
||||
" & ~0x3fffff) "
|
||||
" | (((%s + %d) >> 10) & 0x3fffff);\n",
|
||||
rel->r_offset - start_offset,
|
||||
rel->r_offset - start_offset,
|
||||
name, addend);
|
||||
break;
|
||||
case R_SPARC_LO10:
|
||||
fprintf(outfile,
|
||||
" *(uint32_t *)(gen_code_ptr + %d) = "
|
||||
"((*(uint32_t *)(gen_code_ptr + %d)) "
|
||||
" & ~0x3ff) "
|
||||
" | ((%s + %d) & 0x3ff);\n",
|
||||
rel->r_offset - start_offset,
|
||||
rel->r_offset - start_offset,
|
||||
name, addend);
|
||||
break;
|
||||
case R_SPARC_WDISP30:
|
||||
fprintf(outfile,
|
||||
" *(uint32_t *)(gen_code_ptr + %d) = "
|
||||
"((*(uint32_t *)(gen_code_ptr + %d)) "
|
||||
" & ~0x3fffffff) "
|
||||
" | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
|
||||
" & 0x3fffffff);\n",
|
||||
rel->r_offset - start_offset,
|
||||
rel->r_offset - start_offset,
|
||||
name, addend,
|
||||
rel->r_offset - start_offset);
|
||||
break;
|
||||
default:
|
||||
error("unsupported sparc64 relocation (%d)", type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
@@ -495,11 +875,10 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
int load_elf(const char *filename, FILE *outfile, int do_print_enum)
|
||||
{
|
||||
int fd;
|
||||
struct elfhdr ehdr;
|
||||
struct elf_shdr *sec, *shdr, *symtab_sec, *strtab_sec, *text_sec;
|
||||
int i, j, nb_syms;
|
||||
ElfW(Sym) *symtab, *sym;
|
||||
char *shstr, *strtab;
|
||||
struct elf_shdr *sec, *symtab_sec, *strtab_sec, *text_sec;
|
||||
int i, j;
|
||||
ElfW(Sym) *sym;
|
||||
char *shstr, *data_name;
|
||||
uint8_t *text;
|
||||
void *relocs;
|
||||
int nb_relocs, reloc_sh_type;
|
||||
@@ -551,6 +930,17 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
|
||||
error("could not find .text section");
|
||||
text = load_data(fd, text_sec->sh_offset, text_sec->sh_size);
|
||||
|
||||
#if defined(HOST_PPC)
|
||||
data_name = ".sdata";
|
||||
#else
|
||||
data_name = ".data";
|
||||
#endif
|
||||
sec = find_elf_section(shdr, ehdr.e_shnum, shstr, data_name);
|
||||
if (!sec)
|
||||
error("could not find %s section", data_name);
|
||||
data_shndx = sec - shdr;
|
||||
data_data = load_data(fd, sec->sh_offset, sec->sh_size);
|
||||
|
||||
/* find text relocations, if any */
|
||||
nb_relocs = 0;
|
||||
relocs = NULL;
|
||||
@@ -564,17 +954,17 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
|
||||
nb_relocs = sec->sh_size / sec->sh_entsize;
|
||||
if (do_swap) {
|
||||
if (sec->sh_type == SHT_REL) {
|
||||
Elf32_Rel *rel = relocs;
|
||||
ElfW(Rel) *rel = relocs;
|
||||
for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) {
|
||||
swab32s(&rel->r_offset);
|
||||
swab32s(&rel->r_info);
|
||||
swabls(&rel->r_offset);
|
||||
swabls(&rel->r_info);
|
||||
}
|
||||
} else {
|
||||
Elf32_Rela *rel = relocs;
|
||||
ElfW(Rela) *rel = relocs;
|
||||
for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) {
|
||||
swab32s(&rel->r_offset);
|
||||
swab32s(&rel->r_info);
|
||||
swab32s(&rel->r_addend);
|
||||
swabls(&rel->r_offset);
|
||||
swabls(&rel->r_info);
|
||||
swabls(&rel->r_addend);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -590,7 +980,7 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
|
||||
symtab = load_data(fd, symtab_sec->sh_offset, symtab_sec->sh_size);
|
||||
strtab = load_data(fd, strtab_sec->sh_offset, strtab_sec->sh_size);
|
||||
|
||||
nb_syms = symtab_sec->sh_size / sizeof(Elf32_Sym);
|
||||
nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym));
|
||||
if (do_swap) {
|
||||
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
|
||||
swab32s(&sym->st_name);
|
||||
@@ -601,19 +991,40 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
|
||||
}
|
||||
|
||||
if (do_print_enum) {
|
||||
fprintf(outfile, "DEF(end, 0)\n");
|
||||
fprintf(outfile, "DEF(end, 0, 0)\n");
|
||||
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
|
||||
const char *name, *p;
|
||||
name = strtab + sym->st_name;
|
||||
if (strstart(name, OP_PREFIX, &p)) {
|
||||
gen_code(name, sym->st_value, sym->st_size, outfile,
|
||||
text, relocs, nb_relocs, reloc_sh_type, symtab, strtab, 2);
|
||||
text, relocs, nb_relocs, reloc_sh_type, 2);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* generate big code generation switch */
|
||||
#ifdef HOST_ALPHA
|
||||
fprintf(outfile,
|
||||
"register int gp asm(\"$29\");\n"
|
||||
"static inline void immediate_ldah(void *p, int val) {\n"
|
||||
" uint32_t *dest = p;\n"
|
||||
" long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff;\n"
|
||||
"\n"
|
||||
" *dest &= ~0xffff;\n"
|
||||
" *dest |= high;\n"
|
||||
" *dest |= 31 << 16;\n"
|
||||
"}\n"
|
||||
"static inline void immediate_lda(void *dest, int val) {\n"
|
||||
" *(uint16_t *) dest = val;\n"
|
||||
"}\n"
|
||||
"void fix_bsr(void *p, int offset) {\n"
|
||||
" uint32_t *dest = p;\n"
|
||||
" *dest &= ~((1 << 21) - 1);\n"
|
||||
" *dest |= (offset >> 2) & ((1 << 21) - 1);\n"
|
||||
"}\n");
|
||||
#endif
|
||||
fprintf(outfile,
|
||||
"int dyngen_code(uint8_t *gen_code_buf,\n"
|
||||
" uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
|
||||
" const uint16_t *opc_buf, const uint32_t *opparam_buf)\n"
|
||||
"{\n"
|
||||
" uint8_t *gen_code_ptr;\n"
|
||||
@@ -621,7 +1032,22 @@ fprintf(outfile,
|
||||
" const uint32_t *opparam_ptr;\n"
|
||||
" gen_code_ptr = gen_code_buf;\n"
|
||||
" opc_ptr = opc_buf;\n"
|
||||
" opparam_ptr = opparam_buf;\n"
|
||||
" opparam_ptr = opparam_buf;\n");
|
||||
|
||||
/* Generate prologue, if needed. */
|
||||
switch(ELF_ARCH) {
|
||||
case EM_SPARC:
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c23a080; /* sub %%sp, 128, %%sp */\n");
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc27a080; /* sub %%fp, 128, %%fp */\n");
|
||||
break;
|
||||
|
||||
case EM_SPARCV9:
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c23a100; /* sub %%sp, 256, %%sp */\n");
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc27a100; /* sub %%fp, 256, %%fp */\n");
|
||||
break;
|
||||
};
|
||||
|
||||
fprintf(outfile,
|
||||
" for(;;) {\n"
|
||||
" switch(*opc_ptr++) {\n"
|
||||
);
|
||||
@@ -637,7 +1063,7 @@ fprintf(outfile,
|
||||
if (sym->st_shndx != (text_sec - shdr))
|
||||
error("invalid section for opcode (0x%x)", sym->st_shndx);
|
||||
gen_code(name, sym->st_value, sym->st_size, outfile,
|
||||
text, relocs, nb_relocs, reloc_sh_type, symtab, strtab, 1);
|
||||
text, relocs, nb_relocs, reloc_sh_type, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -649,7 +1075,7 @@ fprintf(outfile,
|
||||
" the_end:\n"
|
||||
);
|
||||
|
||||
/* generate a return */
|
||||
/* generate epilogue */
|
||||
switch(ELF_ARCH) {
|
||||
case EM_386:
|
||||
fprintf(outfile, "*gen_code_ptr++ = 0xc3; /* ret */\n");
|
||||
@@ -660,6 +1086,24 @@ fprintf(outfile,
|
||||
case EM_S390:
|
||||
fprintf(outfile, "*((uint16_t *)gen_code_ptr)++ = 0x07fe; /* br %%r14 */\n");
|
||||
break;
|
||||
case EM_ALPHA:
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x6bfa8001; /* ret */\n");
|
||||
break;
|
||||
case EM_IA_64:
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x00840008; /* br.ret.sptk.many b0;; */\n");
|
||||
break;
|
||||
case EM_SPARC:
|
||||
case EM_SPARC32PLUS:
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc07a080; /* add %%fp, 256, %%fp */\n");
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c62008; /* jmpl %%i0 + 8, %%g0 */\n");
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c03a080; /* add %%sp, 256, %%sp */\n");
|
||||
break;
|
||||
case EM_SPARCV9:
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c7e008; /* ret */\n");
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81e80000; /* restore */\n");
|
||||
break;
|
||||
default:
|
||||
error("unknown ELF architecture");
|
||||
}
|
||||
|
||||
fprintf(outfile, "return gen_code_ptr - gen_code_buf;\n");
|
||||
@@ -674,7 +1118,7 @@ fprintf(outfile,
|
||||
if (sym->st_shndx != (text_sec - shdr))
|
||||
error("invalid section for opcode (0x%x)", sym->st_shndx);
|
||||
gen_code(name, sym->st_value, sym->st_size, outfile,
|
||||
text, relocs, nb_relocs, reloc_sh_type, symtab, strtab, 0);
|
||||
text, relocs, nb_relocs, reloc_sh_type, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
116
elf.h
116
elf.h
@@ -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 */
|
||||
|
410
exec-i386.c
410
exec-i386.c
@@ -18,107 +18,38 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "exec-i386.h"
|
||||
#include "disas.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;
|
||||
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
void cpu_lock(void)
|
||||
{
|
||||
while (testandset(&global_cpu_lock));
|
||||
spin_lock(&global_cpu_lock);
|
||||
}
|
||||
|
||||
void cpu_unlock(void)
|
||||
{
|
||||
global_cpu_lock = 0;
|
||||
spin_unlock(&global_cpu_lock);
|
||||
}
|
||||
|
||||
/* exception support */
|
||||
/* NOTE: not static to force relocation generation by GCC */
|
||||
void raise_exception(int exception_index)
|
||||
void cpu_loop_exit(void)
|
||||
{
|
||||
/* NOTE: the register at this point must be saved by hand because
|
||||
longjmp restore them */
|
||||
#ifdef __sparc__
|
||||
/* We have to stay in the same register window as our caller,
|
||||
* thus this trick.
|
||||
*/
|
||||
__asm__ __volatile__("restore\n\t"
|
||||
"mov\t%o0, %i0");
|
||||
#endif
|
||||
#ifdef reg_EAX
|
||||
env->regs[R_EAX] = EAX;
|
||||
#endif
|
||||
@@ -143,133 +74,9 @@ void raise_exception(int exception_index)
|
||||
#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;
|
||||
@@ -303,7 +110,7 @@ int cpu_x86_exec(CPUX86State *env1)
|
||||
TranslationBlock *tb, **ptb;
|
||||
uint8_t *tc_ptr, *cs_base, *pc;
|
||||
unsigned int flags;
|
||||
|
||||
|
||||
/* first we save global registers */
|
||||
saved_T0 = T0;
|
||||
saved_T1 = T1;
|
||||
@@ -349,16 +156,30 @@ int cpu_x86_exec(CPUX86State *env1)
|
||||
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) {
|
||||
T0 = 0; /* force lookup of first TB */
|
||||
for(;;) {
|
||||
if (env->interrupt_request) {
|
||||
raise_exception(EXCP_INTERRUPT);
|
||||
env->exception_index = EXCP_INTERRUPT;
|
||||
cpu_loop_exit();
|
||||
}
|
||||
#ifdef DEBUG_EXEC
|
||||
if (loglevel) {
|
||||
cpu_x86_dump_state(logfile);
|
||||
/* XXX: save all volatile state in cpu state */
|
||||
/* 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, 0);
|
||||
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||
}
|
||||
#endif
|
||||
/* we compute the CPU state. We assume it will not
|
||||
@@ -369,38 +190,76 @@ int cpu_x86_exec(CPUX86State *env1)
|
||||
(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);
|
||||
if (!(env->eflags & VM_MASK)) {
|
||||
flags |= (env->segs[R_CS] & 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->seg_cache[R_CS].base;
|
||||
pc = cs_base + env->eip;
|
||||
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 */
|
||||
/* 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((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;
|
||||
}
|
||||
tb = tb_alloc();
|
||||
*ptb = tb;
|
||||
tb->pc = (unsigned long)pc;
|
||||
tc_ptr = code_gen_ptr;
|
||||
tb->tc_ptr = tc_ptr;
|
||||
tb->cs_base = (unsigned long)cs_base;
|
||||
tb->flags = flags;
|
||||
tb->tc_ptr = tc_ptr;
|
||||
ret = cpu_x86_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size);
|
||||
/* 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);
|
||||
}
|
||||
*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));
|
||||
cpu_unlock();
|
||||
spin_unlock(&tb_lock);
|
||||
}
|
||||
/* execute the generated code */
|
||||
#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
|
||||
/* see if we can patch the calling TB */
|
||||
if (T0 != 0 && !(env->eflags & TF_MASK)) {
|
||||
spin_lock(&tb_lock);
|
||||
tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
|
||||
spin_unlock(&tb_lock);
|
||||
}
|
||||
|
||||
tc_ptr = tb->tc_ptr;
|
||||
|
||||
/* execute the generated code */
|
||||
gen_func = (void *)tc_ptr;
|
||||
#ifdef __sparc__
|
||||
__asm__ __volatile__("call %0\n\t"
|
||||
" mov %%o7,%%i0"
|
||||
: /* no outputs */
|
||||
: "r" (gen_func)
|
||||
: "i0", "i1", "i2", "i3", "i4", "i5");
|
||||
#else
|
||||
gen_func();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
ret = env->exception_index;
|
||||
@@ -452,7 +311,19 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
|
||||
|
||||
saved_env = env;
|
||||
env = s;
|
||||
load_seg(seg_reg, selector);
|
||||
if (env->eflags & VM_MASK) {
|
||||
SegmentCache *sc;
|
||||
selector &= 0xffff;
|
||||
sc = &env->seg_cache[seg_reg];
|
||||
/* NOTE: in VM86 mode, limit and seg_32bit are never reloaded,
|
||||
so we must load them here */
|
||||
sc->base = (void *)(selector << 4);
|
||||
sc->limit = 0xffff;
|
||||
sc->seg_32bit = 0;
|
||||
env->segs[seg_reg] = selector;
|
||||
} else {
|
||||
load_seg(seg_reg, selector, 0);
|
||||
}
|
||||
env = saved_env;
|
||||
}
|
||||
|
||||
@@ -468,23 +339,38 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
|
||||
#include <signal.h>
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
static inline int handle_cpu_signal(unsigned long pc,
|
||||
sigset_t *old_set)
|
||||
/* '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)
|
||||
{
|
||||
#ifdef DEBUG_SIGNAL
|
||||
printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n",
|
||||
pc, *(unsigned long *)old_set);
|
||||
TranslationBlock *tb;
|
||||
int ret;
|
||||
uint32_t found_pc;
|
||||
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n",
|
||||
pc, address, is_write, *(unsigned long *)old_set);
|
||||
#endif
|
||||
if (pc >= (unsigned long)code_gen_buffer &&
|
||||
pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
|
||||
/* XXX: locking issue */
|
||||
if (is_write && page_unprotect(address)) {
|
||||
return 1;
|
||||
}
|
||||
tb = tb_find_pc(pc);
|
||||
if (tb) {
|
||||
/* the PC is inside the translated code. It means that we have
|
||||
a virtual CPU fault */
|
||||
ret = cpu_x86_search_pc(tb, &found_pc, pc);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
env->eip = found_pc - tb->cs_base;
|
||||
env->cr2 = address;
|
||||
/* we restore the process signal mask as the sigreturn should
|
||||
do it */
|
||||
do it (XXX: use sigsetjmp) */
|
||||
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);
|
||||
raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1));
|
||||
/* never comes here */
|
||||
return 1;
|
||||
} else {
|
||||
@@ -492,23 +378,53 @@ static inline int handle_cpu_signal(unsigned long pc,
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
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
|
||||
#define REG_EIP EIP
|
||||
#define REG_ERR ERR
|
||||
#define REG_TRAPNO TRAPNO
|
||||
#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
|
||||
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_x86_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);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error CPU specific signal handler needed
|
||||
|
||||
#endif
|
||||
|
65
exec-i386.h
65
exec-i386.h
@@ -89,10 +89,27 @@ 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");
|
||||
register unsigned int EAX asm("l0");
|
||||
register unsigned int ECX asm("l1");
|
||||
register unsigned int EDX asm("l2");
|
||||
register unsigned int EBX asm("l3");
|
||||
register unsigned int ESP asm("l4");
|
||||
register unsigned int EBP asm("l5");
|
||||
register unsigned int ESI asm("l6");
|
||||
register unsigned int EDI asm("l7");
|
||||
register unsigned int T0 asm("g1");
|
||||
register unsigned int T1 asm("g2");
|
||||
register unsigned int A0 asm("g3");
|
||||
register struct CPUX86State *env asm("g6");
|
||||
#define USE_FP_CONVERT
|
||||
#define reg_EAX
|
||||
#define reg_ECX
|
||||
#define reg_EDX
|
||||
#define reg_EBX
|
||||
#define reg_ESP
|
||||
#define reg_EBP
|
||||
#define reg_ESI
|
||||
#define reg_EDI
|
||||
#endif
|
||||
#ifdef __s390__
|
||||
register unsigned int T0 asm("r7");
|
||||
@@ -104,7 +121,19 @@ register struct CPUX86State *env asm("r10");
|
||||
register unsigned int T0 asm("$9");
|
||||
register unsigned int T1 asm("$10");
|
||||
register unsigned int A0 asm("$11");
|
||||
register struct CPUX86State *env asm("$12");
|
||||
register unsigned int EAX asm("$12");
|
||||
register unsigned int ESP asm("$13");
|
||||
register unsigned int EBP asm("$14");
|
||||
register struct CPUX86State *env asm("$15");
|
||||
#define reg_EAX
|
||||
#define reg_ESP
|
||||
#define reg_EBP
|
||||
#endif
|
||||
#ifdef __ia64__
|
||||
register unsigned int T0 asm("r24");
|
||||
register unsigned int T1 asm("r25");
|
||||
register unsigned int A0 asm("r26");
|
||||
register struct CPUX86State *env asm("r27");
|
||||
#endif
|
||||
|
||||
/* force GCC to generate only one epilog at the end of the function */
|
||||
@@ -154,12 +183,32 @@ register struct CPUX86State *env asm("$12");
|
||||
#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7])
|
||||
#define ST1 ST(1)
|
||||
|
||||
#ifdef USE_FP_CONVERT
|
||||
#define FP_CONVERT (env->fp_convert)
|
||||
#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 __attribute__((visibility("hidden")));
|
||||
extern int __op_param2 __attribute__((visibility("hidden")));
|
||||
extern int __op_param3 __attribute__((visibility("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;
|
||||
|
||||
#include "cpu-i386.h"
|
||||
#include "exec.h"
|
||||
|
||||
typedef struct CCTable {
|
||||
int (*compute_all)(void); /* return all the flags */
|
||||
@@ -168,10 +217,14 @@ typedef struct CCTable {
|
||||
|
||||
extern CCTable cc_table[];
|
||||
|
||||
void load_seg(int seg_reg, int selector);
|
||||
void load_seg(int seg_reg, int selector, unsigned cur_eip);
|
||||
void cpu_lock(void);
|
||||
void cpu_unlock(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 cpu_loop_exit(void);
|
||||
|
||||
void OPPROTO op_movl_eflags_T0(void);
|
||||
void OPPROTO op_movl_T0_eflags(void);
|
||||
|
564
exec.c
Normal file
564
exec.c
Normal file
@@ -0,0 +1,564 @@
|
||||
/*
|
||||
* 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 "cpu-i386.h"
|
||||
#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];
|
||||
|
||||
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_x86_tblocks_init(void)
|
||||
{
|
||||
if (!code_gen_ptr) {
|
||||
code_gen_ptr = code_gen_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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];
|
||||
}
|
269
exec.h
Normal file
269
exec.h
Normal file
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#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 */
|
||||
|
||||
struct TranslationBlock;
|
||||
int cpu_x86_gen_code(struct TranslationBlock *tb,
|
||||
int max_code_size, int *gen_code_size_ptr);
|
||||
int cpu_x86_search_pc(struct TranslationBlock *tb,
|
||||
uint32_t *found_pc, unsigned long searched_pc);
|
||||
void cpu_x86_tblocks_init(void);
|
||||
void page_init(void);
|
||||
int page_unprotect(unsigned long address);
|
||||
|
||||
#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
|
||||
uint8_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] = (void *)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
|
||||
|
||||
#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__
|
||||
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
|
||||
|
||||
typedef int spinlock_t;
|
||||
|
||||
#define SPIN_LOCK_UNLOCKED 0
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
extern spinlock_t tb_lock;
|
||||
|
32
ia64-syscall.S
Normal file
32
ia64-syscall.S
Normal file
@@ -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
|
@@ -11,6 +11,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "qemu.h"
|
||||
#include "disas.h"
|
||||
|
||||
#ifdef TARGET_I386
|
||||
|
||||
@@ -94,8 +95,6 @@ struct exec
|
||||
#define ZMAGIC 0413
|
||||
#define QMAGIC 0314
|
||||
|
||||
#define X86_STACK_TOP 0x7d000000
|
||||
|
||||
/* max code+data+bss space allocated to elf interpreter */
|
||||
#define INTERP_MAP_SIZE (32 * 1024 * 1024)
|
||||
|
||||
@@ -122,23 +121,11 @@ struct exec
|
||||
#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
|
||||
@@ -159,9 +146,6 @@ static inline void memcpy_tofs(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)
|
||||
|
||||
extern unsigned long x86_stack_size;
|
||||
|
||||
static int load_aout_interp(void * exptr, int interp_fd);
|
||||
@@ -195,6 +179,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)
|
||||
@@ -204,8 +210,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");
|
||||
@@ -218,7 +224,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);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -249,9 +255,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;
|
||||
}
|
||||
@@ -367,21 +373,21 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
|
||||
* it for args, we'll use it for something else...
|
||||
*/
|
||||
size = x86_stack_size;
|
||||
if (size < MAX_ARG_PAGES*X86_PAGE_SIZE)
|
||||
size = MAX_ARG_PAGES*X86_PAGE_SIZE;
|
||||
error = (unsigned long)mmap4k(NULL,
|
||||
size + X86_PAGE_SIZE,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
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 */
|
||||
mprotect((void *)(error + size), X86_PAGE_SIZE, PROT_NONE);
|
||||
target_mprotect(error + size, host_page_size, PROT_NONE);
|
||||
|
||||
stack_base = error + size - MAX_ARG_PAGES*X86_PAGE_SIZE;
|
||||
stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
|
||||
p += stack_base;
|
||||
|
||||
if (bprm->loader) {
|
||||
@@ -393,10 +399,10 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
|
||||
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;
|
||||
}
|
||||
@@ -404,13 +410,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);
|
||||
}
|
||||
@@ -428,9 +434,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;
|
||||
@@ -471,7 +477,7 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
|
||||
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)(ALPHA_PAGE_SIZE));
|
||||
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);
|
||||
@@ -531,7 +537,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 *)
|
||||
@@ -571,9 +577,9 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
|
||||
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 = (unsigned long)mmap4k(NULL, INTERP_MAP_SIZE,
|
||||
PROT_NONE, MAP_PRIVATE | MAP_ANON,
|
||||
-1, 0);
|
||||
error = target_mmap(0, INTERP_MAP_SIZE,
|
||||
PROT_NONE, MAP_PRIVATE | MAP_ANON,
|
||||
-1, 0);
|
||||
if (error == -1) {
|
||||
perror("mmap");
|
||||
exit(-1);
|
||||
@@ -597,12 +603,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 */
|
||||
@@ -642,13 +648,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);
|
||||
|
||||
@@ -656,7 +662,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)
|
||||
@@ -670,7 +725,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
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;
|
||||
@@ -907,33 +962,32 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
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 = (unsigned long)mmap4k(NULL, ET_DYN_MAP_SIZE,
|
||||
PROT_NONE, MAP_PRIVATE | MAP_ANON,
|
||||
-1, 0);
|
||||
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 = X86_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
|
||||
load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
|
||||
}
|
||||
|
||||
error = (unsigned long)mmap4k(
|
||||
X86_ELF_PAGESTART(load_bias + 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)));
|
||||
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) {
|
||||
@@ -941,7 +995,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
|
||||
if (elf_ex.e_type == ET_DYN) {
|
||||
load_bias += error -
|
||||
X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
|
||||
TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
|
||||
load_addr += load_bias;
|
||||
}
|
||||
}
|
||||
@@ -989,6 +1043,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);
|
||||
|
||||
@@ -1033,8 +1090,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
|
||||
@@ -1062,7 +1119,7 @@ int elf_exec(const char * filename, char ** argv, char ** envp,
|
||||
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);
|
||||
|
@@ -51,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)
|
||||
|
@@ -67,181 +67,70 @@ void gemu_log(const char *fmt, ...)
|
||||
/***********************************************************/
|
||||
/* 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)
|
||||
static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
|
||||
int flags)
|
||||
{
|
||||
unsigned int e1, e2, limit_in_pages;
|
||||
limit_in_pages = 0;
|
||||
if (limit > 0xffff) {
|
||||
limit = limit >> 12;
|
||||
limit_in_pages = 1;
|
||||
}
|
||||
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;
|
||||
@@ -249,69 +138,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->cr2;
|
||||
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;
|
||||
@@ -321,14 +191,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);
|
||||
}
|
||||
@@ -344,6 +231,7 @@ void cpu_loop(struct CPUX86State *env)
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
default:
|
||||
pc = env->seg_cache[R_CS].base + env->eip;
|
||||
fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
|
||||
(long)pc, trapnr);
|
||||
abort();
|
||||
@@ -358,13 +246,16 @@ void usage(void)
|
||||
"usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]\n"
|
||||
"Linux x86 emulator\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 x86 elf interpreter prefix (default=%s)\n"
|
||||
"-s size set the x86 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",
|
||||
interp_prefix,
|
||||
x86_stack_size);
|
||||
x86_stack_size,
|
||||
DEBUG_LOGFILE);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
@@ -411,6 +302,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();
|
||||
}
|
||||
@@ -438,12 +336,18 @@ int main(int argc, char **argv)
|
||||
/* 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_x86_init();
|
||||
|
||||
if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
|
||||
printf("Error loading %s\n", filename);
|
||||
_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);
|
||||
@@ -458,7 +362,6 @@ int main(int argc, char **argv)
|
||||
syscall_init();
|
||||
signal_init();
|
||||
|
||||
env = cpu_x86_init();
|
||||
global_env = env;
|
||||
|
||||
/* build Task State */
|
||||
@@ -477,11 +380,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);
|
||||
|
381
linux-user/mmap.c
Normal file
381
linux-user/mmap.c
Normal file
@@ -0,0 +1,381 @@
|
||||
/*
|
||||
* 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 (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) {
|
||||
ret = (long)mmap((void *)host_start, host_end - host_start,
|
||||
prot, flags, fd, offset + host_start - start);
|
||||
if (ret == -1)
|
||||
return ret;
|
||||
}
|
||||
the_end1:
|
||||
page_set_flags(start, start + len, prot | PAGE_VALID);
|
||||
the_end:
|
||||
#ifdef DEBUG_MMAP
|
||||
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);
|
||||
}
|
||||
|
@@ -54,6 +54,9 @@ typedef struct TaskState {
|
||||
struct TaskState *next;
|
||||
struct target_vm86plus_struct *target_v86;
|
||||
struct vm86_saved_state vm86_saved_regs;
|
||||
struct target_vm86plus_struct vm86plus;
|
||||
uint32_t v86flags;
|
||||
uint32_t v86mask;
|
||||
int used; /* non zero if used */
|
||||
uint8_t stack[0];
|
||||
} __attribute__((aligned(16))) TaskState;
|
||||
@@ -73,7 +76,27 @@ void cpu_loop(CPUX86State *env);
|
||||
void process_pending_signals(void *cpu_env);
|
||||
void signal_init(void);
|
||||
int queue_signal(int sig, target_siginfo_t *info);
|
||||
void save_v86_state(CPUX86State *env);
|
||||
void init_paths(const char *prefix);
|
||||
const char *path(const char *pathname);
|
||||
|
||||
extern int loglevel;
|
||||
extern FILE *logfile;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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
|
||||
|
@@ -26,6 +26,13 @@
|
||||
#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
|
||||
@@ -103,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;
|
||||
@@ -124,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) {
|
||||
@@ -166,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));
|
||||
@@ -520,8 +529,8 @@ 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->eflags, &sc->eflags);
|
||||
@@ -538,7 +547,7 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
|
||||
#endif
|
||||
/* non-iBCS2 extensions.. */
|
||||
err |= __put_user(mask, &sc->oldmask);
|
||||
err |= __put_user(/*current->thread.cr2*/ 0, &sc->cr2);
|
||||
err |= __put_user(env->cr2, &sc->cr2);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -781,6 +790,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++)
|
||||
|
@@ -58,16 +58,12 @@
|
||||
#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])
|
||||
@@ -85,7 +81,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
|
||||
|
||||
@@ -117,6 +113,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)
|
||||
{
|
||||
@@ -151,7 +148,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) {
|
||||
@@ -160,11 +157,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 {
|
||||
@@ -219,6 +215,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)
|
||||
{
|
||||
@@ -1028,7 +1047,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));
|
||||
@@ -1056,78 +1075,6 @@ 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;
|
||||
}
|
||||
|
||||
/* this stack is the equivalent of the kernel stack associated with a
|
||||
thread/process */
|
||||
#define NEW_STACK_SIZE 8192
|
||||
@@ -1163,7 +1110,11 @@ int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp)
|
||||
new_env->regs[R_ESP] = newsp;
|
||||
new_env->regs[R_EAX] = 0;
|
||||
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)
|
||||
@@ -1175,6 +1126,49 @@ int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp)
|
||||
|
||||
#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)
|
||||
#define low2highuid(x) (x)
|
||||
@@ -1209,6 +1203,7 @@ 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:
|
||||
@@ -1414,15 +1409,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;
|
||||
@@ -1672,7 +1659,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;
|
||||
@@ -1692,9 +1687,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:
|
||||
@@ -1725,7 +1744,7 @@ 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, v4, v5, v6));
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
@@ -1734,16 +1753,17 @@ 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, arg4, 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));
|
||||
@@ -1898,24 +1918,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2213,9 +2216,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;
|
||||
@@ -2238,7 +2244,16 @@ 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:
|
||||
@@ -2257,7 +2272,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
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
|
||||
@@ -2356,16 +2371,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;
|
||||
|
@@ -212,6 +212,13 @@ struct target_pollfd {
|
||||
short revents; /* returned events */
|
||||
};
|
||||
|
||||
/* virtual terminal ioctls */
|
||||
#define TARGET_KIOCSOUND 0x4B2F /* start sound generation (0 for off) */
|
||||
#define TARGET_KDMKTONE 0x4B30 /* generate tone */
|
||||
#define TARGET_KDGKBTYPE 0x4b33
|
||||
#define TARGET_KDGKBENT 0x4B46 /* gets one entry in translation table */
|
||||
#define TARGET_KDGKBSENT 0x4B48 /* gets one function key string entry */
|
||||
|
||||
/* Networking ioctls */
|
||||
#define TARGET_SIOCADDRT 0x890B /* add routing table entry */
|
||||
#define TARGET_SIOCDELRT 0x890C /* delete routing table entry */
|
||||
|
@@ -64,3 +64,6 @@ STRUCT(hd_geometry,
|
||||
|
||||
STRUCT(dirent,
|
||||
TYPE_LONG, TYPE_LONG, TYPE_SHORT, MK_ARRAY(TYPE_CHAR, 256))
|
||||
|
||||
STRUCT(kbentry,
|
||||
TYPE_CHAR, TYPE_CHAR, TYPE_SHORT)
|
||||
|
475
linux-user/vm86.c
Normal file
475
linux-user/vm86.c
Normal file
@@ -0,0 +1,475 @@
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
*(uint16_t *)(segptr + (reg16 & 0xffff)) = tswap16(val);
|
||||
}
|
||||
|
||||
static inline void vm_putl(uint8_t *segptr, unsigned int reg16, unsigned int val)
|
||||
{
|
||||
*(uint32_t *)(segptr + (reg16 & 0xffff)) = tswap32(val);
|
||||
}
|
||||
|
||||
static inline unsigned int vm_getw(uint8_t *segptr, unsigned int reg16)
|
||||
{
|
||||
return tswap16(*(uint16_t *)(segptr + (reg16 & 0xffff)));
|
||||
}
|
||||
|
||||
static inline unsigned int vm_getl(uint8_t *segptr, unsigned int reg16)
|
||||
{
|
||||
return tswap32(*(uint32_t *)(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]);
|
||||
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]);
|
||||
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], 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;
|
||||
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] == 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] << 4);
|
||||
sp = env->regs[R_ESP] & 0xffff;
|
||||
vm_putw(ssp, sp - 2, get_vflags(env));
|
||||
vm_putw(ssp, sp - 4, env->segs[R_CS]);
|
||||
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] << 4);
|
||||
ip = env->eip & 0xffff;
|
||||
pc = csp + ip;
|
||||
|
||||
ssp = (uint8_t *)(env->segs[R_SS] << 4);
|
||||
sp = env->regs[R_ESP] & 0xffff;
|
||||
|
||||
#if defined(DEBUG_VM86)
|
||||
fprintf(logfile, "VM86 exception %04x:%08x %02x %02x\n",
|
||||
env->segs[R_CS], 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];
|
||||
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 */
|
||||
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], env->eip);
|
||||
#endif
|
||||
/* now the virtual CPU is ready for vm86 execution ! */
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
506
op-i386.c
506
op-i386.c
@@ -364,8 +364,10 @@ void OPPROTO op_divb_AL_T0(void)
|
||||
|
||||
num = (EAX & 0xffff);
|
||||
den = (T0 & 0xff);
|
||||
if (den == 0)
|
||||
if (den == 0) {
|
||||
EIP = PARAM1;
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
}
|
||||
q = (num / den) & 0xff;
|
||||
r = (num % den) & 0xff;
|
||||
EAX = (EAX & 0xffff0000) | (r << 8) | q;
|
||||
@@ -377,8 +379,10 @@ void OPPROTO op_idivb_AL_T0(void)
|
||||
|
||||
num = (int16_t)EAX;
|
||||
den = (int8_t)T0;
|
||||
if (den == 0)
|
||||
if (den == 0) {
|
||||
EIP = PARAM1;
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
}
|
||||
q = (num / den) & 0xff;
|
||||
r = (num % den) & 0xff;
|
||||
EAX = (EAX & 0xffff0000) | (r << 8) | q;
|
||||
@@ -390,8 +394,10 @@ void OPPROTO op_divw_AX_T0(void)
|
||||
|
||||
num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
|
||||
den = (T0 & 0xffff);
|
||||
if (den == 0)
|
||||
if (den == 0) {
|
||||
EIP = PARAM1;
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
}
|
||||
q = (num / den) & 0xffff;
|
||||
r = (num % den) & 0xffff;
|
||||
EAX = (EAX & 0xffff0000) | q;
|
||||
@@ -404,8 +410,10 @@ void OPPROTO op_idivw_AX_T0(void)
|
||||
|
||||
num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
|
||||
den = (int16_t)T0;
|
||||
if (den == 0)
|
||||
if (den == 0) {
|
||||
EIP = PARAM1;
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
}
|
||||
q = (num / den) & 0xffff;
|
||||
r = (num % den) & 0xffff;
|
||||
EAX = (EAX & 0xffff0000) | q;
|
||||
@@ -435,8 +443,10 @@ void OPPROTO op_divl_EAX_T0(void)
|
||||
|
||||
num = EAX | ((uint64_t)EDX << 32);
|
||||
den = T0;
|
||||
if (den == 0)
|
||||
if (den == 0) {
|
||||
EIP = PARAM1;
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
}
|
||||
#ifdef BUGGY_GCC_DIV64
|
||||
r = div64(&q, num, den);
|
||||
#else
|
||||
@@ -454,8 +464,10 @@ void OPPROTO op_idivl_EAX_T0(void)
|
||||
|
||||
num = EAX | ((uint64_t)EDX << 32);
|
||||
den = T0;
|
||||
if (den == 0)
|
||||
if (den == 0) {
|
||||
EIP = PARAM1;
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
}
|
||||
#ifdef BUGGY_GCC_DIV64
|
||||
r = idiv64(&q, num, den);
|
||||
#else
|
||||
@@ -614,16 +626,109 @@ void OPPROTO op_jmp_im(void)
|
||||
EIP = PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_int_im(void)
|
||||
#if 0
|
||||
/* full interrupt support (only useful for real CPU emulation, not
|
||||
finished) - I won't do it any time soon, finish it if you want ! */
|
||||
void raise_interrupt(int intno, int is_int, int error_code,
|
||||
unsigned int next_eip)
|
||||
{
|
||||
EIP = PARAM1;
|
||||
raise_exception(EXCP0D_GPF);
|
||||
SegmentDescriptorTable *dt;
|
||||
uint8_t *ptr;
|
||||
int type, dpl, cpl;
|
||||
uint32_t e1, e2;
|
||||
|
||||
dt = &env->idt;
|
||||
if (intno * 8 + 7 > dt->limit)
|
||||
raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
|
||||
ptr = dt->base + intno * 8;
|
||||
e1 = ldl(ptr);
|
||||
e2 = ldl(ptr + 4);
|
||||
/* check gate type */
|
||||
type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
|
||||
switch(type) {
|
||||
case 5: /* task gate */
|
||||
case 6: /* 286 interrupt gate */
|
||||
case 7: /* 286 trap gate */
|
||||
case 14: /* 386 interrupt gate */
|
||||
case 15: /* 386 trap gate */
|
||||
break;
|
||||
default:
|
||||
raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
|
||||
break;
|
||||
}
|
||||
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
|
||||
cpl = env->segs[R_CS] & 3;
|
||||
/* check privledge if software int */
|
||||
if (is_int && dpl < cpl)
|
||||
raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
|
||||
/* check valid bit */
|
||||
if (!(e2 & DESC_P_MASK))
|
||||
raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
|
||||
}
|
||||
|
||||
void OPPROTO op_int3(void)
|
||||
#else
|
||||
|
||||
/*
|
||||
* is_int is TRUE if coming from the int instruction. next_eip is the
|
||||
* EIP value AFTER the interrupt instruction. It is only relevant if
|
||||
* is_int is TRUE.
|
||||
*/
|
||||
void raise_interrupt(int intno, int is_int, int error_code,
|
||||
unsigned int next_eip)
|
||||
{
|
||||
EIP = PARAM1;
|
||||
raise_exception(EXCP03_INT3);
|
||||
SegmentDescriptorTable *dt;
|
||||
uint8_t *ptr;
|
||||
int dpl, cpl;
|
||||
uint32_t e2;
|
||||
|
||||
dt = &env->idt;
|
||||
ptr = dt->base + (intno * 8);
|
||||
e2 = ldl(ptr + 4);
|
||||
|
||||
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
|
||||
cpl = 3;
|
||||
/* check privledge if software int */
|
||||
if (is_int && dpl < cpl)
|
||||
raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
|
||||
|
||||
/* Since we emulate only user space, we cannot do more than
|
||||
exiting the emulation with the suitable exception and error
|
||||
code */
|
||||
if (is_int)
|
||||
EIP = next_eip;
|
||||
env->exception_index = intno;
|
||||
env->error_code = error_code;
|
||||
|
||||
cpu_loop_exit();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* shortcuts to generate exceptions */
|
||||
void raise_exception_err(int exception_index, int error_code)
|
||||
{
|
||||
raise_interrupt(exception_index, 0, error_code, 0);
|
||||
}
|
||||
|
||||
void raise_exception(int exception_index)
|
||||
{
|
||||
raise_interrupt(exception_index, 0, 0, 0);
|
||||
}
|
||||
|
||||
void OPPROTO op_raise_interrupt(void)
|
||||
{
|
||||
int intno;
|
||||
unsigned int next_eip;
|
||||
intno = PARAM1;
|
||||
next_eip = PARAM2;
|
||||
raise_interrupt(intno, 1, 0, next_eip);
|
||||
}
|
||||
|
||||
void OPPROTO op_raise_exception(void)
|
||||
{
|
||||
int exception_index;
|
||||
exception_index = PARAM1;
|
||||
raise_exception(exception_index);
|
||||
}
|
||||
|
||||
void OPPROTO op_into(void)
|
||||
@@ -631,24 +736,23 @@ void OPPROTO op_into(void)
|
||||
int eflags;
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
if (eflags & CC_O) {
|
||||
raise_exception(EXCP04_INTO);
|
||||
raise_interrupt(EXCP04_INTO, 1, 0, PARAM1);
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
/* XXX: add IOPL/CPL tests */
|
||||
void OPPROTO op_cli(void)
|
||||
{
|
||||
raise_exception(EXCP0D_GPF);
|
||||
env->eflags &= ~IF_MASK;
|
||||
}
|
||||
|
||||
/* XXX: add IOPL/CPL tests */
|
||||
void OPPROTO op_sti(void)
|
||||
{
|
||||
raise_exception(EXCP0D_GPF);
|
||||
env->eflags |= IF_MASK;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* vm86plus instructions */
|
||||
|
||||
void OPPROTO op_cli_vm(void)
|
||||
{
|
||||
env->eflags &= ~VIF_MASK;
|
||||
@@ -663,6 +767,7 @@ void OPPROTO op_sti_vm(void)
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
#endif
|
||||
|
||||
void OPPROTO op_boundw(void)
|
||||
{
|
||||
@@ -670,8 +775,10 @@ void OPPROTO op_boundw(void)
|
||||
low = ldsw((uint8_t *)A0);
|
||||
high = ldsw((uint8_t *)A0 + 2);
|
||||
v = (int16_t)T0;
|
||||
if (v < low || v > high)
|
||||
if (v < low || v > high) {
|
||||
EIP = PARAM1;
|
||||
raise_exception(EXCP05_BOUND);
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
@@ -681,8 +788,10 @@ void OPPROTO op_boundl(void)
|
||||
low = ldl((uint8_t *)A0);
|
||||
high = ldl((uint8_t *)A0 + 4);
|
||||
v = T0;
|
||||
if (v < low || v > high)
|
||||
if (v < low || v > high) {
|
||||
EIP = PARAM1;
|
||||
raise_exception(EXCP05_BOUND);
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
@@ -705,7 +814,44 @@ void OPPROTO op_cmpxchg8b(void)
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
/* string ops */
|
||||
#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;\
|
||||
goto *((TranslationBlock *)tbparam)->tb_next[n];\
|
||||
label ## n:\
|
||||
T0 = (long)(tbparam) + (n);\
|
||||
EIP = eip;\
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
void OPPROTO op_jmp_tb_next(void)
|
||||
{
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T0_0(void)
|
||||
{
|
||||
T0 = 0;
|
||||
}
|
||||
|
||||
/* multiple size ops */
|
||||
|
||||
#define ldul ldl
|
||||
|
||||
@@ -932,7 +1078,7 @@ void helper_cpuid(void)
|
||||
EAX = 0x52b;
|
||||
EBX = 0;
|
||||
ECX = 0;
|
||||
EDX = CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE |
|
||||
EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE |
|
||||
CPUID_TSC | CPUID_MSR | CPUID_MCE |
|
||||
CPUID_CX8;
|
||||
}
|
||||
@@ -1075,8 +1221,8 @@ void OPPROTO op_das(void)
|
||||
|
||||
/* segment handling */
|
||||
|
||||
/* XXX: use static VM86 information */
|
||||
void load_seg(int seg_reg, int selector)
|
||||
/* only works if protected mode and not VM86 */
|
||||
void load_seg(int seg_reg, int selector, unsigned cur_eip)
|
||||
{
|
||||
SegmentCache *sc;
|
||||
SegmentDescriptorTable *dt;
|
||||
@@ -1084,23 +1230,57 @@ void load_seg(int seg_reg, int selector)
|
||||
uint32_t e1, e2;
|
||||
uint8_t *ptr;
|
||||
|
||||
env->segs[seg_reg] = selector;
|
||||
sc = &env->seg_cache[seg_reg];
|
||||
if (env->eflags & VM_MASK) {
|
||||
sc->base = (void *)(selector << 4);
|
||||
sc->limit = 0xffff;
|
||||
sc->seg_32bit = 0;
|
||||
if ((selector & 0xfffc) == 0) {
|
||||
/* null selector case */
|
||||
if (seg_reg == R_SS) {
|
||||
EIP = cur_eip;
|
||||
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
||||
} else {
|
||||
/* XXX: each access should trigger an exception */
|
||||
sc->base = NULL;
|
||||
sc->limit = 0;
|
||||
sc->seg_32bit = 1;
|
||||
}
|
||||
} else {
|
||||
if (selector & 0x4)
|
||||
dt = &env->ldt;
|
||||
else
|
||||
dt = &env->gdt;
|
||||
index = selector & ~7;
|
||||
if ((index + 7) > dt->limit)
|
||||
raise_exception(EXCP0D_GPF);
|
||||
if ((index + 7) > dt->limit) {
|
||||
EIP = cur_eip;
|
||||
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
||||
}
|
||||
ptr = dt->base + index;
|
||||
e1 = ldl(ptr);
|
||||
e2 = ldl(ptr + 4);
|
||||
if (!(e2 & DESC_S_MASK) ||
|
||||
(e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
|
||||
EIP = cur_eip;
|
||||
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
||||
}
|
||||
|
||||
if (seg_reg == R_SS) {
|
||||
if ((e2 & (DESC_CS_MASK | DESC_W_MASK)) == 0) {
|
||||
EIP = cur_eip;
|
||||
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
||||
}
|
||||
} else {
|
||||
if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
|
||||
EIP = cur_eip;
|
||||
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(e2 & DESC_P_MASK)) {
|
||||
EIP = cur_eip;
|
||||
if (seg_reg == R_SS)
|
||||
raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
|
||||
else
|
||||
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
|
||||
}
|
||||
|
||||
sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
|
||||
sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000);
|
||||
if (e2 & (1 << 23))
|
||||
@@ -1111,11 +1291,24 @@ void load_seg(int seg_reg, int selector)
|
||||
selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit);
|
||||
#endif
|
||||
}
|
||||
env->segs[seg_reg] = selector;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_seg_T0(void)
|
||||
{
|
||||
load_seg(PARAM1, T0 & 0xffff);
|
||||
load_seg(PARAM1, T0 & 0xffff, PARAM2);
|
||||
}
|
||||
|
||||
/* faster VM86 version */
|
||||
void OPPROTO op_movl_seg_T0_vm(void)
|
||||
{
|
||||
int selector;
|
||||
|
||||
selector = T0 & 0xffff;
|
||||
/* env->segs[] access */
|
||||
*(uint32_t *)((char *)env + PARAM1) = selector;
|
||||
/* env->seg_cache[] access */
|
||||
((SegmentCache *)((char *)env + PARAM2))->base = (void *)(selector << 4);
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T0_seg(void)
|
||||
@@ -1133,92 +1326,77 @@ void OPPROTO op_addl_A0_seg(void)
|
||||
A0 += *(unsigned long *)((char *)env + PARAM1);
|
||||
}
|
||||
|
||||
void helper_lsl(void)
|
||||
{
|
||||
unsigned int selector, limit;
|
||||
SegmentDescriptorTable *dt;
|
||||
int index;
|
||||
uint32_t e1, e2;
|
||||
uint8_t *ptr;
|
||||
|
||||
CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
|
||||
selector = T0 & 0xffff;
|
||||
if (selector & 0x4)
|
||||
dt = &env->ldt;
|
||||
else
|
||||
dt = &env->gdt;
|
||||
index = selector & ~7;
|
||||
if ((index + 7) > dt->limit)
|
||||
return;
|
||||
ptr = dt->base + index;
|
||||
e1 = ldl(ptr);
|
||||
e2 = ldl(ptr + 4);
|
||||
limit = (e1 & 0xffff) | (e2 & 0x000f0000);
|
||||
if (e2 & (1 << 23))
|
||||
limit = (limit << 12) | 0xfff;
|
||||
T1 = limit;
|
||||
CC_SRC |= CC_Z;
|
||||
}
|
||||
|
||||
void OPPROTO op_lsl(void)
|
||||
{
|
||||
helper_lsl();
|
||||
}
|
||||
|
||||
void helper_lar(void)
|
||||
{
|
||||
unsigned int selector;
|
||||
SegmentDescriptorTable *dt;
|
||||
int index;
|
||||
uint32_t e2;
|
||||
uint8_t *ptr;
|
||||
|
||||
CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
|
||||
selector = T0 & 0xffff;
|
||||
if (selector & 0x4)
|
||||
dt = &env->ldt;
|
||||
else
|
||||
dt = &env->gdt;
|
||||
index = selector & ~7;
|
||||
if ((index + 7) > dt->limit)
|
||||
return;
|
||||
ptr = dt->base + index;
|
||||
e2 = ldl(ptr + 4);
|
||||
T1 = e2 & 0x00f0ff00;
|
||||
CC_SRC |= CC_Z;
|
||||
}
|
||||
|
||||
void OPPROTO op_lar(void)
|
||||
{
|
||||
helper_lar();
|
||||
}
|
||||
|
||||
/* flags handling */
|
||||
|
||||
/* slow jumps cases (compute x86 flags) */
|
||||
void OPPROTO op_jo_cc(void)
|
||||
/* slow jumps cases : in order to avoid calling a function with a
|
||||
pointer (which can generate a stack frame on PowerPC), we use
|
||||
op_setcc to set T0 and then call op_jcc. */
|
||||
void OPPROTO op_jcc(void)
|
||||
{
|
||||
int eflags;
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
if (eflags & CC_O)
|
||||
EIP = PARAM1;
|
||||
if (T0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
else
|
||||
EIP = PARAM2;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_jb_cc(void)
|
||||
{
|
||||
if (cc_table[CC_OP].compute_c())
|
||||
EIP = PARAM1;
|
||||
else
|
||||
EIP = PARAM2;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_jz_cc(void)
|
||||
{
|
||||
int eflags;
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
if (eflags & CC_Z)
|
||||
EIP = PARAM1;
|
||||
else
|
||||
EIP = PARAM2;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_jbe_cc(void)
|
||||
{
|
||||
int eflags;
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
if (eflags & (CC_Z | CC_C))
|
||||
EIP = PARAM1;
|
||||
else
|
||||
EIP = PARAM2;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_js_cc(void)
|
||||
{
|
||||
int eflags;
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
if (eflags & CC_S)
|
||||
EIP = PARAM1;
|
||||
else
|
||||
EIP = PARAM2;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_jp_cc(void)
|
||||
{
|
||||
int eflags;
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
if (eflags & CC_P)
|
||||
EIP = PARAM1;
|
||||
else
|
||||
EIP = PARAM2;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_jl_cc(void)
|
||||
{
|
||||
int eflags;
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
if ((eflags ^ (eflags >> 4)) & 0x80)
|
||||
EIP = PARAM1;
|
||||
else
|
||||
EIP = PARAM2;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_jle_cc(void)
|
||||
{
|
||||
int eflags;
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
if (((eflags ^ (eflags >> 4)) & 0x80) || (eflags & CC_Z))
|
||||
EIP = PARAM1;
|
||||
else
|
||||
EIP = PARAM2;
|
||||
JUMP_TB(PARAM1, 1, PARAM3);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
@@ -1310,7 +1488,8 @@ void OPPROTO op_movw_eflags_T0(void)
|
||||
env->eflags = (env->eflags & ~FL_UPDATE_MASK16) | (eflags & FL_UPDATE_MASK16);
|
||||
}
|
||||
|
||||
/* vm86 version */
|
||||
#if 0
|
||||
/* vm86plus version */
|
||||
void OPPROTO op_movw_eflags_T0_vm(void)
|
||||
{
|
||||
int eflags;
|
||||
@@ -1348,6 +1527,7 @@ void OPPROTO op_movl_eflags_T0_vm(void)
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* XXX: compute only O flag */
|
||||
void OPPROTO op_movb_eflags_T0(void)
|
||||
@@ -1366,7 +1546,8 @@ void OPPROTO op_movl_T0_eflags(void)
|
||||
T0 = eflags;
|
||||
}
|
||||
|
||||
/* vm86 version */
|
||||
/* vm86plus version */
|
||||
#if 0
|
||||
void OPPROTO op_movl_T0_eflags_vm(void)
|
||||
{
|
||||
int eflags;
|
||||
@@ -1377,6 +1558,7 @@ void OPPROTO op_movl_T0_eflags_vm(void)
|
||||
eflags |= IF_MASK;
|
||||
T0 = eflags;
|
||||
}
|
||||
#endif
|
||||
|
||||
void OPPROTO op_cld(void)
|
||||
{
|
||||
@@ -1483,13 +1665,13 @@ CCTable cc_table[CC_OP_NB] = {
|
||||
[CC_OP_DECW] = { compute_all_decw, compute_c_incl },
|
||||
[CC_OP_DECL] = { compute_all_decl, compute_c_incl },
|
||||
|
||||
[CC_OP_SHLB] = { compute_all_shlb, compute_c_shll },
|
||||
[CC_OP_SHLW] = { compute_all_shlw, compute_c_shll },
|
||||
[CC_OP_SHLB] = { compute_all_shlb, compute_c_shlb },
|
||||
[CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw },
|
||||
[CC_OP_SHLL] = { compute_all_shll, compute_c_shll },
|
||||
|
||||
[CC_OP_SARB] = { compute_all_sarb, compute_c_shll },
|
||||
[CC_OP_SARW] = { compute_all_sarw, compute_c_shll },
|
||||
[CC_OP_SARL] = { compute_all_sarl, compute_c_shll },
|
||||
[CC_OP_SARB] = { compute_all_sarb, compute_c_sarl },
|
||||
[CC_OP_SARW] = { compute_all_sarw, compute_c_sarl },
|
||||
[CC_OP_SARL] = { compute_all_sarl, compute_c_sarl },
|
||||
};
|
||||
|
||||
/* floating point support. Some of the code for complicated x87
|
||||
@@ -1605,12 +1787,22 @@ typedef union {
|
||||
|
||||
void OPPROTO op_flds_FT0_A0(void)
|
||||
{
|
||||
#ifdef USE_FP_CONVERT
|
||||
FP_CONVERT.i32 = ldl((void *)A0);
|
||||
FT0 = FP_CONVERT.f;
|
||||
#else
|
||||
FT0 = ldfl((void *)A0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OPPROTO op_fldl_FT0_A0(void)
|
||||
{
|
||||
#ifdef USE_FP_CONVERT
|
||||
FP_CONVERT.i64 = ldq((void *)A0);
|
||||
FT0 = FP_CONVERT.d;
|
||||
#else
|
||||
FT0 = ldfq((void *)A0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* helpers are needed to avoid static constant reference. XXX: find a better way */
|
||||
@@ -1650,17 +1842,32 @@ void OPPROTO op_fildll_FT0_A0(void)
|
||||
|
||||
void OPPROTO op_fild_FT0_A0(void)
|
||||
{
|
||||
#ifdef USE_FP_CONVERT
|
||||
FP_CONVERT.i32 = ldsw((void *)A0);
|
||||
FT0 = (CPU86_LDouble)FP_CONVERT.i32;
|
||||
#else
|
||||
FT0 = (CPU86_LDouble)ldsw((void *)A0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OPPROTO op_fildl_FT0_A0(void)
|
||||
{
|
||||
#ifdef USE_FP_CONVERT
|
||||
FP_CONVERT.i32 = (int32_t) ldl((void *)A0);
|
||||
FT0 = (CPU86_LDouble)FP_CONVERT.i32;
|
||||
#else
|
||||
FT0 = (CPU86_LDouble)((int32_t)ldl((void *)A0));
|
||||
#endif
|
||||
}
|
||||
|
||||
void OPPROTO op_fildll_FT0_A0(void)
|
||||
{
|
||||
#ifdef USE_FP_CONVERT
|
||||
FP_CONVERT.i64 = (int64_t) ldq((void *)A0);
|
||||
FT0 = (CPU86_LDouble)FP_CONVERT.i64;
|
||||
#else
|
||||
FT0 = (CPU86_LDouble)((int64_t)ldq((void *)A0));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1668,12 +1875,22 @@ void OPPROTO op_fildll_FT0_A0(void)
|
||||
|
||||
void OPPROTO op_flds_ST0_A0(void)
|
||||
{
|
||||
#ifdef USE_FP_CONVERT
|
||||
FP_CONVERT.i32 = ldl((void *)A0);
|
||||
ST0 = FP_CONVERT.f;
|
||||
#else
|
||||
ST0 = ldfl((void *)A0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OPPROTO op_fldl_ST0_A0(void)
|
||||
{
|
||||
#ifdef USE_FP_CONVERT
|
||||
FP_CONVERT.i64 = ldq((void *)A0);
|
||||
ST0 = FP_CONVERT.d;
|
||||
#else
|
||||
ST0 = ldfq((void *)A0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_X86LDOUBLE
|
||||
@@ -1738,17 +1955,32 @@ void OPPROTO op_fildll_ST0_A0(void)
|
||||
|
||||
void OPPROTO op_fild_ST0_A0(void)
|
||||
{
|
||||
#ifdef USE_FP_CONVERT
|
||||
FP_CONVERT.i32 = ldsw((void *)A0);
|
||||
ST0 = (CPU86_LDouble)FP_CONVERT.i32;
|
||||
#else
|
||||
ST0 = (CPU86_LDouble)ldsw((void *)A0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OPPROTO op_fildl_ST0_A0(void)
|
||||
{
|
||||
#ifdef USE_FP_CONVERT
|
||||
FP_CONVERT.i32 = (int32_t) ldl((void *)A0);
|
||||
ST0 = (CPU86_LDouble)FP_CONVERT.i32;
|
||||
#else
|
||||
ST0 = (CPU86_LDouble)((int32_t)ldl((void *)A0));
|
||||
#endif
|
||||
}
|
||||
|
||||
void OPPROTO op_fildll_ST0_A0(void)
|
||||
{
|
||||
#ifdef USE_FP_CONVERT
|
||||
FP_CONVERT.i64 = (int64_t) ldq((void *)A0);
|
||||
ST0 = (CPU86_LDouble)FP_CONVERT.i64;
|
||||
#else
|
||||
ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0));
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1757,7 +1989,12 @@ void OPPROTO op_fildll_ST0_A0(void)
|
||||
|
||||
void OPPROTO op_fsts_ST0_A0(void)
|
||||
{
|
||||
#ifdef USE_FP_CONVERT
|
||||
FP_CONVERT.d = ST0;
|
||||
stfl((void *)A0, FP_CONVERT.f);
|
||||
#else
|
||||
stfl((void *)A0, (float)ST0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OPPROTO op_fstl_ST0_A0(void)
|
||||
@@ -1792,22 +2029,43 @@ void OPPROTO op_fstt_ST0_A0(void)
|
||||
|
||||
void OPPROTO op_fist_ST0_A0(void)
|
||||
{
|
||||
#if defined(__sparc__) && !defined(__sparc_v9__)
|
||||
register CPU86_LDouble d asm("o0");
|
||||
#else
|
||||
CPU86_LDouble d;
|
||||
#endif
|
||||
int val;
|
||||
val = lrint(ST0);
|
||||
|
||||
d = ST0;
|
||||
val = lrint(d);
|
||||
stw((void *)A0, val);
|
||||
}
|
||||
|
||||
void OPPROTO op_fistl_ST0_A0(void)
|
||||
{
|
||||
#if defined(__sparc__) && !defined(__sparc_v9__)
|
||||
register CPU86_LDouble d asm("o0");
|
||||
#else
|
||||
CPU86_LDouble d;
|
||||
#endif
|
||||
int val;
|
||||
val = lrint(ST0);
|
||||
|
||||
d = ST0;
|
||||
val = lrint(d);
|
||||
stl((void *)A0, val);
|
||||
}
|
||||
|
||||
void OPPROTO op_fistll_ST0_A0(void)
|
||||
{
|
||||
#if defined(__sparc__) && !defined(__sparc_v9__)
|
||||
register CPU86_LDouble d asm("o0");
|
||||
#else
|
||||
CPU86_LDouble d;
|
||||
#endif
|
||||
int64_t val;
|
||||
val = llrint(ST0);
|
||||
|
||||
d = ST0;
|
||||
val = llrint(d);
|
||||
stq((void *)A0, val);
|
||||
}
|
||||
|
||||
|
@@ -193,7 +193,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 +205,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 +216,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 +228,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
opc-i386.h
644
opc-i386.h
@@ -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)
|
@@ -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;
|
||||
}
|
||||
@@ -233,18 +238,18 @@ void OPPROTO glue(op_jb_sub, SUFFIX)(void)
|
||||
src2 = CC_SRC - CC_DST;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -255,18 +260,18 @@ void OPPROTO glue(op_jbe_sub, SUFFIX)(void)
|
||||
src2 = CC_SRC - CC_DST;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -277,9 +282,9 @@ void OPPROTO glue(op_jl_sub, SUFFIX)(void)
|
||||
src2 = CC_SRC - CC_DST;
|
||||
|
||||
if ((DATA_STYPE)src1 < (DATA_STYPE)src2)
|
||||
EIP = PARAM1;
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
else
|
||||
EIP = PARAM2;
|
||||
JUMP_TB(PARAM1, 1, PARAM3);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
@@ -290,9 +295,9 @@ void OPPROTO glue(op_jle_sub, SUFFIX)(void)
|
||||
src2 = CC_SRC - CC_DST;
|
||||
|
||||
if ((DATA_STYPE)src1 <= (DATA_STYPE)src2)
|
||||
EIP = PARAM1;
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
else
|
||||
EIP = PARAM2;
|
||||
JUMP_TB(PARAM1, 1, PARAM3);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
@@ -843,12 +848,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
|
||||
|
142
qemu-doc.texi
142
qemu-doc.texi
@@ -10,11 +10,11 @@
|
||||
@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.
|
||||
processes on non-x86 Linux architectures such as PowerPC. 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}) or
|
||||
@code{DOSEMU} (@url{http://www.dosemu.org}) on non-x86 CPUs.
|
||||
|
||||
QEMU features:
|
||||
|
||||
@@ -22,21 +22,26 @@ QEMU features:
|
||||
|
||||
@item User space only x86 emulator.
|
||||
|
||||
@item Currently ported on i386, PowerPC and S390.
|
||||
@item Currently ported on i386, PowerPC. Work in progress for S390, Alpha and Sparc.
|
||||
|
||||
@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).
|
||||
User space LDT and GDT are emulated. VM86 mode is also supported.
|
||||
|
||||
@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 virtual x86 signals.
|
||||
|
||||
@item QEMU can emulate itself on x86 (experimental).
|
||||
@item Precise user space x86 exceptions.
|
||||
|
||||
@item Self-modifying code support.
|
||||
|
||||
@item Support of host page sizes bigger than 4KB.
|
||||
|
||||
@item QEMU can emulate itself on x86.
|
||||
|
||||
@item The virtual x86 CPU is a library (@code{libqemu}) which can be used
|
||||
in other projects.
|
||||
@@ -46,19 +51,15 @@ 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 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).
|
||||
@@ -119,7 +120,7 @@ qemu /usr/local/qemu-i386/bin/qemu-i386 /usr/local/qemu-i386/bin/ls-i386
|
||||
|
||||
@end itemize
|
||||
|
||||
@section Wine launch (Currently only tested when emulating x86 on x86)
|
||||
@section Wine launch
|
||||
|
||||
@itemize
|
||||
|
||||
@@ -152,17 +153,24 @@ 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 Internals
|
||||
|
||||
@section QEMU compared to other emulators
|
||||
@@ -265,17 +273,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.
|
||||
|
||||
Althought 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
|
||||
|
||||
@@ -284,6 +334,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
|
||||
@@ -312,6 +367,10 @@ 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. Althought
|
||||
@@ -319,13 +378,9 @@ 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 ELF shared object
|
||||
as the ld-linux.so ELF interpreter. That way, it can be relocated at
|
||||
load time.
|
||||
|
||||
Since self-modifying code is not supported yet, QEMU cannot self
|
||||
virtualize itself in case of translation cache flush. This limitation
|
||||
will be suppressed soon.
|
||||
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 Bibliography
|
||||
|
||||
@@ -379,19 +434,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}
|
||||
|
||||
@@ -399,9 +445,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}).
|
||||
|
204
s390.ld
Normal file
204
s390.ld
Normal file
@@ -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) }
|
||||
}
|
||||
|
@@ -330,7 +330,7 @@ struct target_stat64 {
|
||||
target_ulong __pad7; /* will be high 32 bits of ctime someday */
|
||||
|
||||
unsigned long long st_ino;
|
||||
};
|
||||
} __attribute__((packed));
|
||||
|
||||
#define TARGET_SA_NOCLDSTOP 0x00000001
|
||||
#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */
|
||||
@@ -444,6 +444,18 @@ typedef struct target_siginfo {
|
||||
} _sifields;
|
||||
} target_siginfo_t;
|
||||
|
||||
/*
|
||||
* si_code values
|
||||
* Digital reserves positive values for kernel-generated signals.
|
||||
*/
|
||||
#define TARGET_SI_USER 0 /* sent by kill, sigsend, raise */
|
||||
#define TARGET_SI_KERNEL 0x80 /* sent by the kernel from somewhere */
|
||||
#define TARGET_SI_QUEUE -1 /* sent by sigqueue */
|
||||
#define TARGET_SI_TIMER -2 /* sent by timer expiration */
|
||||
#define TARGET_SI_MESGQ -3 /* sent by real time mesq state change */
|
||||
#define TARGET_SI_ASYNCIO -4 /* sent by AIO completion */
|
||||
#define TARGET_SI_SIGIO -5 /* sent by queued SIGIO */
|
||||
|
||||
/*
|
||||
* SIGILL si_codes
|
||||
*/
|
||||
@@ -462,6 +474,18 @@ typedef struct target_siginfo {
|
||||
#define TARGET_FPE_FLTSUB (8) /* subscript out of range */
|
||||
#define TARGET_NSIGFPE 8
|
||||
|
||||
/*
|
||||
* SIGSEGV si_codes
|
||||
*/
|
||||
#define TARGET_SEGV_MAPERR (1) /* address not mapped to object */
|
||||
#define TARGET_SEGV_ACCERR (2) /* invalid permissions for mapped object */
|
||||
|
||||
/*
|
||||
* SIGTRAP si_codes
|
||||
*/
|
||||
#define TARGET_TRAP_BRKPT (1) /* process breakpoint */
|
||||
#define TARGET_TRAP_TRACE (2) /* process trace trap */
|
||||
|
||||
/* default linux values for the selectors */
|
||||
#define __USER_CS (0x23)
|
||||
#define __USER_DS (0x2B)
|
||||
@@ -760,6 +784,13 @@ struct target_modify_ldt_ldt_s {
|
||||
|
||||
#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) */
|
||||
@@ -936,6 +967,40 @@ union target_semun {
|
||||
unsigned int __pad; /* really void* */
|
||||
};
|
||||
|
||||
#define TARGET_F_DUPFD 0 /* dup */
|
||||
#define TARGET_F_GETFD 1 /* get close_on_exec */
|
||||
#define TARGET_F_SETFD 2 /* set/clear close_on_exec */
|
||||
#define TARGET_F_GETFL 3 /* get file->f_flags */
|
||||
#define TARGET_F_SETFL 4 /* set file->f_flags */
|
||||
#define TARGET_F_GETLK 5
|
||||
#define TARGET_F_SETLK 6
|
||||
#define TARGET_F_SETLKW 7
|
||||
|
||||
#define TARGET_F_SETOWN 8 /* for sockets. */
|
||||
#define TARGET_F_GETOWN 9 /* for sockets. */
|
||||
#define TARGET_F_SETSIG 10 /* for sockets. */
|
||||
#define TARGET_F_GETSIG 11 /* for sockets. */
|
||||
|
||||
#define TARGET_F_GETLK64 12 /* using 'struct flock64' */
|
||||
#define TARGET_F_SETLK64 13
|
||||
#define TARGET_F_SETLKW64 14
|
||||
|
||||
struct target_flock {
|
||||
short l_type;
|
||||
short l_whence;
|
||||
target_ulong l_start;
|
||||
target_ulong l_len;
|
||||
int l_pid;
|
||||
};
|
||||
|
||||
struct target_flock64 {
|
||||
short l_type;
|
||||
short l_whence;
|
||||
unsigned long long l_start;
|
||||
unsigned long long l_len;
|
||||
int l_pid;
|
||||
};
|
||||
|
||||
/* soundcard defines (XXX: move them to generic file syscall_defs.h) */
|
||||
|
||||
#define TARGET_SNDCTL_COPR_HALT 0xc0144307
|
||||
|
@@ -3,16 +3,10 @@
|
||||
hello
|
||||
sha1.test.c
|
||||
sha1.c
|
||||
op.c
|
||||
test-i386
|
||||
sha1
|
||||
testclone
|
||||
interp.h
|
||||
interploop.c
|
||||
.gdb_history
|
||||
cachegrind.out
|
||||
interp.c
|
||||
interp
|
||||
testthread
|
||||
test-i386.s
|
||||
test-i386.ref
|
||||
|
@@ -30,9 +30,10 @@ test_path: test_path.c
|
||||
./$@ || { 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)
|
||||
|
@@ -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);
|
||||
|
@@ -125,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);
|
||||
|
104
tests/test-i386-vm86.S
Normal file
104
tests/test-i386-vm86.S
Normal file
@@ -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:
|
||||
|
@@ -1,7 +1,13 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <stdio.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
|
||||
|
||||
@@ -707,6 +713,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 +803,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 */
|
||||
@@ -890,6 +919,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 +1284,8 @@ int main(int argc, char **argv)
|
||||
test_lea();
|
||||
test_segs();
|
||||
test_code16();
|
||||
test_vm86();
|
||||
test_exceptions();
|
||||
test_self_modifying_code();
|
||||
return 0;
|
||||
}
|
||||
|
136
tests/testsig.c
136
tests/testsig.c
@@ -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;
|
||||
}
|
||||
|
2
thunk.h
2
thunk.h
@@ -70,7 +70,7 @@
|
||||
#define TARGET_LONG_BITS 32
|
||||
|
||||
|
||||
#if defined(__alpha__)
|
||||
#if defined(__alpha__) || defined (__ia64__)
|
||||
#define HOST_LONG_BITS 64
|
||||
#else
|
||||
#define HOST_LONG_BITS 32
|
||||
|
776
translate-i386.c
776
translate-i386.c
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user