Compare commits

..
2 Commits
Author SHA1 Message Date
(no author) 291fc25cec This commit was manufactured by cvs2svn to create tag 'initial'.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/tags/initial@4 c046a42c-6fe2-441c-8c8c-71466251a162
2003-02-18 22:55:37 +00:00
bellard 136d8f1646 first import
git-svn-id: svn://svn.savannah.nongnu.org/qemu/branches/perso@2 c046a42c-6fe2-441c-8c8c-71466251a162
2003-02-18 22:55:36 +00:00
342 changed files with 2045 additions and 183638 deletions

No files matched your search

-23
View File
@@ -1,23 +0,0 @@
arm-user
armeb-user
config-host.*
dyngen
i386
i386-softmmu
i386-user
ppc-softmmu
ppc64-softmmu
ppc-user
qemu-doc.html
qemu-tech.html
qemu.1
qemu.pod
qemu-img.1
qemu-img.pod
sparc-user
qemu-img
sparc-softmmu
x86_64-softmmu
sparc64-user
sparc64-softmmu
mips-softmmu
-339
View File
@@ -1,339 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
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.
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 software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. 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 components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program 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
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
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.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
+111 -111
View File
@@ -1,14 +1,36 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
------------------------------------------------------------------------------
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/ )
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
Preamble
@@ -17,109 +39,97 @@ freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
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.
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.
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.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
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.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
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
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
Our method of protecting your rights has two steps: (1) copyright
the library, and (2) offer you this license which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
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.
GNU LESSER GENERAL PUBLIC LICENSE
GNU LIBRARY GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
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".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
@@ -268,7 +278,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 combine or
6. As an exception to the Sections above, you may also compile 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
@@ -295,31 +305,23 @@ of these things:
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
b) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
c) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
d) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
the source code 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.
@@ -368,7 +370,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 with
You are not responsible for enforcing compliance by third parties to
this License.
11. If, as a consequence of a court judgment or allegation of patent
@@ -411,7 +413,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 Lesser General Public License from time to time.
versions of the Library 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.
@@ -457,7 +459,7 @@ DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
Appendix: 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
@@ -474,18 +476,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 Lesser General Public
modify it under the terms of the GNU Library 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.
Library 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
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.
Also add information on how to contact you by electronic and paper mail.
@@ -500,5 +502,3 @@ necessary. Here is a sample; alter the names:
Ty Coon, President of Vice
That's all there is to it!
-332
View File
@@ -1,332 +0,0 @@
version 0.7.1:
- read-only Virtual FAT support (Johannes Schindelin)
- Windows 2000 install disk full hack (original idea from Vladimir
N. Oleynik)
- VMDK disk image creation (Filip Navara)
- SPARC64 progress (Blue Swirl)
- initial MIPS support (Jocelyn mayer)
- MIPS improvements (Ralf Baechle)
- 64 bit fixes in user networking (initial patch by Gwenole Beauchesne)
version 0.7.0:
- better BIOS translation and HDD geometry auto-detection
- user mode networking bug fix
- undocumented FPU ops support
- Cirrus VGA: support for 1280x1024x[8,15,16] modes
- 'pidfile' option
- .dmg disk image format support (Johannes Schindelin)
- keymaps support (initial patch by Johannes Schindelin)
- big endian ARM support (Lennert Buytenhek)
- added generic 64 bit target support
- x86_64 target support
- initial APIC support
- MMX/SSE/SSE2/PNI support
- PC parallel port support (Mark Jonckheere)
- initial SPARC64 support (Blue Swirl)
- SPARC target boots Linux (Blue Swirl)
- armv5te user mode support (Paul Brook)
- ARM VFP support (Paul Brook)
- ARM "Angel" semihosting syscalls (Paul Brook)
- user mode gdb stub support (Paul Brook)
- Samba 3 support
- initial Cocoa support (Pierre d'Herbemont)
- generic FPU emulation code
- Virtual PC read-only disk image support (Alex Beregszaszi)
version 0.6.1:
- Mac OS X port (Pierre d'Herbemont)
- Virtual console support
- Better monitor line edition
- New block device layer
- New 'qcow' growable disk image support with AES encryption and
transparent decompression
- VMware 3 and 4 read-only disk image support (untested)
- Support for up to 4 serial ports
- TFTP server support (Magnus Damm)
- Port redirection support in user mode networking
- Support for not executable data sections
- Compressed loop disk image support (Johannes Schindelin)
- Level triggered IRQ fix (aka NE2000 PCI performance fix) (Steve
Wormley)
- Fixed Fedora Core 2 problems (now you can run qemu without any
LD_ASSUME_KERNEL tricks on FC2)
- DHCP fix for Windows (accept DHCPREQUEST alone)
- SPARC system emulation (Blue Swirl)
- Automatic Samba configuration for host file access from Windows.
- '-loadvm' and '-full-screen' options
- ne2000 savevm support (Johannes Schindelin)
- Ctrl-Alt is now the default grab key. Ctrl-Alt-[0-9] switches to
the virtual consoles.
- BIOS floppy fix for NT4 (Mike Nordell, Derek Fawcus, Volker Ruppert)
- Floppy fixes for NT4 and NT5 (Mike Nordell)
- NT4 IDE fixes (Ben Pfaf, Mike Nordell)
- SDL Audio support and SB16 fixes (malc)
- ENTER instruction bug fix (initial patch by Stefan Kisdaroczi)
- VGA font change fix
- VGA read-only CRTC register fix
version 0.6.0:
- minimalist FPU exception support (NetBSD FPU probe fix)
- cr0.ET fix (Win95 boot)
- *BSD port (Markus Niemisto)
- I/O access fix (signaled by Mark Jonckheere)
- IDE drives serial number fix (Mike Nordell)
- int13 CDROM BIOS fix (aka Solaris x86 install CD fix)
- int15, ah=86 BIOS fix (aka Solaris x86 hardware probe hang up fix)
- BSR/BSF "undefined behaviour" fix
- vmdk2raw: convert VMware disk images to raw images
- PCI support
- NE2K PCI support
- dummy VGA PCI support
- VGA font selection fix (Daniel Serpell)
- PIC reset fix (Hidemi KAWAI)
- PIC spurious irq support (aka Solaris install bug)
- added '-localtime' option
- Cirrus CL-GD54xx VGA support (initial patch by Makoto Suzuki (suzu))
- APM and system shutdown support
- Fixed system reset
- Support for other PC BIOSes
- Initial PowerMac hardware emulation
- PowerMac/PREP OpenFirmware compatible BIOS (Jocelyn Mayer)
- initial IDE BMDMA support (needed for Darwin x86)
- Set the default memory size for PC emulation to 128 MB
version 0.5.5:
- SDL full screen support (initial patch by malc)
- VGA support on PowerPC PREP
- VBE fixes (Matthew Mastracci)
- PIT fixes (aka Win98 hardware probe and "VGA slowness" bug)
- IDE master only fixes (aka Win98 CD-ROM probe bug)
- ARM load/store half word fix (Ulrich Hecht)
- FDC fixes for Win98
version 0.5.4:
- qemu-fast fixes
- BIOS area protection fix (aka EMM386.EXE fix) (Mike Nordell)
- keyboard/mouse fix (Mike Nordell)
- IDE fixes (Linux did not recognized slave drivers)
- VM86 EIP masking fix (aka NT5 install fix) (Mike Nordell)
- QEMU can now boot a PowerPC Linux kernel (Jocelyn Mayer)
- User mode network stack
- imul imm8 fix + 0x82 opcode support (Hidemi KAWAI)
- precise self modifying code (aka BeOS install bug)
version 0.5.3:
- added Bochs VESA VBE support
- VGA memory map mode 3 access fix (OS/2 install fix)
- IDE fixes (Jens Axboe)
- CPU interrupt fixes
- fixed various TLB invalidation cases (NT install)
- fixed cr0.WP semantics (XP install)
- direct chaining support for SPARC and PowerPC (faster)
- ARM NWFPE support (initial patch by Ulrich Hecht)
- added specific x86 to x86 translator (close to native performance
in qemu-i386 and qemu-fast)
- shm syscalls support (Paul McKerras)
- added accurate CR0.MP/ME/TS emulation
- fixed DMA memory write access (Win95 boot floppy fix)
- graphical x86 linux loader
- command line monitor
- generic removable device support
- support of CD-ROM change
- multiple network interface support
- initial x86-64 host support (Gwenole Beauchesne)
- lret to outer priviledge fix (OS/2 install fix)
- task switch fixes (SkyOS boot)
- VM save/restore commands
- new timer API
- more precise RTC emulation (periodic timers + time updates)
- Win32 port (initial patch by Kazu)
version 0.5.2:
- improved soft MMU speed (assembly functions and specializing)
- improved multitasking speed by avoiding flushing TBs when
switching tasks
- improved qemu-fast speed
- improved self modifying code handling (big performance gain in
softmmu mode).
- fixed IO checking
- fixed CD-ROM detection (win98 install CD)
- fixed addseg real mode bug (GRUB boot fix)
- added ROM memory support (win98 boot)
- fixed 'call Ev' in case of paging exception
- updated the script 'qemu-binfmt-conf.sh' to use QEMU automagically
when launching executables for the supported target CPUs.
- PowerPC system emulation update (Jocelyn Mayer)
- PC floppy emulation and DMA fixes (Jocelyn Mayer)
- polled mode for PIC (Jocelyn Mayer)
- fixed PTE dirty bit handling
- fixed xadd same reg bug
- fixed cmpxchg exception safeness
- access to virtual memory in gdb stub
- task gate and NT flag fixes
- eflags optimisation fix for string operations
version 0.5.1:
- float access fixes when using soft mmu
- PC emulation support on PowerPC
- A20 support
- IDE CD-ROM emulation
- ARM fixes (Ulrich Hecht)
- SB16 emulation (malc)
- IRET and INT fixes in VM86 mode with IOPL=3
- Port I/Os use TSS io map
- Full task switching/task gate support
- added verr, verw, arpl, fcmovxx
- PowerPC target support (Jocelyn Mayer)
- Major SPARC target fixes (dynamically linked programs begin to work)
version 0.5.0:
- full hardware level VGA emulation
- graphical display with SDL
- added PS/2 mouse and keyboard emulation
- popw (%esp) fix
- mov to/from segment data width fix
- added real mode support
- added Bochs BIOS and LGPL'ed VGA BIOS loader in qemu
- m68k host port (Richard Zidlicky)
- partial soft MMU support for memory mapped I/Os
- multi-target build
- fixed: no error code in hardware interrupts
- fixed: pop ss, mov ss, x and sti disable hardware irqs for the next insn
- correct single stepping thru string operations
- preliminary SPARC target support (Thomas M. Ogrisegg)
- tun-fd option (Rusty Russell)
- automatic IDE geometry detection
- renamed 'vl' to qemu[-fast] and user qemu to qemu-{cpu}.
- added man page
- added full soft mmu mode to launch unpatched OSes.
version 0.4.3:
- x86 exception fix in case of nop instruction.
- gcc 3.2.2 bug workaround (RedHat 9 fix)
- sparc and Alpha host fixes
- many ARM target fixes: 'ls' and 'bash' can be launched.
version 0.4.2:
- many exception handling fixes (can compile a Linux kernel inside vl)
- IDE emulation support
- initial GDB stub support
- deferred update support for disk images (Rusty Russell)
- accept User Mode Linux Copy On Write disk images
- SMP kernels can at least be booted
version 0.4.1:
- more accurate timer support in vl.
- more reliable NE2000 probe in vl.
- added 2.5.66 kernel in vl-test.
- added VLTMPDIR environment variable in vl.
version 0.4:
- initial support for ring 0 x86 processor emulation
- fixed signal handling for correct dosemu DPMI emulation
- fast x86 MMU emulation with mmap()
- fixed popl (%esp) case
- Linux kernel can be executed by QEMU with the 'vl' command.
version 0.3:
- initial support for ARM emulation
- added fnsave, frstor, fnstenv, fldenv FPU instructions
- added FPU register save in signal emulation
- initial ARM port
- Sparc and Alpha ports work on the regression test
- generic ioctl number conversion
- fixed ioctl type conversion
version 0.2:
- PowerPC disassembly and ELF symbols output (Rusty Russell)
- flock support (Rusty Russell)
- ugetrlimit support (Rusty Russell)
- fstat64 fix (Rusty Russell)
- initial Alpha port (Falk Hueffner)
- initial IA64 port (Matt Wilson)
- initial Sparc and Sparc64 port (David S. Miller)
- added HLT instruction
- LRET instruction fix.
- added GPF generation for I/Os.
- added INT3 and TF flag support.
- SHL instruction C flag fix.
- mmap emulation for host page size > 4KB
- self-modifying code support
- better VM86 support (dosemu works on non trivial programs)
- precise exception support (EIP is computed correctly in most cases)
- more precise LDT/GDT/IDT emulation
- faster segment load in vm86 mode
- direct chaining of basic blocks (faster emulation)
version 0.1.6:
- automatic library search system. QEMU can now work with unpatched
ELF dynamic loader and libc (Rusty Russell).
- ISO C warning fixes (Alistair Strachan)
- first self-virtualizable version (works only as long as the
translation cache is not flushed)
- RH9 fixes
version 0.1.5:
- ppc64 support + personality() patch (Rusty Russell)
- first Alpha CPU patches (Falk Hueffner)
- removed bfd.h dependancy
- fixed shrd, shld, idivl and divl on PowerPC.
- fixed buggy glibc PowerPC rint() function (test-i386 passes now on PowerPC).
version 0.1.4:
- more accurate VM86 emulation (can launch small DOS 16 bit
executables in wine).
- fixed push/pop fs/gs
- added iret instruction.
- added times() syscall and SIOCATMARK ioctl.
version 0.1.3:
- S390 support (Ulrich Weigand)
- glibc 2.3.x compile fix (Ulrich Weigand)
- socketcall endian fix (Ulrich Weigand)
- struct sockaddr endian fix (Ulrich Weigand)
- sendmsg/recvmsg endian fix (Ulrich Weigand)
- execve endian fix (Ulrich Weigand)
- fdset endian fix (Ulrich Weigand)
- partial setsockopt syscall support (Ulrich Weigand)
- more accurate pushf/popf emulation
- first partial vm86() syscall support (can be used with runcom example).
- added bound, cmpxchg8b, cpuid instructions
- added 16 bit addressing support/override for string operations
- poll() fix
version 0.1.2:
- compile fixes
- xlat instruction
- xchg instruction memory lock
- added simple vm86 example (not working with QEMU yet). The 54 byte
DOS executable 'pi_10.com' program was released by Bertram
Felgenhauer (more information at http://www.boo.net/~jasonp/pipage.html).
version 0.1.1:
- glibc 2.2 compilation fixes
- added -s and -L options
- binary distribution of x86 glibc and wine
- big endian fixes in ELF loader and getdents.
version 0.1:
- initial public release.
-12
View File
@@ -1,12 +0,0 @@
The following points clarify the QEMU licenses:
1) The QEMU virtual CPU core library (libqemu.a) and the QEMU PC
system emulator are released under the GNU Lesser General Public
License.
2) The Linux user mode QEMU emulator is released under the GNU General
Public License.
3) QEMU is a trademark of Fabrice Bellard.
Fabrice Bellard.
+24 -121
View File
@@ -1,133 +1,36 @@
-include config-host.mak
CFLAGS=-Wall -O2 -g -fno-strict-aliasing
ifdef CONFIG_DARWIN
CFLAGS+= -mdynamic-no-pic
endif
CFLAGS=-Wall -O2 -g
LDFLAGS=-g
LIBS=
DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
TOOLS=qemu-img$(EXESUF)
ifdef CONFIG_STATIC
LDFLAGS+=-static
endif
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1
DEFINES=-D_GNU_SOURCE -DGEMU -DDOSEMU #-DNO_TRACE_MSGS
all: dyngen$(EXESUF) $(TOOLS) $(DOCS)
for d in $(TARGET_DIRS); do \
$(MAKE) -C $$d $@ || exit 1 ; \
done
ifdef CONFIG_KQEMU
ifdef CONFIG_WIN32
$(MAKE) -C kqemu -f Makefile.winnt
else
$(MAKE) -C kqemu
endif
endif
OBJS= i386/fp87.o i386/interp_main.o i386/interp_modrm.o i386/interp_16_32.o \
i386/interp_32_16.o i386/interp_32_32.o i386/emu-utils.o \
i386/dis8086.o i386/emu-ldt.o
OBJS+= elfload.o main.o thunk.o syscall.o
qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c
$(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
SRCS = $(OBJS:.o=.c)
dyngen$(EXESUF): dyngen.c
$(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^
all: gemu
gemu: $(OBJS)
$(CC) -Wl,-T,i386.ld $(LDFLAGS) -o $@ $(OBJS)
depend: $(SRCS)
$(CC) -MM $(CFLAGS) $^ 1>.depend
%.o: %.c
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
clean:
# avoid old build problems by removing potentially incorrect old files
rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
rm -f *.o *.a $(TOOLS) dyngen$(EXESUF) TAGS *.pod *~ */*~
$(MAKE) -C tests clean
for d in $(TARGET_DIRS); do \
$(MAKE) -C $$d $@ || exit 1 ; \
done
ifdef CONFIG_KQEMU
$(MAKE) -C kqemu clean
endif
rm -f *.o *~ i386/*.o i386/*~ gemu hello test1 test2 TAGS
distclean: clean
rm -f config-host.mak config-host.h
for d in $(TARGET_DIRS); do \
rm -rf $$d || exit 1 ; \
done
hello: hello.c
$(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
KEYMAPS=da en-gb et fr fr-ch is lt modifiers no pt-br sv \
ar de en-us fi fr-be hr it lv nl pl ru th \
common de-ch es fo fr-ca hu ja mk nl-be pt sl tr
test1: test1.c
$(CC) $(CFLAGS) -static $(LDFLAGS) -o $@ $<
install: all
mkdir -p "$(bindir)"
install -m 755 -s $(TOOLS) "$(bindir)"
mkdir -p "$(datadir)"
install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \
pc-bios/vgabios-cirrus.bin \
pc-bios/ppc_rom.bin pc-bios/video.x \
pc-bios/proll.elf \
pc-bios/linux_boot.bin "$(datadir)"
mkdir -p "$(docdir)"
install -m 644 qemu-doc.html qemu-tech.html "$(docdir)"
ifndef CONFIG_WIN32
mkdir -p "$(mandir)/man1"
install qemu.1 qemu-img.1 "$(mandir)/man1"
mkdir -p "$(datadir)/keymaps"
install -m 644 $(addprefix keymaps/,$(KEYMAPS)) "$(datadir)/keymaps"
endif
for d in $(TARGET_DIRS); do \
$(MAKE) -C $$d $@ || exit 1 ; \
done
ifdef CONFIG_KQEMU
cd kqemu ; ./install.sh
endif
# various test targets
test speed test2: all
$(MAKE) -C tests $@
TAGS:
etags *.[ch] tests/*.[ch]
# documentation
%.html: %.texi
texi2html -monolithic -number $<
qemu.1: qemu-doc.texi
./texi2pod.pl $< qemu.pod
pod2man --section=1 --center=" " --release=" " qemu.pod > $@
qemu-img.1: qemu-img.texi
./texi2pod.pl $< qemu-img.pod
pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@
FILE=qemu-$(shell cat VERSION)
# tar release (use 'make -k tar' on a checkouted tree)
tar:
rm -rf /tmp/$(FILE)
cp -r . /tmp/$(FILE)
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS )
rm -rf /tmp/$(FILE)
# generate a binary distribution
tarbin:
( cd / ; tar zcvf ~/qemu-$(VERSION)-i386.tar.gz \
$(bindir)/qemu \
$(bindir)/qemu-system-ppc \
$(bindir)/qemu-system-sparc \
$(bindir)/qemu-system-x86_64 \
$(bindir)/qemu-system-mips \
$(bindir)/qemu-i386 \
$(bindir)/qemu-arm \
$(bindir)/qemu-sparc \
$(bindir)/qemu-ppc \
$(bindir)/qemu-img \
$(datadir)/bios.bin \
$(datadir)/vgabios.bin \
$(datadir)/vgabios-cirrus.bin \
$(datadir)/ppc_rom.bin \
$(datadir)/video.x \
$(datadir)/proll.elf \
$(datadir)/linux_boot.bin \
$(docdir)/qemu-doc.html \
$(docdir)/qemu-tech.html \
$(mandir)/man1/qemu.1 $(mandir)/man1/qemu-img.1 )
test2: test2.c
$(CC) $(CFLAGS) -static $(LDFLAGS) -o $@ $<
ifneq ($(wildcard .depend),)
include .depend
-435
View File
@@ -1,435 +0,0 @@
include config.mak
TARGET_BASE_ARCH:=$(TARGET_ARCH)
ifeq ($(TARGET_ARCH), x86_64)
TARGET_BASE_ARCH:=i386
endif
ifeq ($(TARGET_ARCH), ppc64)
TARGET_BASE_ARCH:=ppc
endif
ifeq ($(TARGET_ARCH), sparc64)
TARGET_BASE_ARCH:=sparc
endif
TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH)
VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio
DEFINES=-I. -I$(TARGET_PATH) -I$(SRC_PATH)
ifdef CONFIG_USER_ONLY
VPATH+=:$(SRC_PATH)/linux-user
DEFINES+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH)
endif
CFLAGS=-Wall -O2 -g -fno-strict-aliasing
#CFLAGS+=-Werror
LDFLAGS=-g
LIBS=
HELPER_CFLAGS=$(CFLAGS)
DYNGEN=../dyngen$(EXESUF)
# user emulator name
ifeq ($(TARGET_ARCH),arm)
ifeq ($(TARGET_WORDS_BIGENDIAN),yes)
QEMU_USER=qemu-armeb
else
QEMU_USER=qemu-arm
endif
else
QEMU_USER=qemu-$(TARGET_ARCH)
endif
# system emulator name
ifdef CONFIG_SOFTMMU
ifeq ($(TARGET_ARCH), i386)
QEMU_SYSTEM=qemu$(EXESUF)
else
QEMU_SYSTEM=qemu-system-$(TARGET_ARCH)$(EXESUF)
endif
else
QEMU_SYSTEM=qemu-fast
endif
ifdef CONFIG_USER_ONLY
PROGS=$(QEMU_USER)
else
PROGS+=$(QEMU_SYSTEM)
ifndef CONFIG_SOFTMMU
CONFIG_STATIC=y
endif
endif # !CONFIG_USER_ONLY
ifdef CONFIG_STATIC
LDFLAGS+=-static
endif
ifeq ($(ARCH),i386)
CFLAGS+=-fomit-frame-pointer
OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2
ifeq ($(HAVE_GCC3_OPTIONS),yes)
OP_CFLAGS+= -falign-functions=0 -fno-gcse
else
OP_CFLAGS+= -malign-functions=0
endif
ifdef TARGET_GPROF
USE_I386_LD=y
endif
ifdef CONFIG_STATIC
USE_I386_LD=y
endif
ifdef USE_I386_LD
LDFLAGS+=-Wl,-T,$(SRC_PATH)/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),x86_64)
OP_CFLAGS=$(CFLAGS) -falign-functions=0
LDFLAGS+=-Wl,-T,$(SRC_PATH)/x86_64.ld
endif
ifeq ($(ARCH),ppc)
CFLAGS+= -D__powerpc__
OP_CFLAGS=$(CFLAGS)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/ppc.ld
endif
ifeq ($(ARCH),s390)
OP_CFLAGS=$(CFLAGS)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/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
HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
# -static is used to avoid g1/g3 usage by the dynamic linker
LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc.ld -static
endif
ifeq ($(ARCH),sparc64)
CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
LDFLAGS+=-m64
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
endif
ifeq ($(ARCH),alpha)
# -msmall-data is not used because we want two-instruction relocations
# for the constant constructions
OP_CFLAGS=-Wall -O2 -g
# Ensure there's only a single GP
CFLAGS += -msmall-data
LDFLAGS+=-Wl,-T,$(SRC_PATH)/alpha.ld
endif
ifeq ($(ARCH),ia64)
CFLAGS += -mno-sdata
OP_CFLAGS=$(CFLAGS)
LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
endif
ifeq ($(ARCH),arm)
OP_CFLAGS=$(CFLAGS) -mno-sched-prolog -fno-omit-frame-pointer
LDFLAGS+=-Wl,-T,$(SRC_PATH)/arm.ld
endif
ifeq ($(ARCH),m68k)
OP_CFLAGS=$(CFLAGS) -fomit-frame-pointer
LDFLAGS+=-Wl,-T,m68k.ld
endif
ifeq ($(HAVE_GCC3_OPTIONS),yes)
# very important to generate a return at the end of every operation
OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
endif
ifeq ($(CONFIG_DARWIN),yes)
OP_CFLAGS+= -mdynamic-no-pic
LIBS+=-lmx
endif
#########################################################
DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
LIBS+=-lm
ifndef CONFIG_USER_ONLY
LIBS+=-lz
endif
ifdef CONFIG_WIN32
LIBS+=-lwinmm -lws2_32 -liphlpapi
endif
# profiling code
ifdef TARGET_GPROF
LDFLAGS+=-p
main.o: CFLAGS+=-p
endif
OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o
ifeq ($(TARGET_ARCH), i386)
OBJS+= vm86.o
endif
ifeq ($(TARGET_ARCH), arm)
OBJS+=nwfpe/fpa11.o nwfpe/fpa11_cpdo.o \
nwfpe/fpa11_cpdt.o nwfpe/fpa11_cprt.o nwfpe/fpopcode.o nwfpe/single_cpdo.o \
nwfpe/double_cpdo.o nwfpe/extended_cpdo.o arm-semi.o
endif
SRCS:= $(OBJS:.o=.c)
OBJS+= libqemu.a
# cpu emulator library
LIBOBJS=exec.o kqemu.o translate-op.o translate-all.o cpu-exec.o\
translate.o op.o
ifdef CONFIG_SOFTFLOAT
LIBOBJS+=fpu/softfloat.o
else
LIBOBJS+=fpu/softfloat-native.o
endif
DEFINES+=-I$(SRC_PATH)/fpu
ifeq ($(TARGET_ARCH), i386)
LIBOBJS+=helper.o helper2.o
ifeq ($(ARCH), i386)
LIBOBJS+=translate-copy.o
endif
endif
ifeq ($(TARGET_ARCH), x86_64)
LIBOBJS+=helper.o helper2.o
endif
ifeq ($(TARGET_BASE_ARCH), ppc)
LIBOBJS+= op_helper.o helper.o
endif
ifeq ($(TARGET_ARCH), mips)
LIBOBJS+= op_helper.o helper.o
endif
ifeq ($(TARGET_BASE_ARCH), sparc)
LIBOBJS+= op_helper.o helper.o
endif
ifeq ($(TARGET_BASE_ARCH), arm)
LIBOBJS+= op_helper.o
endif
# NOTE: the disassembler code is only needed for debugging
LIBOBJS+=disas.o
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
USE_I386_DIS=y
endif
ifeq ($(findstring x86_64, $(TARGET_ARCH) $(ARCH)),x86_64)
USE_I386_DIS=y
endif
ifdef USE_I386_DIS
LIBOBJS+=i386-dis.o
endif
ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha)
LIBOBJS+=alpha-dis.o
endif
ifeq ($(findstring ppc, $(TARGET_BASE_ARCH) $(ARCH)),ppc)
LIBOBJS+=ppc-dis.o
endif
ifeq ($(findstring mips, $(TARGET_ARCH) $(ARCH)),mips)
LIBOBJS+=mips-dis.o
endif
ifeq ($(findstring sparc, $(TARGET_BASE_ARCH) $(ARCH)),sparc)
LIBOBJS+=sparc-dis.o
endif
ifeq ($(findstring arm, $(TARGET_ARCH) $(ARCH)),arm)
LIBOBJS+=arm-dis.o
endif
ifeq ($(ARCH),ia64)
OBJS += ia64-syscall.o
endif
ifdef CONFIG_GDBSTUB
OBJS+=gdbstub.o
endif
all: $(PROGS)
$(QEMU_USER): $(OBJS)
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
ifeq ($(ARCH),alpha)
# Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of
# the address space (31 bit so sign extending doesn't matter)
echo -ne '\001\000\000\000' | dd of=qemu bs=1 seek=48 count=4 conv=notrunc
endif
# must use static linking to avoid leaving stuff in virtual address space
VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o
VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o
SOUND_HW = sb16.o
AUDIODRV = audio.o noaudio.o wavaudio.o
ifdef CONFIG_SDL
AUDIODRV += sdlaudio.o
endif
ifdef CONFIG_OSS
AUDIODRV += ossaudio.o
endif
pc.o: DEFINES := -DUSE_SB16 $(DEFINES)
ifdef CONFIG_ADLIB
SOUND_HW += fmopl.o adlib.o
endif
ifdef CONFIG_FMOD
AUDIODRV += fmodaudio.o
audio.o fmodaudio.o: DEFINES := -I$(CONFIG_FMOD_INC) $(DEFINES)
LIBS += $(CONFIG_FMOD_LIB)
endif
ifeq ($(TARGET_BASE_ARCH), i386)
# Hardware support
VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o
VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o
endif
ifeq ($(TARGET_BASE_ARCH), ppc)
VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o
endif
ifeq ($(TARGET_ARCH), mips)
VL_OBJS+= mips_r4k.o dma.o vga.o serial.o ne2000.o i8259.o
#VL_OBJS+= #ide.o pckbd.o i8254.o fdc.o m48t59.o
endif
ifeq ($(TARGET_BASE_ARCH), sparc)
ifeq ($(TARGET_ARCH), sparc64)
VL_OBJS+= sun4u.o ide.o ne2000.o pckbd.o vga.o
VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o
VL_OBJS+= cirrus_vga.o parallel.o
VL_OBJS+= magic-load.o
else
VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o
endif
endif
ifdef CONFIG_GDBSTUB
VL_OBJS+=gdbstub.o
endif
ifdef CONFIG_SDL
VL_OBJS+=sdl.o
endif
ifdef CONFIG_COCOA
VL_OBJS+=cocoa.o
COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa
endif
ifdef CONFIG_SLIRP
DEFINES+=-I$(SRC_PATH)/slirp
SLIRP_OBJS=cksum.o if.o ip_icmp.o ip_input.o ip_output.o \
slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o \
tcp_subr.o tcp_timer.o udp.o bootp.o debug.o tftp.o
VL_OBJS+=$(addprefix slirp/, $(SLIRP_OBJS))
endif
VL_LDFLAGS=
# specific flags are needed for non soft mmu emulator
ifdef CONFIG_STATIC
VL_LDFLAGS+=-static
endif
ifndef CONFIG_SOFTMMU
VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386-vl.ld
endif
ifndef CONFIG_DARWIN
ifndef CONFIG_WIN32
VL_LIBS=-lutil
endif
endif
ifdef TARGET_GPROF
vl.o: CFLAGS+=-p
VL_LDFLAGS+=-p
endif
ifeq ($(ARCH),ia64)
VL_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
endif
$(QEMU_SYSTEM): $(VL_OBJS) libqemu.a
$(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS)
cocoa.o: cocoa.m
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
sdl.o: sdl.c keymaps.c sdl_keysym.h
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
sdlaudio.o: sdlaudio.c
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
depend: $(SRCS)
$(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
# libqemu
libqemu.a: $(LIBOBJS)
rm -f $@
$(AR) rcs $@ $(LIBOBJS)
translate.o: translate.c gen-op.h opc.h cpu.h
translate-all.o: translate-all.c opc.h cpu.h
translate-op.o: translate-all.c op.h opc.h cpu.h
op.h: op.o $(DYNGEN)
$(DYNGEN) -o $@ $<
opc.h: op.o $(DYNGEN)
$(DYNGEN) -c -o $@ $<
gen-op.h: op.o $(DYNGEN)
$(DYNGEN) -g -o $@ $<
op.o: op.c
$(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
helper.o: helper.c
$(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $<
ifeq ($(TARGET_BASE_ARCH), i386)
op.o: op.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h ops_sse.h
endif
ifeq ($(TARGET_ARCH), arm)
op.o: op.c op_template.h
endif
ifeq ($(TARGET_BASE_ARCH), sparc)
op.o: op.c op_template.h op_mem.h fop_template.h fbranch_template.h
magic_load.o: elf_op.h
endif
ifeq ($(TARGET_BASE_ARCH), ppc)
op.o: op.c op_template.h op_mem.h
op_helper.o: op_helper_mem.h
translate.o: translate.c translate_init.c
endif
ifeq ($(TARGET_ARCH), mips)
op.o: op.c op_template.c op_mem.c
op_helper.o: op_helper_mem.c
endif
mixeng.o: mixeng.c mixeng.h mixeng_template.h
%.o: %.c
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
%.o: %.S
$(CC) $(DEFINES) -c -o $@ $<
clean:
rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o fpu/*.o
install: all
ifneq ($(PROGS),)
install -m 755 -s $(PROGS) "$(bindir)"
endif
ifneq ($(wildcard .depend),)
include .depend
endif
-3
View File
@@ -1,3 +0,0 @@
Read the documentation in qemu-doc.html.
Fabrice Bellard.
-16
View File
@@ -1,16 +0,0 @@
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/wine-i386
All exe and libs were stripped. Some compile time tools and the
includes were deleted.
* ldconfig was launched to build the library links:
qemu-i386 /usr/gnemul/qemu-i386/bin/ldconfig-i386 -C /usr/gnemul/qemu-i386/etc/ld.so.cache
+2 -57
View File
@@ -1,57 +1,2 @@
short term:
----------
- debug option in 'configure' script + disable -fomit-frame-pointer
- Precise VGA timings for old games/demos (malc patch)
- merge PIC spurious interrupt patch
- merge Solaris patch
- warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?)
- config file (at least for windows/Mac OS X)
- commit message if execution of code in IO memory
- update doc: PCI infos.
- VNC patch + Synaptic patch.
- basic VGA optimizations
- physical memory cache (reduce qemu-fast address space size to about 32 MB)
- better code fetch (different exception handling + CS.limit support)
- do not resize vga if invalid size.
- avoid looping if only exceptions
- cycle counter for all archs
- TLB code protection support for PPC
- see openMosix Doc
- disable SMC handling for ARM/SPARC/PPC (not finished)
- see undefined flags for BTx insn
- user/kernel PUSHL/POPL in helper.c
- keyboard output buffer filling timing emulation
- return UD exception if LOCK prefix incorrectly used
- test ldt limit < 7 ?
- tests for each target CPU
- fix CCOP optimisation
- fix all remaining thread lock issues (must put TBs in a specific invalid
state, find a solution for tb_flush()).
- fix arm fpu rounding (at least for float->integer conversions)
- SMP support
ppc specific:
------------
- TLB invalidate not needed if msr_pr changes
- SPR_ENCODE() not useful
- enable shift optimizations ?
lower priority:
--------------
- more friendly BIOS (logo)
- int15 ah=86: use better timing
- suppress shift_mem ops
- fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret)
- optimize FPU operations (evaluate x87 stack pointer statically)
- add IPC syscalls
- use -msoft-float on ARM
- use kernel traps for unaligned accesses on ARM ?
- handle rare page fault cases (in particular if page fault in helpers 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)
- 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).
- swap all elf paramters
- fix printf for doubles (fp87.c bug ?)
-1
View File
@@ -1 +0,0 @@
0.7.1
-431
View File
@@ -1,431 +0,0 @@
/* a.out.h
Copyright 1997, 1998, 1999, 2001 Red Hat, Inc.
This file is part of Cygwin.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#ifndef _A_OUT_H_
#define _A_OUT_H_
#ifdef __cplusplus
extern "C" {
#endif
#define COFF_IMAGE_WITH_PE
#define COFF_LONG_SECTION_NAMES
/*** coff information for Intel 386/486. */
/********************** FILE HEADER **********************/
struct external_filehdr {
short f_magic; /* magic number */
short f_nscns; /* number of sections */
unsigned long f_timdat; /* time & date stamp */
unsigned long f_symptr; /* file pointer to symtab */
unsigned long f_nsyms; /* number of symtab entries */
short f_opthdr; /* sizeof(optional hdr) */
short f_flags; /* flags */
};
/* Bits for f_flags:
* F_RELFLG relocation info stripped from file
* F_EXEC file is executable (no unresolved external references)
* F_LNNO line numbers stripped from file
* F_LSYMS local symbols stripped from file
* F_AR32WR file has byte ordering of an AR32WR machine (e.g. vax)
*/
#define F_RELFLG (0x0001)
#define F_EXEC (0x0002)
#define F_LNNO (0x0004)
#define F_LSYMS (0x0008)
#define I386MAGIC 0x14c
#define I386PTXMAGIC 0x154
#define I386AIXMAGIC 0x175
/* This is Lynx's all-platform magic number for executables. */
#define LYNXCOFFMAGIC 0415
#define I386BADMAG(x) (((x).f_magic != I386MAGIC) \
&& (x).f_magic != I386AIXMAGIC \
&& (x).f_magic != I386PTXMAGIC \
&& (x).f_magic != LYNXCOFFMAGIC)
#define FILHDR struct external_filehdr
#define FILHSZ 20
/********************** AOUT "OPTIONAL HEADER"=
**********************/
typedef struct
{
unsigned short magic; /* type of file */
unsigned short vstamp; /* version stamp */
unsigned long tsize; /* text size in bytes, padded to FW bdry*/
unsigned long dsize; /* initialized data " " */
unsigned long bsize; /* uninitialized data " " */
unsigned long entry; /* entry pt. */
unsigned long text_start; /* base of text used for this file */
unsigned long data_start; /* base of data used for this file=
*/
}
AOUTHDR;
#define AOUTSZ 28
#define AOUTHDRSZ 28
#define OMAGIC 0404 /* object files, eg as output */
#define ZMAGIC 0413 /* demand load format, eg normal ld output */
#define STMAGIC 0401 /* target shlib */
#define SHMAGIC 0443 /* host shlib */
/* define some NT default values */
/* #define NT_IMAGE_BASE 0x400000 moved to internal.h */
#define NT_SECTION_ALIGNMENT 0x1000
#define NT_FILE_ALIGNMENT 0x200
#define NT_DEF_RESERVE 0x100000
#define NT_DEF_COMMIT 0x1000
/********************** SECTION HEADER **********************/
struct external_scnhdr {
char s_name[8]; /* section name */
unsigned long s_paddr; /* physical address, offset
of last addr in scn */
unsigned long s_vaddr; /* virtual address */
unsigned long s_size; /* section size */
unsigned long s_scnptr; /* file ptr to raw data for section */
unsigned long s_relptr; /* file ptr to relocation */
unsigned long s_lnnoptr; /* file ptr to line numbers */
unsigned short s_nreloc; /* number of relocation entries */
unsigned short s_nlnno; /* number of line number entries*/
unsigned long s_flags; /* flags */
};
#define SCNHDR struct external_scnhdr
#define SCNHSZ 40
/*
* names of "special" sections
*/
#define _TEXT ".text"
#define _DATA ".data"
#define _BSS ".bss"
#define _COMMENT ".comment"
#define _LIB ".lib"
/********************** LINE NUMBERS **********************/
/* 1 line number entry for every "breakpointable" source line in a section.
* Line numbers are grouped on a per function basis; first entry in a function
* grouping will have l_lnno = 0 and in place of physical address will be the
* symbol table index of the function name.
*/
struct external_lineno {
union {
unsigned long l_symndx; /* function name symbol index, iff l_lnno 0 */
unsigned long l_paddr; /* (physical) address of line number */
} l_addr;
unsigned short l_lnno; /* line number */
};
#define LINENO struct external_lineno
#define LINESZ 6
/********************** SYMBOLS **********************/
#define E_SYMNMLEN 8 /* # characters in a symbol name */
#define E_FILNMLEN 14 /* # characters in a file name */
#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */
struct __attribute__((packed)) external_syment
{
union {
char e_name[E_SYMNMLEN];
struct {
unsigned long e_zeroes;
unsigned long e_offset;
} e;
} e;
unsigned long e_value;
unsigned short e_scnum;
unsigned short e_type;
char e_sclass[1];
char e_numaux[1];
};
#define N_BTMASK (0xf)
#define N_TMASK (0x30)
#define N_BTSHFT (4)
#define N_TSHIFT (2)
union external_auxent {
struct {
unsigned long x_tagndx; /* str, un, or enum tag indx */
union {
struct {
unsigned short x_lnno; /* declaration line number */
unsigned short x_size; /* str/union/array size */
} x_lnsz;
unsigned long x_fsize; /* size of function */
} x_misc;
union {
struct { /* if ISFCN, tag, or .bb */
unsigned long x_lnnoptr;/* ptr to fcn line # */
unsigned long x_endndx; /* entry ndx past block end */
} x_fcn;
struct { /* if ISARY, up to 4 dimen. */
char x_dimen[E_DIMNUM][2];
} x_ary;
} x_fcnary;
unsigned short x_tvndx; /* tv index */
} x_sym;
union {
char x_fname[E_FILNMLEN];
struct {
unsigned long x_zeroes;
unsigned long x_offset;
} x_n;
} x_file;
struct {
unsigned long x_scnlen; /* section length */
unsigned short x_nreloc; /* # relocation entries */
unsigned short x_nlinno; /* # line numbers */
unsigned long x_checksum; /* section COMDAT checksum */
unsigned short x_associated;/* COMDAT associated section index */
char x_comdat[1]; /* COMDAT selection number */
} x_scn;
struct {
unsigned long x_tvfill; /* tv fill value */
unsigned short x_tvlen; /* length of .tv */
char x_tvran[2][2]; /* tv range */
} x_tv; /* info about .tv section (in auxent of symbol .tv)) */
};
#define SYMENT struct external_syment
#define SYMESZ 18
#define AUXENT union external_auxent
#define AUXESZ 18
#define _ETEXT "etext"
/********************** RELOCATION DIRECTIVES **********************/
struct external_reloc {
char r_vaddr[4];
char r_symndx[4];
char r_type[2];
};
#define RELOC struct external_reloc
#define RELSZ 10
/* end of coff/i386.h */
/* PE COFF header information */
#ifndef _PE_H
#define _PE_H
/* NT specific file attributes */
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008
#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080
#define IMAGE_FILE_32BIT_MACHINE 0x0100
#define IMAGE_FILE_DEBUG_STRIPPED 0x0200
#define IMAGE_FILE_SYSTEM 0x1000
#define IMAGE_FILE_DLL 0x2000
#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000
/* additional flags to be set for section headers to allow the NT loader to
read and write to the section data (to replace the addresses of data in
dlls for one thing); also to execute the section in .text's case=
*/
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
#define IMAGE_SCN_MEM_READ 0x40000000
#define IMAGE_SCN_MEM_WRITE 0x80000000
/*
* Section characteristics added for ppc-nt
*/
#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* Reserved. */
#define IMAGE_SCN_CNT_CODE 0x00000020 /* Section contains code. */
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 /* Section contains initialized data. */
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 /* Section contains uninitialized data. */
#define IMAGE_SCN_LNK_OTHER 0x00000100 /* Reserved. */
#define IMAGE_SCN_LNK_INFO 0x00000200 /* Section contains comments or some other type of information. */
#define IMAGE_SCN_LNK_REMOVE 0x00000800 /* Section contents will not become part of image. */
#define IMAGE_SCN_LNK_COMDAT 0x00001000 /* Section contents comdat. */
#define IMAGE_SCN_MEM_FARDATA 0x00008000
#define IMAGE_SCN_MEM_PURGEABLE 0x00020000
#define IMAGE_SCN_MEM_16BIT 0x00020000
#define IMAGE_SCN_MEM_LOCKED 0x00040000
#define IMAGE_SCN_MEM_PRELOAD 0x00080000
#define IMAGE_SCN_ALIGN_1BYTES 0x00100000
#define IMAGE_SCN_ALIGN_2BYTES 0x00200000
#define IMAGE_SCN_ALIGN_4BYTES 0x00300000
#define IMAGE_SCN_ALIGN_8BYTES 0x00400000
#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 /* Default alignment if no others are specified. */
#define IMAGE_SCN_ALIGN_32BYTES 0x00600000
#define IMAGE_SCN_ALIGN_64BYTES 0x00700000
#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 /* Section contains extended relocations. */
#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 /* Section is not cachable. */
#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 /* Section is not pageable. */
#define IMAGE_SCN_MEM_SHARED 0x10000000 /* Section is shareable. */
/* COMDAT selection codes. */
#define IMAGE_COMDAT_SELECT_NODUPLICATES (1) /* Warn if duplicates. */
#define IMAGE_COMDAT_SELECT_ANY (2) /* No warning. */
#define IMAGE_COMDAT_SELECT_SAME_SIZE (3) /* Warn if different size. */
#define IMAGE_COMDAT_SELECT_EXACT_MATCH (4) /* Warn if different. */
#define IMAGE_COMDAT_SELECT_ASSOCIATIVE (5) /* Base on other section. */
/* Magic values that are true for all dos/nt implementations */
#define DOSMAGIC 0x5a4d
#define NT_SIGNATURE 0x00004550
/* NT allows long filenames, we want to accommodate this. This may break
some of the bfd functions */
#undef FILNMLEN
#define FILNMLEN 18 /* # characters in a file name */
#ifdef COFF_IMAGE_WITH_PE
/* The filehdr is only weired in images */
#undef FILHDR
struct external_PE_filehdr
{
/* DOS header fields */
unsigned short e_magic; /* Magic number, 0x5a4d */
unsigned short e_cblp; /* Bytes on last page of file, 0x90 */
unsigned short e_cp; /* Pages in file, 0x3 */
unsigned short e_crlc; /* Relocations, 0x0 */
unsigned short e_cparhdr; /* Size of header in paragraphs, 0x4 */
unsigned short e_minalloc; /* Minimum extra paragraphs needed, 0x0 */
unsigned short e_maxalloc; /* Maximum extra paragraphs needed, 0xFFFF */
unsigned short e_ss; /* Initial (relative) SS value, 0x0 */
unsigned short e_sp; /* Initial SP value, 0xb8 */
unsigned short e_csum; /* Checksum, 0x0 */
unsigned short e_ip; /* Initial IP value, 0x0 */
unsigned short e_cs; /* Initial (relative) CS value, 0x0 */
unsigned short e_lfarlc; /* File address of relocation table, 0x40 */
unsigned short e_ovno; /* Overlay number, 0x0 */
char e_res[4][2]; /* Reserved words, all 0x0 */
unsigned short e_oemid; /* OEM identifier (for e_oeminfo), 0x0 */
unsigned short e_oeminfo; /* OEM information; e_oemid specific, 0x0 */
char e_res2[10][2]; /* Reserved words, all 0x0 */
unsigned long e_lfanew; /* File address of new exe header, 0x80 */
char dos_message[16][4]; /* other stuff, always follow DOS header */
unsigned int nt_signature; /* required NT signature, 0x4550 */
/* From standard header */
unsigned short f_magic; /* magic number */
unsigned short f_nscns; /* number of sections */
unsigned long f_timdat; /* time & date stamp */
unsigned long f_symptr; /* file pointer to symtab */
unsigned long f_nsyms; /* number of symtab entries */
unsigned short f_opthdr; /* sizeof(optional hdr) */
unsigned short f_flags; /* flags */
};
#define FILHDR struct external_PE_filehdr
#undef FILHSZ
#define FILHSZ 152
#endif
typedef struct
{
unsigned short magic; /* type of file */
unsigned short vstamp; /* version stamp */
unsigned long tsize; /* text size in bytes, padded to FW bdry*/
unsigned long dsize; /* initialized data " " */
unsigned long bsize; /* uninitialized data " " */
unsigned long entry; /* entry pt. */
unsigned long text_start; /* base of text used for this file */
unsigned long data_start; /* base of all data used for this file */
/* NT extra fields; see internal.h for descriptions */
unsigned long ImageBase;
unsigned long SectionAlignment;
unsigned long FileAlignment;
unsigned short MajorOperatingSystemVersion;
unsigned short MinorOperatingSystemVersion;
unsigned short MajorImageVersion;
unsigned short MinorImageVersion;
unsigned short MajorSubsystemVersion;
unsigned short MinorSubsystemVersion;
char Reserved1[4];
unsigned long SizeOfImage;
unsigned long SizeOfHeaders;
unsigned long CheckSum;
unsigned short Subsystem;
unsigned short DllCharacteristics;
unsigned long SizeOfStackReserve;
unsigned long SizeOfStackCommit;
unsigned long SizeOfHeapReserve;
unsigned long SizeOfHeapCommit;
unsigned long LoaderFlags;
unsigned long NumberOfRvaAndSizes;
/* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */
char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars */
} PEAOUTHDR;
#undef AOUTSZ
#define AOUTSZ (AOUTHDRSZ + 196)
#undef E_FILNMLEN
#define E_FILNMLEN 18 /* # characters in a file name */
#endif
/* end of coff/pe.h */
#define DT_NON (0) /* no derived type */
#define DT_PTR (1) /* pointer */
#define DT_FCN (2) /* function */
#define DT_ARY (3) /* array */
#define ISPTR(x) (((x) & N_TMASK) == (DT_PTR << N_BTSHFT))
#define ISFCN(x) (((x) & N_TMASK) == (DT_FCN << N_BTSHFT))
#define ISARY(x) (((x) & N_TMASK) == (DT_ARY << N_BTSHFT))
#ifdef __cplusplus
}
#endif
#endif /* _A_OUT_H_ */
-1317
View File
File diff suppressed because it is too large. Load diff
-26
View File
@@ -1,26 +0,0 @@
#ifndef QEMU_AES_H
#define QEMU_AES_H
#define AES_MAXNR 14
#define AES_BLOCK_SIZE 16
struct aes_key_st {
uint32_t rd_key[4 *(AES_MAXNR + 1)];
int rounds;
};
typedef struct aes_key_st AES_KEY;
int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
AES_KEY *key);
int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
AES_KEY *key);
void AES_encrypt(const unsigned char *in, unsigned char *out,
const AES_KEY *key);
void AES_decrypt(const unsigned char *in, unsigned char *out,
const AES_KEY *key);
void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
const unsigned long length, const AES_KEY *key,
unsigned char *ivec, const int enc);
#endif
-1963
View File
File diff suppressed because it is too large. Load diff
-128
View File
@@ -1,128 +0,0 @@
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 . */
}
-1680
View File
File diff suppressed because it is too large. Load diff
-128
View File
@@ -1,128 +0,0 @@
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm",
"elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
SECTIONS
{
/* Read-only sections, merged into text segment: */
. = 0x60000000 + SIZEOF_HEADERS;
.interp : { *(.interp) }
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rel.text :
{ *(.rel.text) *(.rel.gnu.linkonce.t*) }
.rela.text :
{ *(.rela.text) *(.rela.gnu.linkonce.t*) }
.rel.data :
{ *(.rel.data) *(.rel.gnu.linkonce.d*) }
.rela.data :
{ *(.rela.data) *(.rela.gnu.linkonce.d*) }
.rel.rodata :
{ *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
.rela.rodata :
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
.rel.got : { *(.rel.got) }
.rela.got : { *(.rela.got) }
.rel.ctors : { *(.rel.ctors) }
.rela.ctors : { *(.rela.ctors) }
.rel.dtors : { *(.rel.dtors) }
.rela.dtors : { *(.rela.dtors) }
.rel.init : { *(.rel.init) }
.rela.init : { *(.rela.init) }
.rel.fini : { *(.rel.fini) }
.rela.fini : { *(.rela.fini) }
.rel.bss : { *(.rel.bss) }
.rela.bss : { *(.rela.bss) }
.rel.plt : { *(.rel.plt) }
.rela.plt : { *(.rela.plt) }
.init : { *(.init) } =0x47ff041f
.text :
{
*(.text)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.gnu.linkonce.t*)
} =0x47ff041f
_etext = .;
PROVIDE (etext = .);
.fini : { *(.fini) } =0x47ff041f
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
.rodata1 : { *(.rodata1) }
.reginfo : { *(.reginfo) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = ALIGN(0x100000) + (. & (0x100000 - 1));
.data :
{
*(.data)
*(.gnu.linkonce.d*)
CONSTRUCTORS
}
.data1 : { *(.data1) }
.ctors :
{
*(.ctors)
}
.dtors :
{
*(.dtors)
}
.plt : { *(.plt) }
.got : { *(.got.plt) *(.got) }
.dynamic : { *(.dynamic) }
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
.sdata : { *(.sdata) }
_edata = .;
PROVIDE (edata = .);
__bss_start = .;
.sbss : { *(.sbss) *(.scommon) }
.bss :
{
*(.dynbss)
*(.bss)
*(COMMON)
}
_end = . ;
PROVIDE (end = .);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* These must appear regardless of . */
}
-911
View File
@@ -1,911 +0,0 @@
/*
* QEMU Audio subsystem
*
* Copyright (c) 2003-2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <assert.h>
#include "vl.h"
#define USE_WAV_AUDIO
#include "audio/audio_int.h"
#define dolog(...) AUD_log ("audio", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
#define QC_AUDIO_DRV "QEMU_AUDIO_DRV"
#define QC_VOICES "QEMU_VOICES"
#define QC_FIXED_FORMAT "QEMU_FIXED_FORMAT"
#define QC_FIXED_FREQ "QEMU_FIXED_FREQ"
static HWVoice *hw_voices;
AudioState audio_state = {
1, /* use fixed settings */
44100, /* fixed frequency */
2, /* fixed channels */
AUD_FMT_S16, /* fixed format */
1, /* number of hw voices */
-1 /* voice size */
};
/* http://www.df.lth.se/~john_e/gems/gem002d.html */
/* http://www.multi-platforms.com/Tips/PopCount.htm */
uint32_t popcount (uint32_t u)
{
u = ((u&0x55555555) + ((u>>1)&0x55555555));
u = ((u&0x33333333) + ((u>>2)&0x33333333));
u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
u = ( u&0x0000ffff) + (u>>16);
return u;
}
inline uint32_t lsbindex (uint32_t u)
{
return popcount ((u&-u)-1);
}
int audio_get_conf_int (const char *key, int defval)
{
int val = defval;
char *strval;
strval = getenv (key);
if (strval) {
val = atoi (strval);
}
return val;
}
const char *audio_get_conf_str (const char *key, const char *defval)
{
const char *val = getenv (key);
if (!val)
return defval;
else
return val;
}
void AUD_log (const char *cap, const char *fmt, ...)
{
va_list ap;
fprintf (stderr, "%s: ", cap);
va_start (ap, fmt);
vfprintf (stderr, fmt, ap);
va_end (ap);
}
/*
* Soft Voice
*/
void pcm_sw_free_resources (SWVoice *sw)
{
if (sw->buf) qemu_free (sw->buf);
if (sw->rate) st_rate_stop (sw->rate);
sw->buf = NULL;
sw->rate = NULL;
}
int pcm_sw_alloc_resources (SWVoice *sw)
{
sw->buf = qemu_mallocz (sw->hw->samples * sizeof (st_sample_t));
if (!sw->buf)
return -1;
sw->rate = st_rate_start (sw->freq, sw->hw->freq);
if (!sw->rate) {
qemu_free (sw->buf);
sw->buf = NULL;
return -1;
}
return 0;
}
void pcm_sw_fini (SWVoice *sw)
{
pcm_sw_free_resources (sw);
}
int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq,
int nchannels, audfmt_e fmt)
{
int bits = 8, sign = 0;
switch (fmt) {
case AUD_FMT_S8:
sign = 1;
case AUD_FMT_U8:
break;
case AUD_FMT_S16:
sign = 1;
case AUD_FMT_U16:
bits = 16;
break;
}
sw->hw = hw;
sw->freq = freq;
sw->fmt = fmt;
sw->nchannels = nchannels;
sw->shift = (nchannels == 2) + (bits == 16);
sw->align = (1 << sw->shift) - 1;
sw->left = 0;
sw->pos = 0;
sw->wpos = 0;
sw->live = 0;
sw->ratio = (sw->hw->freq * ((int64_t) INT_MAX)) / sw->freq;
sw->bytes_per_second = sw->freq << sw->shift;
sw->conv = mixeng_conv[nchannels == 2][sign][bits == 16];
pcm_sw_free_resources (sw);
return pcm_sw_alloc_resources (sw);
}
/* Hard voice */
void pcm_hw_free_resources (HWVoice *hw)
{
if (hw->mix_buf)
qemu_free (hw->mix_buf);
hw->mix_buf = NULL;
}
int pcm_hw_alloc_resources (HWVoice *hw)
{
hw->mix_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t));
if (!hw->mix_buf)
return -1;
return 0;
}
void pcm_hw_fini (HWVoice *hw)
{
if (hw->active) {
ldebug ("pcm_hw_fini: %d %d %d\n", hw->freq, hw->nchannels, hw->fmt);
pcm_hw_free_resources (hw);
hw->pcm_ops->fini (hw);
memset (hw, 0, audio_state.drv->voice_size);
}
}
void pcm_hw_gc (HWVoice *hw)
{
if (hw->nb_voices)
return;
pcm_hw_fini (hw);
}
int pcm_hw_get_live (HWVoice *hw)
{
int i, alive = 0, live = hw->samples;
for (i = 0; i < hw->nb_voices; i++) {
if (hw->pvoice[i]->live) {
live = audio_MIN (hw->pvoice[i]->live, live);
alive += 1;
}
}
if (alive)
return live;
else
return -1;
}
int pcm_hw_get_live2 (HWVoice *hw, int *nb_active)
{
int i, alive = 0, live = hw->samples;
*nb_active = 0;
for (i = 0; i < hw->nb_voices; i++) {
if (hw->pvoice[i]->live) {
if (hw->pvoice[i]->live < live) {
*nb_active = hw->pvoice[i]->active != 0;
live = hw->pvoice[i]->live;
}
alive += 1;
}
}
if (alive)
return live;
else
return -1;
}
void pcm_hw_dec_live (HWVoice *hw, int decr)
{
int i;
for (i = 0; i < hw->nb_voices; i++) {
if (hw->pvoice[i]->live) {
hw->pvoice[i]->live -= decr;
}
}
}
void pcm_hw_clear (HWVoice *hw, void *buf, int len)
{
if (!len)
return;
switch (hw->fmt) {
case AUD_FMT_S16:
case AUD_FMT_S8:
memset (buf, len << hw->shift, 0x00);
break;
case AUD_FMT_U8:
memset (buf, len << hw->shift, 0x80);
break;
case AUD_FMT_U16:
{
unsigned int i;
uint16_t *p = buf;
int shift = hw->nchannels - 1;
for (i = 0; i < len << shift; i++) {
p[i] = INT16_MAX;
}
}
break;
}
}
int pcm_hw_write (SWVoice *sw, void *buf, int size)
{
int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
int ret = 0, pos = 0;
if (!sw)
return size;
hwsamples = sw->hw->samples;
samples = size >> sw->shift;
if (!sw->live) {
sw->wpos = sw->hw->rpos;
}
wpos = sw->wpos;
live = sw->live;
dead = hwsamples - live;
swlim = (dead * ((int64_t) INT_MAX)) / sw->ratio;
swlim = audio_MIN (swlim, samples);
ldebug ("size=%d live=%d dead=%d swlim=%d wpos=%d\n",
size, live, dead, swlim, wpos);
if (swlim)
sw->conv (sw->buf, buf, swlim);
while (swlim) {
dead = hwsamples - live;
left = hwsamples - wpos;
blck = audio_MIN (dead, left);
if (!blck) {
/* dolog ("swlim=%d\n", swlim); */
break;
}
isamp = swlim;
osamp = blck;
st_rate_flow (sw->rate, sw->buf + pos, sw->hw->mix_buf + wpos, &isamp, &osamp);
ret += isamp;
swlim -= isamp;
pos += isamp;
live += osamp;
wpos = (wpos + osamp) % hwsamples;
}
sw->wpos = wpos;
sw->live = live;
return ret << sw->shift;
}
int pcm_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
int sign = 0, bits = 8;
pcm_hw_fini (hw);
ldebug ("pcm_hw_init: %d %d %d\n", freq, nchannels, fmt);
if (hw->pcm_ops->init (hw, freq, nchannels, fmt)) {
memset (hw, 0, audio_state.drv->voice_size);
return -1;
}
switch (hw->fmt) {
case AUD_FMT_S8:
sign = 1;
case AUD_FMT_U8:
break;
case AUD_FMT_S16:
sign = 1;
case AUD_FMT_U16:
bits = 16;
break;
}
hw->nb_voices = 0;
hw->active = 1;
hw->shift = (hw->nchannels == 2) + (bits == 16);
hw->bytes_per_second = hw->freq << hw->shift;
hw->align = (1 << hw->shift) - 1;
hw->samples = hw->bufsize >> hw->shift;
hw->clip = mixeng_clip[hw->nchannels == 2][sign][bits == 16];
if (pcm_hw_alloc_resources (hw)) {
pcm_hw_fini (hw);
return -1;
}
return 0;
}
static int dist (void *hw)
{
if (hw) {
return (((uint8_t *) hw - (uint8_t *) hw_voices)
/ audio_state.drv->voice_size) + 1;
}
else {
return 0;
}
}
#define ADVANCE(hw) \
((hw) ? advance (hw, audio_state.drv->voice_size) : hw_voices)
HWVoice *pcm_hw_find_any (HWVoice *hw)
{
int i = dist (hw);
for (; i < audio_state.nb_hw_voices; i++) {
hw = ADVANCE (hw);
return hw;
}
return NULL;
}
HWVoice *pcm_hw_find_any_active (HWVoice *hw)
{
int i = dist (hw);
for (; i < audio_state.nb_hw_voices; i++) {
hw = ADVANCE (hw);
if (hw->active)
return hw;
}
return NULL;
}
HWVoice *pcm_hw_find_any_active_enabled (HWVoice *hw)
{
int i = dist (hw);
for (; i < audio_state.nb_hw_voices; i++) {
hw = ADVANCE (hw);
if (hw->active && hw->enabled)
return hw;
}
return NULL;
}
HWVoice *pcm_hw_find_any_passive (HWVoice *hw)
{
int i = dist (hw);
for (; i < audio_state.nb_hw_voices; i++) {
hw = ADVANCE (hw);
if (!hw->active)
return hw;
}
return NULL;
}
HWVoice *pcm_hw_find_specific (HWVoice *hw, int freq,
int nchannels, audfmt_e fmt)
{
while ((hw = pcm_hw_find_any_active (hw))) {
if (hw->freq == freq &&
hw->nchannels == nchannels &&
hw->fmt == fmt)
return hw;
}
return NULL;
}
HWVoice *pcm_hw_add (int freq, int nchannels, audfmt_e fmt)
{
HWVoice *hw;
if (audio_state.fixed_format) {
freq = audio_state.fixed_freq;
nchannels = audio_state.fixed_channels;
fmt = audio_state.fixed_fmt;
}
hw = pcm_hw_find_specific (NULL, freq, nchannels, fmt);
if (hw)
return hw;
hw = pcm_hw_find_any_passive (NULL);
if (hw) {
hw->pcm_ops = audio_state.drv->pcm_ops;
if (!hw->pcm_ops)
return NULL;
if (pcm_hw_init (hw, freq, nchannels, fmt)) {
pcm_hw_gc (hw);
return NULL;
}
else
return hw;
}
return pcm_hw_find_any (NULL);
}
int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw)
{
SWVoice **pvoice = qemu_mallocz ((hw->nb_voices + 1) * sizeof (sw));
if (!pvoice)
return -1;
memcpy (pvoice, hw->pvoice, hw->nb_voices * sizeof (sw));
qemu_free (hw->pvoice);
hw->pvoice = pvoice;
hw->pvoice[hw->nb_voices++] = sw;
return 0;
}
int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw)
{
int i, j;
if (hw->nb_voices > 1) {
SWVoice **pvoice = qemu_mallocz ((hw->nb_voices - 1) * sizeof (sw));
if (!pvoice) {
dolog ("Can not maintain consistent state (not enough memory)\n");
return -1;
}
for (i = 0, j = 0; i < hw->nb_voices; i++) {
if (j >= hw->nb_voices - 1) {
dolog ("Can not maintain consistent state "
"(invariant violated)\n");
return -1;
}
if (hw->pvoice[i] != sw)
pvoice[j++] = hw->pvoice[i];
}
qemu_free (hw->pvoice);
hw->pvoice = pvoice;
hw->nb_voices -= 1;
}
else {
qemu_free (hw->pvoice);
hw->pvoice = NULL;
hw->nb_voices = 0;
}
return 0;
}
SWVoice *pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt)
{
SWVoice *sw;
HWVoice *hw;
sw = qemu_mallocz (sizeof (*sw));
if (!sw)
goto err1;
hw = pcm_hw_add (freq, nchannels, fmt);
if (!hw)
goto err2;
if (pcm_hw_add_sw (hw, sw))
goto err3;
if (pcm_sw_init (sw, hw, freq, nchannels, fmt))
goto err4;
return sw;
err4:
pcm_hw_del_sw (hw, sw);
err3:
pcm_hw_gc (hw);
err2:
qemu_free (sw);
err1:
return NULL;
}
SWVoice *AUD_open (SWVoice *sw, const char *name,
int freq, int nchannels, audfmt_e fmt)
{
if (!audio_state.drv) {
return NULL;
}
if (sw && freq == sw->freq && sw->nchannels == nchannels && sw->fmt == fmt) {
return sw;
}
if (sw) {
ldebug ("Different format %s %d %d %d\n",
name,
sw->freq == freq,
sw->nchannels == nchannels,
sw->fmt == fmt);
}
if (nchannels != 1 && nchannels != 2) {
dolog ("Bogus channel count %d for voice %s\n", nchannels, name);
return NULL;
}
if (!audio_state.fixed_format && sw) {
pcm_sw_fini (sw);
pcm_hw_del_sw (sw->hw, sw);
pcm_hw_gc (sw->hw);
if (sw->name) {
qemu_free (sw->name);
sw->name = NULL;
}
qemu_free (sw);
sw = NULL;
}
if (sw) {
HWVoice *hw = sw->hw;
if (!hw) {
dolog ("Internal logic error voice %s has no hardware store\n",
name);
return sw;
}
if (pcm_sw_init (sw, hw, freq, nchannels, fmt)) {
pcm_sw_fini (sw);
pcm_hw_del_sw (hw, sw);
pcm_hw_gc (hw);
if (sw->name) {
qemu_free (sw->name);
sw->name = NULL;
}
qemu_free (sw);
return NULL;
}
}
else {
sw = pcm_create_voice_pair (freq, nchannels, fmt);
if (!sw) {
dolog ("Failed to create voice %s\n", name);
return NULL;
}
}
if (sw->name) {
qemu_free (sw->name);
sw->name = NULL;
}
sw->name = qemu_strdup (name);
return sw;
}
void AUD_close (SWVoice *sw)
{
if (!sw)
return;
pcm_sw_fini (sw);
pcm_hw_del_sw (sw->hw, sw);
pcm_hw_gc (sw->hw);
if (sw->name) {
qemu_free (sw->name);
sw->name = NULL;
}
qemu_free (sw);
}
int AUD_write (SWVoice *sw, void *buf, int size)
{
int bytes;
if (!sw->hw->enabled)
dolog ("Writing to disabled voice %s\n", sw->name);
bytes = sw->hw->pcm_ops->write (sw, buf, size);
return bytes;
}
void AUD_run (void)
{
HWVoice *hw = NULL;
while ((hw = pcm_hw_find_any_active_enabled (hw))) {
int i;
if (hw->pending_disable && pcm_hw_get_live (hw) <= 0) {
hw->enabled = 0;
hw->pcm_ops->ctl (hw, VOICE_DISABLE);
for (i = 0; i < hw->nb_voices; i++) {
hw->pvoice[i]->live = 0;
/* hw->pvoice[i]->old_ticks = 0; */
}
continue;
}
hw->pcm_ops->run (hw);
assert (hw->rpos < hw->samples);
for (i = 0; i < hw->nb_voices; i++) {
SWVoice *sw = hw->pvoice[i];
if (!sw->active && !sw->live && sw->old_ticks) {
int64_t delta = qemu_get_clock (vm_clock) - sw->old_ticks;
if (delta > audio_state.ticks_threshold) {
ldebug ("resetting old_ticks for %s\n", sw->name);
sw->old_ticks = 0;
}
}
}
}
}
int AUD_get_free (SWVoice *sw)
{
int free;
if (!sw)
return 4096;
free = ((sw->hw->samples - sw->live) << sw->hw->shift) * sw->ratio
/ INT_MAX;
free &= ~sw->hw->align;
if (!free) return 0;
return free;
}
int AUD_get_buffer_size (SWVoice *sw)
{
return sw->hw->bufsize;
}
void AUD_adjust (SWVoice *sw, int bytes)
{
if (!sw)
return;
sw->old_ticks += (ticks_per_sec * (int64_t) bytes) / sw->bytes_per_second;
}
void AUD_reset (SWVoice *sw)
{
sw->active = 0;
sw->old_ticks = 0;
}
int AUD_calc_elapsed (SWVoice *sw)
{
int64_t now, delta, bytes;
int dead, swlim;
if (!sw)
return 0;
now = qemu_get_clock (vm_clock);
delta = now - sw->old_ticks;
bytes = (delta * sw->bytes_per_second) / ticks_per_sec;
if (delta < 0) {
dolog ("whoops delta(<0)=%lld\n", delta);
return 0;
}
dead = sw->hw->samples - sw->live;
swlim = ((dead * (int64_t) INT_MAX) / sw->ratio);
if (bytes > swlim) {
return swlim;
}
else {
return bytes;
}
}
void AUD_enable (SWVoice *sw, int on)
{
int i;
HWVoice *hw;
if (!sw)
return;
hw = sw->hw;
if (on) {
if (!sw->live)
sw->wpos = sw->hw->rpos;
if (!sw->old_ticks) {
sw->old_ticks = qemu_get_clock (vm_clock);
}
}
if (sw->active != on) {
if (on) {
hw->pending_disable = 0;
if (!hw->enabled) {
hw->enabled = 1;
for (i = 0; i < hw->nb_voices; i++) {
ldebug ("resetting voice\n");
sw = hw->pvoice[i];
sw->old_ticks = qemu_get_clock (vm_clock);
}
hw->pcm_ops->ctl (hw, VOICE_ENABLE);
}
}
else {
if (hw->enabled && !hw->pending_disable) {
int nb_active = 0;
for (i = 0; i < hw->nb_voices; i++) {
nb_active += hw->pvoice[i]->active != 0;
}
if (nb_active == 1) {
hw->pending_disable = 1;
}
}
}
sw->active = on;
}
}
static struct audio_output_driver *drvtab[] = {
#ifdef CONFIG_OSS
&oss_output_driver,
#endif
#ifdef CONFIG_FMOD
&fmod_output_driver,
#endif
#ifdef CONFIG_SDL
&sdl_output_driver,
#endif
&no_output_driver,
#ifdef USE_WAV_AUDIO
&wav_output_driver,
#endif
};
static int voice_init (struct audio_output_driver *drv)
{
audio_state.opaque = drv->init ();
if (audio_state.opaque) {
if (audio_state.nb_hw_voices > drv->max_voices) {
dolog ("`%s' does not support %d multiple hardware channels\n"
"Resetting to %d\n",
drv->name, audio_state.nb_hw_voices, drv->max_voices);
audio_state.nb_hw_voices = drv->max_voices;
}
hw_voices = qemu_mallocz (audio_state.nb_hw_voices * drv->voice_size);
if (hw_voices) {
audio_state.drv = drv;
return 1;
}
else {
dolog ("Not enough memory for %d `%s' voices (each %d bytes)\n",
audio_state.nb_hw_voices, drv->name, drv->voice_size);
drv->fini (audio_state.opaque);
return 0;
}
}
else {
dolog ("Could not init `%s' audio\n", drv->name);
return 0;
}
}
static void audio_vm_stop_handler (void *opaque, int reason)
{
HWVoice *hw = NULL;
while ((hw = pcm_hw_find_any (hw))) {
if (!hw->pcm_ops)
continue;
hw->pcm_ops->ctl (hw, reason ? VOICE_ENABLE : VOICE_DISABLE);
}
}
static void audio_atexit (void)
{
HWVoice *hw = NULL;
while ((hw = pcm_hw_find_any (hw))) {
if (!hw->pcm_ops)
continue;
hw->pcm_ops->ctl (hw, VOICE_DISABLE);
hw->pcm_ops->fini (hw);
}
audio_state.drv->fini (audio_state.opaque);
}
static void audio_save (QEMUFile *f, void *opaque)
{
}
static int audio_load (QEMUFile *f, void *opaque, int version_id)
{
if (version_id != 1)
return -EINVAL;
return 0;
}
void AUD_init (void)
{
int i;
int done = 0;
const char *drvname;
audio_state.fixed_format =
!!audio_get_conf_int (QC_FIXED_FORMAT, audio_state.fixed_format);
audio_state.fixed_freq =
audio_get_conf_int (QC_FIXED_FREQ, audio_state.fixed_freq);
audio_state.nb_hw_voices =
audio_get_conf_int (QC_VOICES, audio_state.nb_hw_voices);
if (audio_state.nb_hw_voices <= 0) {
dolog ("Bogus number of voices %d, resetting to 1\n",
audio_state.nb_hw_voices);
}
drvname = audio_get_conf_str (QC_AUDIO_DRV, NULL);
if (drvname) {
int found = 0;
for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
if (!strcmp (drvname, drvtab[i]->name)) {
done = voice_init (drvtab[i]);
found = 1;
break;
}
}
if (!found) {
dolog ("Unknown audio driver `%s'\n", drvname);
}
}
qemu_add_vm_stop_handler (audio_vm_stop_handler, NULL);
atexit (audio_atexit);
if (!done) {
for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
if (drvtab[i]->can_be_default)
done = voice_init (drvtab[i]);
}
}
audio_state.ticks_threshold = ticks_per_sec / 50;
audio_state.freq_threshold = 100;
register_savevm ("audio", 0, 1, audio_save, audio_load, NULL);
if (!done) {
dolog ("Can not initialize audio subsystem\n");
voice_init (&no_output_driver);
}
}
-65
View File
@@ -1,65 +0,0 @@
/*
* QEMU Audio subsystem header
*
* Copyright (c) 2003-2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef QEMU_AUDIO_H
#define QEMU_AUDIO_H
#include "mixeng.h"
typedef enum {
AUD_FMT_U8,
AUD_FMT_S8,
AUD_FMT_U16,
AUD_FMT_S16
} audfmt_e;
typedef struct SWVoice SWVoice;
SWVoice * AUD_open (SWVoice *sw, const char *name, int freq,
int nchannels, audfmt_e fmt);
void AUD_init (void);
void AUD_log (const char *cap, const char *fmt, ...)
__attribute__ ((__format__ (__printf__, 2, 3)));;
void AUD_close (SWVoice *sw);
int AUD_write (SWVoice *sw, void *pcm_buf, int size);
void AUD_adjust (SWVoice *sw, int leftover);
void AUD_reset (SWVoice *sw);
int AUD_get_free (SWVoice *sw);
int AUD_get_buffer_size (SWVoice *sw);
void AUD_run (void);
void AUD_enable (SWVoice *sw, int on);
int AUD_calc_elapsed (SWVoice *sw);
static inline void *advance (void *p, int incr)
{
uint8_t *d = p;
return (d + incr);
}
uint32_t popcount (uint32_t u);
inline uint32_t lsbindex (uint32_t u);
#define audio_MIN(a, b) ((a)>(b)?(b):(a))
#define audio_MAX(a, b) ((a)<(b)?(b):(a))
#endif /* audio.h */
-163
View File
@@ -1,163 +0,0 @@
/*
* QEMU Audio subsystem header
*
* Copyright (c) 2003-2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef QEMU_AUDIO_INT_H
#define QEMU_AUDIO_INT_H
#include "vl.h"
struct pcm_ops;
typedef struct HWVoice {
int active;
int enabled;
int pending_disable;
int valid;
int freq;
f_sample *clip;
audfmt_e fmt;
int nchannels;
int align;
int shift;
int rpos;
int bufsize;
int bytes_per_second;
st_sample_t *mix_buf;
int samples;
int64_t old_ticks;
int nb_voices;
struct SWVoice **pvoice;
struct pcm_ops *pcm_ops;
} HWVoice;
extern struct pcm_ops no_pcm_ops;
extern struct audio_output_driver no_output_driver;
extern struct pcm_ops oss_pcm_ops;
extern struct audio_output_driver oss_output_driver;
extern struct pcm_ops sdl_pcm_ops;
extern struct audio_output_driver sdl_output_driver;
extern struct pcm_ops wav_pcm_ops;
extern struct audio_output_driver wav_output_driver;
extern struct pcm_ops fmod_pcm_ops;
extern struct audio_output_driver fmod_output_driver;
struct audio_output_driver {
const char *name;
void *(*init) (void);
void (*fini) (void *);
struct pcm_ops *pcm_ops;
int can_be_default;
int max_voices;
int voice_size;
};
typedef struct AudioState {
int fixed_format;
int fixed_freq;
int fixed_channels;
int fixed_fmt;
int nb_hw_voices;
int64_t ticks_threshold;
int freq_threshold;
void *opaque;
struct audio_output_driver *drv;
} AudioState;
extern AudioState audio_state;
struct SWVoice {
int freq;
audfmt_e fmt;
int nchannels;
int shift;
int align;
t_sample *conv;
int left;
int pos;
int bytes_per_second;
int64_t ratio;
st_sample_t *buf;
void *rate;
int wpos;
int live;
int active;
int64_t old_ticks;
HWVoice *hw;
char *name;
};
struct pcm_ops {
int (*init) (HWVoice *hw, int freq, int nchannels, audfmt_e fmt);
void (*fini) (HWVoice *hw);
void (*run) (HWVoice *hw);
int (*write) (SWVoice *sw, void *buf, int size);
int (*ctl) (HWVoice *hw, int cmd, ...);
};
void pcm_sw_free_resources (SWVoice *sw);
int pcm_sw_alloc_resources (SWVoice *sw);
void pcm_sw_fini (SWVoice *sw);
int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq,
int nchannels, audfmt_e fmt);
void pcm_hw_clear (HWVoice *hw, void *buf, int len);
HWVoice * pcm_hw_find_any (HWVoice *hw);
HWVoice * pcm_hw_find_any_active (HWVoice *hw);
HWVoice * pcm_hw_find_any_passive (HWVoice *hw);
HWVoice * pcm_hw_find_specific (HWVoice *hw, int freq,
int nchannels, audfmt_e fmt);
HWVoice * pcm_hw_add (int freq, int nchannels, audfmt_e fmt);
int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw);
int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw);
SWVoice * pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt);
void pcm_hw_free_resources (HWVoice *hw);
int pcm_hw_alloc_resources (HWVoice *hw);
void pcm_hw_fini (HWVoice *hw);
void pcm_hw_gc (HWVoice *hw);
int pcm_hw_get_live (HWVoice *hw);
int pcm_hw_get_live2 (HWVoice *hw, int *nb_active);
void pcm_hw_dec_live (HWVoice *hw, int decr);
int pcm_hw_write (SWVoice *sw, void *buf, int len);
int audio_get_conf_int (const char *key, int defval);
const char *audio_get_conf_str (const char *key, const char *defval);
struct audio_output_driver;
#define VOICE_ENABLE 1
#define VOICE_DISABLE 2
#endif /* audio_int.h */
-469
View File
@@ -1,469 +0,0 @@
/*
* QEMU FMOD audio output driver
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <fmod.h>
#include <fmod_errors.h>
#include "vl.h"
#include "audio/audio_int.h"
typedef struct FMODVoice {
HWVoice hw;
unsigned int old_pos;
FSOUND_SAMPLE *fmod_sample;
int channel;
} FMODVoice;
#define dolog(...) AUD_log ("fmod", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
#define QC_FMOD_DRV "QEMU_FMOD_DRV"
#define QC_FMOD_FREQ "QEMU_FMOD_FREQ"
#define QC_FMOD_SAMPLES "QEMU_FMOD_SAMPLES"
#define QC_FMOD_CHANNELS "QEMU_FMOD_CHANNELS"
#define QC_FMOD_BUFSIZE "QEMU_FMOD_BUFSIZE"
#define QC_FMOD_THRESHOLD "QEMU_FMOD_THRESHOLD"
static struct {
int nb_samples;
int freq;
int nb_channels;
int bufsize;
int threshold;
} conf = {
2048,
44100,
1,
0,
128
};
#define errstr() FMOD_ErrorString (FSOUND_GetError ())
static int fmod_hw_write (SWVoice *sw, void *buf, int len)
{
return pcm_hw_write (sw, buf, len);
}
static void fmod_clear_sample (FMODVoice *fmd)
{
HWVoice *hw = &fmd->hw;
int status;
void *p1 = 0, *p2 = 0;
unsigned int len1 = 0, len2 = 0;
status = FSOUND_Sample_Lock (
fmd->fmod_sample,
0,
hw->samples << hw->shift,
&p1,
&p2,
&len1,
&len2
);
if (!status) {
dolog ("Failed to lock sample\nReason: %s\n", errstr ());
return;
}
if ((len1 & hw->align) || (len2 & hw->align)) {
dolog ("Locking sample returned unaligned length %d, %d\n",
len1, len2);
goto fail;
}
if (len1 + len2 != hw->samples << hw->shift) {
dolog ("Locking sample returned incomplete length %d, %d\n",
len1 + len2, hw->samples << hw->shift);
goto fail;
}
pcm_hw_clear (hw, p1, hw->samples);
fail:
status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, len1, len2);
if (!status) {
dolog ("Failed to unlock sample\nReason: %s\n", errstr ());
}
}
static int fmod_write_sample (HWVoice *hw, uint8_t *dst, st_sample_t *src,
int src_size, int src_pos, int dst_len)
{
int src_len1 = dst_len, src_len2 = 0, pos = src_pos + dst_len;
st_sample_t *src1 = src + src_pos, *src2 = 0;
if (src_pos + dst_len > src_size) {
src_len1 = src_size - src_pos;
src2 = src;
src_len2 = dst_len - src_len1;
pos = src_len2;
}
if (src_len1) {
hw->clip (dst, src1, src_len1);
memset (src1, 0, src_len1 * sizeof (st_sample_t));
advance (dst, src_len1);
}
if (src_len2) {
hw->clip (dst, src2, src_len2);
memset (src2, 0, src_len2 * sizeof (st_sample_t));
}
return pos;
}
static int fmod_unlock_sample (FMODVoice *fmd, void *p1, void *p2,
unsigned int blen1, unsigned int blen2)
{
int status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, blen1, blen2);
if (!status) {
dolog ("Failed to unlock sample\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int fmod_lock_sample (FMODVoice *fmd, int pos, int len,
void **p1, void **p2,
unsigned int *blen1, unsigned int *blen2)
{
HWVoice *hw = &fmd->hw;
int status;
status = FSOUND_Sample_Lock (
fmd->fmod_sample,
pos << hw->shift,
len << hw->shift,
p1,
p2,
blen1,
blen2
);
if (!status) {
dolog ("Failed to lock sample\nReason: %s\n", errstr ());
return -1;
}
if ((*blen1 & hw->align) || (*blen2 & hw->align)) {
dolog ("Locking sample returned unaligned length %d, %d\n",
*blen1, *blen2);
fmod_unlock_sample (fmd, *p1, *p2, *blen1, *blen2);
return -1;
}
return 0;
}
static void fmod_hw_run (HWVoice *hw)
{
FMODVoice *fmd = (FMODVoice *) hw;
int rpos, live, decr;
void *p1 = 0, *p2 = 0;
unsigned int blen1 = 0, blen2 = 0;
unsigned int len1 = 0, len2 = 0;
int nb_active;
live = pcm_hw_get_live2 (hw, &nb_active);
if (live <= 0) {
return;
}
if (!hw->pending_disable
&& nb_active
&& conf.threshold
&& live <= conf.threshold) {
ldebug ("live=%d nb_active=%d\n", live, nb_active);
return;
}
decr = live;
#if 1
if (fmd->channel >= 0) {
int pos2 = (fmd->old_pos + decr) % hw->samples;
int pos = FSOUND_GetCurrentPosition (fmd->channel);
if (fmd->old_pos < pos && pos2 >= pos) {
decr = pos - fmd->old_pos - (pos2 == pos) - 1;
}
else if (fmd->old_pos > pos && pos2 >= pos && pos2 < fmd->old_pos) {
decr = (hw->samples - fmd->old_pos) + pos - (pos2 == pos) - 1;
}
/* ldebug ("pos=%d pos2=%d old=%d live=%d decr=%d\n", */
/* pos, pos2, fmd->old_pos, live, decr); */
}
#endif
if (decr <= 0) {
return;
}
if (fmod_lock_sample (fmd, fmd->old_pos, decr, &p1, &p2, &blen1, &blen2)) {
return;
}
len1 = blen1 >> hw->shift;
len2 = blen2 >> hw->shift;
ldebug ("%p %p %d %d %d %d\n", p1, p2, len1, len2, blen1, blen2);
decr = len1 + len2;
rpos = hw->rpos;
if (len1) {
rpos = fmod_write_sample (hw, p1, hw->mix_buf, hw->samples, rpos, len1);
}
if (len2) {
rpos = fmod_write_sample (hw, p2, hw->mix_buf, hw->samples, rpos, len2);
}
fmod_unlock_sample (fmd, p1, p2, blen1, blen2);
pcm_hw_dec_live (hw, decr);
hw->rpos = rpos % hw->samples;
fmd->old_pos = (fmd->old_pos + decr) % hw->samples;
}
static int AUD_to_fmodfmt (audfmt_e fmt, int stereo)
{
int mode = FSOUND_LOOP_NORMAL;
switch (fmt) {
case AUD_FMT_S8:
mode |= FSOUND_SIGNED | FSOUND_8BITS;
break;
case AUD_FMT_U8:
mode |= FSOUND_UNSIGNED | FSOUND_8BITS;
break;
case AUD_FMT_S16:
mode |= FSOUND_SIGNED | FSOUND_16BITS;
break;
case AUD_FMT_U16:
mode |= FSOUND_UNSIGNED | FSOUND_16BITS;
break;
default:
dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
exit (EXIT_FAILURE);
}
mode |= stereo ? FSOUND_STEREO : FSOUND_MONO;
return mode;
}
static void fmod_hw_fini (HWVoice *hw)
{
FMODVoice *fmd = (FMODVoice *) hw;
if (fmd->fmod_sample) {
FSOUND_Sample_Free (fmd->fmod_sample);
fmd->fmod_sample = 0;
if (fmd->channel >= 0) {
FSOUND_StopSound (fmd->channel);
}
}
}
static int fmod_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
int bits16, mode, channel;
FMODVoice *fmd = (FMODVoice *) hw;
mode = AUD_to_fmodfmt (fmt, nchannels == 2 ? 1 : 0);
fmd->fmod_sample = FSOUND_Sample_Alloc (
FSOUND_FREE, /* index */
conf.nb_samples, /* length */
mode, /* mode */
freq, /* freq */
255, /* volume */
128, /* pan */
255 /* priority */
);
if (!fmd->fmod_sample) {
dolog ("Failed to allocate FMOD sample\nReason: %s\n", errstr ());
return -1;
}
channel = FSOUND_PlaySoundEx (FSOUND_FREE, fmd->fmod_sample, 0, 1);
if (channel < 0) {
dolog ("Failed to start playing sound\nReason: %s\n", errstr ());
FSOUND_Sample_Free (fmd->fmod_sample);
return -1;
}
fmd->channel = channel;
hw->freq = freq;
hw->fmt = fmt;
hw->nchannels = nchannels;
bits16 = fmt == AUD_FMT_U16 || fmt == AUD_FMT_S16;
hw->bufsize = conf.nb_samples << (nchannels == 2) << bits16;
return 0;
}
static int fmod_hw_ctl (HWVoice *hw, int cmd, ...)
{
int status;
FMODVoice *fmd = (FMODVoice *) hw;
switch (cmd) {
case VOICE_ENABLE:
fmod_clear_sample (fmd);
status = FSOUND_SetPaused (fmd->channel, 0);
if (!status) {
dolog ("Failed to resume channel %d\nReason: %s\n",
fmd->channel, errstr ());
}
break;
case VOICE_DISABLE:
status = FSOUND_SetPaused (fmd->channel, 1);
if (!status) {
dolog ("Failed to pause channel %d\nReason: %s\n",
fmd->channel, errstr ());
}
break;
}
return 0;
}
static struct {
const char *name;
int type;
} drvtab[] = {
{"none", FSOUND_OUTPUT_NOSOUND},
#ifdef _WIN32
{"winmm", FSOUND_OUTPUT_WINMM},
{"dsound", FSOUND_OUTPUT_DSOUND},
{"a3d", FSOUND_OUTPUT_A3D},
{"asio", FSOUND_OUTPUT_ASIO},
#endif
#ifdef __linux__
{"oss", FSOUND_OUTPUT_OSS},
{"alsa", FSOUND_OUTPUT_ALSA},
{"esd", FSOUND_OUTPUT_ESD},
#endif
#ifdef __APPLE__
{"mac", FSOUND_OUTPUT_MAC},
#endif
#if 0
{"xbox", FSOUND_OUTPUT_XBOX},
{"ps2", FSOUND_OUTPUT_PS2},
{"gcube", FSOUND_OUTPUT_GC},
#endif
{"nort", FSOUND_OUTPUT_NOSOUND_NONREALTIME}
};
static void *fmod_audio_init (void)
{
int i;
double ver;
int status;
int output_type = -1;
const char *drv = audio_get_conf_str (QC_FMOD_DRV, NULL);
ver = FSOUND_GetVersion ();
if (ver < FMOD_VERSION) {
dolog ("Wrong FMOD version %f, need at least %f\n", ver, FMOD_VERSION);
return NULL;
}
if (drv) {
int found = 0;
for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
if (!strcmp (drv, drvtab[i].name)) {
output_type = drvtab[i].type;
found = 1;
break;
}
}
if (!found) {
dolog ("Unknown FMOD output driver `%s'\n", drv);
}
}
if (output_type != -1) {
status = FSOUND_SetOutput (output_type);
if (!status) {
dolog ("FSOUND_SetOutput(%d) failed\nReason: %s\n",
output_type, errstr ());
return NULL;
}
}
conf.freq = audio_get_conf_int (QC_FMOD_FREQ, conf.freq);
conf.nb_samples = audio_get_conf_int (QC_FMOD_SAMPLES, conf.nb_samples);
conf.nb_channels =
audio_get_conf_int (QC_FMOD_CHANNELS,
(audio_state.nb_hw_voices > 1
? audio_state.nb_hw_voices
: conf.nb_channels));
conf.bufsize = audio_get_conf_int (QC_FMOD_BUFSIZE, conf.bufsize);
conf.threshold = audio_get_conf_int (QC_FMOD_THRESHOLD, conf.threshold);
if (conf.bufsize) {
status = FSOUND_SetBufferSize (conf.bufsize);
if (!status) {
dolog ("FSOUND_SetBufferSize (%d) failed\nReason: %s\n",
conf.bufsize, errstr ());
}
}
status = FSOUND_Init (conf.freq, conf.nb_channels, 0);
if (!status) {
dolog ("FSOUND_Init failed\nReason: %s\n", errstr ());
return NULL;
}
return &conf;
}
static void fmod_audio_fini (void *opaque)
{
FSOUND_Close ();
}
struct pcm_ops fmod_pcm_ops = {
fmod_hw_init,
fmod_hw_fini,
fmod_hw_run,
fmod_hw_write,
fmod_hw_ctl
};
struct audio_output_driver fmod_output_driver = {
"fmod",
fmod_audio_init,
fmod_audio_fini,
&fmod_pcm_ops,
1,
INT_MAX,
sizeof (FMODVoice)
};
-255
View File
@@ -1,255 +0,0 @@
/*
* QEMU Mixing engine
*
* Copyright (c) 2004 Vassili Karpov (malc)
* Copyright (c) 1998 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
//#define DEBUG_FP
#include "audio/mixeng.h"
#define IN_T int8_t
#define IN_MIN CHAR_MIN
#define IN_MAX CHAR_MAX
#define SIGNED
#include "mixeng_template.h"
#undef SIGNED
#undef IN_MAX
#undef IN_MIN
#undef IN_T
#define IN_T uint8_t
#define IN_MIN 0
#define IN_MAX UCHAR_MAX
#include "mixeng_template.h"
#undef IN_MAX
#undef IN_MIN
#undef IN_T
#define IN_T int16_t
#define IN_MIN SHRT_MIN
#define IN_MAX SHRT_MAX
#define SIGNED
#include "mixeng_template.h"
#undef SIGNED
#undef IN_MAX
#undef IN_MIN
#undef IN_T
#define IN_T uint16_t
#define IN_MIN 0
#define IN_MAX USHRT_MAX
#include "mixeng_template.h"
#undef IN_MAX
#undef IN_MIN
#undef IN_T
t_sample *mixeng_conv[2][2][2] = {
{
{
conv_uint8_t_to_mono,
conv_uint16_t_to_mono
},
{
conv_int8_t_to_mono,
conv_int16_t_to_mono
}
},
{
{
conv_uint8_t_to_stereo,
conv_uint16_t_to_stereo
},
{
conv_int8_t_to_stereo,
conv_int16_t_to_stereo
}
}
};
f_sample *mixeng_clip[2][2][2] = {
{
{
clip_uint8_t_from_mono,
clip_uint16_t_from_mono
},
{
clip_int8_t_from_mono,
clip_int16_t_from_mono
}
},
{
{
clip_uint8_t_from_stereo,
clip_uint16_t_from_stereo
},
{
clip_int8_t_from_stereo,
clip_int16_t_from_stereo
}
}
};
/*
* August 21, 1998
* Copyright 1998 Fabrice Bellard.
*
* [Rewrote completly the code of Lance Norskog And Sundry
* Contributors with a more efficient algorithm.]
*
* This source code is freely redistributable and may be used for
* any purpose. This copyright notice must be maintained.
* Lance Norskog And Sundry Contributors are not responsible for
* the consequences of using this software.
*/
/*
* Sound Tools rate change effect file.
*/
/*
* Linear Interpolation.
*
* The use of fractional increment allows us to use no buffer. It
* avoid the problems at the end of the buffer we had with the old
* method which stored a possibly big buffer of size
* lcm(in_rate,out_rate).
*
* Limited to 16 bit samples and sampling frequency <= 65535 Hz. If
* the input & output frequencies are equal, a delay of one sample is
* introduced. Limited to processing 32-bit count worth of samples.
*
* 1 << FRAC_BITS evaluating to zero in several places. Changed with
* an (unsigned long) cast to make it safe. MarkMLl 2/1/99
*/
/* Private data */
typedef struct ratestuff {
uint64_t opos;
uint64_t opos_inc;
uint32_t ipos; /* position in the input stream (integer) */
st_sample_t ilast; /* last sample in the input stream */
} *rate_t;
/*
* Prepare processing.
*/
void *st_rate_start (int inrate, int outrate)
{
rate_t rate = (rate_t) qemu_mallocz (sizeof (struct ratestuff));
if (!rate) {
exit (EXIT_FAILURE);
}
if (inrate == outrate) {
// exit (EXIT_FAILURE);
}
if (inrate >= 65535 || outrate >= 65535) {
// exit (EXIT_FAILURE);
}
rate->opos = 0;
/* increment */
rate->opos_inc = (inrate * ((int64_t) UINT_MAX)) / outrate;
rate->ipos = 0;
rate->ilast.l = 0;
rate->ilast.r = 0;
return rate;
}
/*
* Processed signed long samples from ibuf to obuf.
* Return number of samples processed.
*/
void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
int *isamp, int *osamp)
{
rate_t rate = (rate_t) opaque;
st_sample_t *istart, *iend;
st_sample_t *ostart, *oend;
st_sample_t ilast, icur, out;
int64_t t;
ilast = rate->ilast;
istart = ibuf;
iend = ibuf + *isamp;
ostart = obuf;
oend = obuf + *osamp;
if (rate->opos_inc == 1ULL << 32) {
int i, n = *isamp > *osamp ? *osamp : *isamp;
for (i = 0; i < n; i++) {
obuf[i].l += ibuf[i].r;
obuf[i].r += ibuf[i].r;
}
*isamp = n;
*osamp = n;
return;
}
while (obuf < oend) {
/* Safety catch to make sure we have input samples. */
if (ibuf >= iend)
break;
/* read as many input samples so that ipos > opos */
while (rate->ipos <= (rate->opos >> 32)) {
ilast = *ibuf++;
rate->ipos++;
/* See if we finished the input buffer yet */
if (ibuf >= iend) goto the_end;
}
icur = *ibuf;
/* interpolate */
t = rate->opos & 0xffffffff;
out.l = (ilast.l * (INT_MAX - t) + icur.l * t) / INT_MAX;
out.r = (ilast.r * (INT_MAX - t) + icur.r * t) / INT_MAX;
/* output sample & increment position */
#if 0
*obuf++ = out;
#else
obuf->l += out.l;
obuf->r += out.r;
obuf += 1;
#endif
rate->opos += rate->opos_inc;
}
the_end:
*isamp = ibuf - istart;
*osamp = obuf - ostart;
rate->ilast = ilast;
}
void st_rate_stop (void *opaque)
{
qemu_free (opaque);
}
-39
View File
@@ -1,39 +0,0 @@
/*
* QEMU Mixing engine header
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef QEMU_MIXENG_H
#define QEMU_MIXENG_H
typedef void (t_sample) (void *dst, const void *src, int samples);
typedef void (f_sample) (void *dst, const void *src, int samples);
typedef struct { int64_t l; int64_t r; } st_sample_t;
extern t_sample *mixeng_conv[2][2][2];
extern f_sample *mixeng_clip[2][2][2];
void *st_rate_start (int inrate, int outrate);
void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
int *isamp, int *osamp);
void st_rate_stop (void *opaque);
#endif /* mixeng.h */
-111
View File
@@ -1,111 +0,0 @@
/*
* QEMU Mixing engine
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/*
* Tusen tack till Mike Nordell
* dec++'ified by Dscho
*/
#ifdef SIGNED
#define HALFT IN_MAX
#define HALF IN_MAX
#else
#define HALFT ((IN_MAX)>>1)
#define HALF HALFT
#endif
static int64_t inline glue(conv_,IN_T) (IN_T v)
{
#ifdef SIGNED
return (INT_MAX*(int64_t)v)/HALF;
#else
return (INT_MAX*((int64_t)v-HALFT))/HALF;
#endif
}
static IN_T inline glue(clip_,IN_T) (int64_t v)
{
if (v >= INT_MAX)
return IN_MAX;
else if (v < -INT_MAX)
return IN_MIN;
#ifdef SIGNED
return (IN_T) (v*HALF/INT_MAX);
#else
return (IN_T) (v+INT_MAX/2)*HALF/INT_MAX;
#endif
}
static void glue(glue(conv_,IN_T),_to_stereo) (void *dst, const void *src,
int samples)
{
st_sample_t *out = (st_sample_t *) dst;
IN_T *in = (IN_T *) src;
while (samples--) {
out->l = glue(conv_,IN_T) (*in++);
out->r = glue(conv_,IN_T) (*in++);
out += 1;
}
}
static void glue(glue(conv_,IN_T),_to_mono) (void *dst, const void *src,
int samples)
{
st_sample_t *out = (st_sample_t *) dst;
IN_T *in = (IN_T *) src;
while (samples--) {
out->l = glue(conv_,IN_T) (in[0]);
out->r = out->l;
out += 1;
in += 1;
}
}
static void glue(glue(clip_,IN_T),_from_stereo) (void *dst, const void *src,
int samples)
{
st_sample_t *in = (st_sample_t *) src;
IN_T *out = (IN_T *) dst;
while (samples--) {
*out++ = glue(clip_,IN_T) (in->l);
*out++ = glue(clip_,IN_T) (in->r);
in += 1;
}
}
static void glue(glue(clip_,IN_T),_from_mono) (void *dst, const void *src,
int samples)
{
st_sample_t *in = (st_sample_t *) src;
IN_T *out = (IN_T *) dst;
while (samples--) {
*out++ = glue(clip_,IN_T) (in->l + in->r);
in += 1;
}
}
#undef HALF
#undef HALFT
-128
View File
@@ -1,128 +0,0 @@
/*
* QEMU NULL audio output driver
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "audio/audio_int.h"
typedef struct NoVoice {
HWVoice hw;
int64_t old_ticks;
} NoVoice;
#define dolog(...) AUD_log ("noaudio", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
static void no_hw_run (HWVoice *hw)
{
NoVoice *no = (NoVoice *) hw;
int rpos, live, decr, samples;
st_sample_t *src;
int64_t now = qemu_get_clock (vm_clock);
int64_t ticks = now - no->old_ticks;
int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec;
if (bytes > INT_MAX)
samples = INT_MAX >> hw->shift;
else
samples = bytes >> hw->shift;
live = pcm_hw_get_live (hw);
if (live <= 0)
return;
no->old_ticks = now;
decr = audio_MIN (live, samples);
samples = decr;
rpos = hw->rpos;
while (samples) {
int left_till_end_samples = hw->samples - rpos;
int convert_samples = audio_MIN (samples, left_till_end_samples);
src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
memset (src, 0, convert_samples * sizeof (st_sample_t));
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
}
pcm_hw_dec_live (hw, decr);
hw->rpos = rpos;
}
static int no_hw_write (SWVoice *sw, void *buf, int len)
{
return pcm_hw_write (sw, buf, len);
}
static int no_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
hw->freq = freq;
hw->nchannels = nchannels;
hw->fmt = fmt;
hw->bufsize = 4096;
return 0;
}
static void no_hw_fini (HWVoice *hw)
{
(void) hw;
}
static int no_hw_ctl (HWVoice *hw, int cmd, ...)
{
(void) hw;
(void) cmd;
return 0;
}
static void *no_audio_init (void)
{
return &no_audio_init;
}
static void no_audio_fini (void *opaque)
{
}
struct pcm_ops no_pcm_ops = {
no_hw_init,
no_hw_fini,
no_hw_run,
no_hw_write,
no_hw_ctl
};
struct audio_output_driver no_output_driver = {
"none",
no_audio_init,
no_audio_fini,
&no_pcm_ops,
1,
1,
sizeof (NoVoice)
};
-475
View File
@@ -1,475 +0,0 @@
/*
* QEMU OSS audio output driver
*
* Copyright (c) 2003-2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>
#include <assert.h>
#include "vl.h"
#include "audio/audio_int.h"
typedef struct OSSVoice {
HWVoice hw;
void *pcm_buf;
int fd;
int nfrags;
int fragsize;
int mmapped;
int old_optr;
} OSSVoice;
#define dolog(...) AUD_log ("oss", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
#define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE"
#define QC_OSS_NFRAGS "QEMU_OSS_NFRAGS"
#define QC_OSS_MMAP "QEMU_OSS_MMAP"
#define QC_OSS_DEV "QEMU_OSS_DEV"
#define errstr() strerror (errno)
static struct {
int try_mmap;
int nfrags;
int fragsize;
const char *dspname;
} conf = {
.try_mmap = 0,
.nfrags = 4,
.fragsize = 4096,
.dspname = "/dev/dsp"
};
struct oss_params {
int freq;
audfmt_e fmt;
int nchannels;
int nfrags;
int fragsize;
};
static int oss_hw_write (SWVoice *sw, void *buf, int len)
{
return pcm_hw_write (sw, buf, len);
}
static int AUD_to_ossfmt (audfmt_e fmt)
{
switch (fmt) {
case AUD_FMT_S8: return AFMT_S8;
case AUD_FMT_U8: return AFMT_U8;
case AUD_FMT_S16: return AFMT_S16_LE;
case AUD_FMT_U16: return AFMT_U16_LE;
default:
dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
exit (EXIT_FAILURE);
}
}
static int oss_to_audfmt (int fmt)
{
switch (fmt) {
case AFMT_S8: return AUD_FMT_S8;
case AFMT_U8: return AUD_FMT_U8;
case AFMT_S16_LE: return AUD_FMT_S16;
case AFMT_U16_LE: return AUD_FMT_U16;
default:
dolog ("Internal logic error: Unrecognized OSS audio format %d\n"
"Aborting\n",
fmt);
exit (EXIT_FAILURE);
}
}
#ifdef DEBUG_PCM
static void oss_dump_pcm_info (struct oss_params *req, struct oss_params *obt)
{
dolog ("parameter | requested value | obtained value\n");
dolog ("format | %10d | %10d\n", req->fmt, obt->fmt);
dolog ("channels | %10d | %10d\n", req->nchannels, obt->nchannels);
dolog ("frequency | %10d | %10d\n", req->freq, obt->freq);
dolog ("nfrags | %10d | %10d\n", req->nfrags, obt->nfrags);
dolog ("fragsize | %10d | %10d\n", req->fragsize, obt->fragsize);
}
#endif
static int oss_open (struct oss_params *req, struct oss_params *obt, int *pfd)
{
int fd;
int mmmmssss;
audio_buf_info abinfo;
int fmt, freq, nchannels;
const char *dspname = conf.dspname;
fd = open (dspname, O_WRONLY | O_NONBLOCK);
if (-1 == fd) {
dolog ("Could not initialize audio hardware. Failed to open `%s':\n"
"Reason:%s\n",
dspname,
errstr ());
return -1;
}
freq = req->freq;
nchannels = req->nchannels;
fmt = req->fmt;
if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
dolog ("Could not initialize audio hardware\n"
"Failed to set sample size\n"
"Reason: %s\n",
errstr ());
goto err;
}
if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) {
dolog ("Could not initialize audio hardware\n"
"Failed to set number of channels\n"
"Reason: %s\n",
errstr ());
goto err;
}
if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) {
dolog ("Could not initialize audio hardware\n"
"Failed to set frequency\n"
"Reason: %s\n",
errstr ());
goto err;
}
if (ioctl (fd, SNDCTL_DSP_NONBLOCK)) {
dolog ("Could not initialize audio hardware\n"
"Failed to set non-blocking mode\n"
"Reason: %s\n",
errstr ());
goto err;
}
mmmmssss = (req->nfrags << 16) | lsbindex (req->fragsize);
if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
dolog ("Could not initialize audio hardware\n"
"Failed to set buffer length (%d, %d)\n"
"Reason:%s\n",
conf.nfrags, conf.fragsize,
errstr ());
goto err;
}
if (ioctl (fd, SNDCTL_DSP_GETOSPACE, &abinfo)) {
dolog ("Could not initialize audio hardware\n"
"Failed to get buffer length\n"
"Reason:%s\n",
errstr ());
goto err;
}
obt->fmt = fmt;
obt->nchannels = nchannels;
obt->freq = freq;
obt->nfrags = abinfo.fragstotal;
obt->fragsize = abinfo.fragsize;
*pfd = fd;
if ((req->fmt != obt->fmt) ||
(req->nchannels != obt->nchannels) ||
(req->freq != obt->freq) ||
(req->fragsize != obt->fragsize) ||
(req->nfrags != obt->nfrags)) {
#ifdef DEBUG_PCM
dolog ("Audio parameters mismatch\n");
oss_dump_pcm_info (req, obt);
#endif
}
#ifdef DEBUG_PCM
oss_dump_pcm_info (req, obt);
#endif
return 0;
err:
close (fd);
return -1;
}
static void oss_hw_run (HWVoice *hw)
{
OSSVoice *oss = (OSSVoice *) hw;
int err, rpos, live, decr;
int samples;
uint8_t *dst;
st_sample_t *src;
struct audio_buf_info abinfo;
struct count_info cntinfo;
live = pcm_hw_get_live (hw);
if (live <= 0)
return;
if (oss->mmapped) {
int bytes;
err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
if (err < 0) {
dolog ("SNDCTL_DSP_GETOPTR failed\nReason: %s\n", errstr ());
return;
}
if (cntinfo.ptr == oss->old_optr) {
if (abs (hw->samples - live) < 64)
dolog ("overrun\n");
return;
}
if (cntinfo.ptr > oss->old_optr) {
bytes = cntinfo.ptr - oss->old_optr;
}
else {
bytes = hw->bufsize + cntinfo.ptr - oss->old_optr;
}
decr = audio_MIN (bytes >> hw->shift, live);
}
else {
err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
if (err < 0) {
dolog ("SNDCTL_DSP_GETOSPACE failed\nReason: %s\n", errstr ());
return;
}
decr = audio_MIN (abinfo.bytes >> hw->shift, live);
if (decr <= 0)
return;
}
samples = decr;
rpos = hw->rpos;
while (samples) {
int left_till_end_samples = hw->samples - rpos;
int convert_samples = audio_MIN (samples, left_till_end_samples);
src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
dst = advance (oss->pcm_buf, rpos << hw->shift);
hw->clip (dst, src, convert_samples);
if (!oss->mmapped) {
int written;
written = write (oss->fd, dst, convert_samples << hw->shift);
/* XXX: follow errno recommendations ? */
if (written == -1) {
dolog ("Failed to write audio\nReason: %s\n", errstr ());
continue;
}
if (written != convert_samples << hw->shift) {
int wsamples = written >> hw->shift;
int wbytes = wsamples << hw->shift;
if (wbytes != written) {
dolog ("Unaligned write %d, %d\n", wbytes, written);
}
memset (src, 0, wbytes);
decr -= samples;
rpos = (rpos + wsamples) % hw->samples;
break;
}
}
memset (src, 0, convert_samples * sizeof (st_sample_t));
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
}
if (oss->mmapped) {
oss->old_optr = cntinfo.ptr;
}
pcm_hw_dec_live (hw, decr);
hw->rpos = rpos;
}
static void oss_hw_fini (HWVoice *hw)
{
int err;
OSSVoice *oss = (OSSVoice *) hw;
ldebug ("oss_hw_fini\n");
err = close (oss->fd);
if (err) {
dolog ("Failed to close OSS descriptor\nReason: %s\n", errstr ());
}
oss->fd = -1;
if (oss->pcm_buf) {
if (oss->mmapped) {
err = munmap (oss->pcm_buf, hw->bufsize);
if (err) {
dolog ("Failed to unmap OSS buffer\nReason: %s\n",
errstr ());
}
}
else {
qemu_free (oss->pcm_buf);
}
oss->pcm_buf = NULL;
}
}
static int oss_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
OSSVoice *oss = (OSSVoice *) hw;
struct oss_params req, obt;
assert (!oss->fd);
req.fmt = AUD_to_ossfmt (fmt);
req.freq = freq;
req.nchannels = nchannels;
req.fragsize = conf.fragsize;
req.nfrags = conf.nfrags;
if (oss_open (&req, &obt, &oss->fd))
return -1;
hw->freq = obt.freq;
hw->fmt = oss_to_audfmt (obt.fmt);
hw->nchannels = obt.nchannels;
oss->nfrags = obt.nfrags;
oss->fragsize = obt.fragsize;
hw->bufsize = obt.nfrags * obt.fragsize;
oss->mmapped = 0;
if (conf.try_mmap) {
oss->pcm_buf = mmap (0, hw->bufsize, PROT_READ | PROT_WRITE,
MAP_SHARED, oss->fd, 0);
if (oss->pcm_buf == MAP_FAILED) {
dolog ("Failed to mmap OSS device\nReason: %s\n",
errstr ());
} else {
int err;
int trig = 0;
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n",
errstr ());
}
else {
trig = PCM_ENABLE_OUTPUT;
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
"Reason: %s\n", errstr ());
}
else {
oss->mmapped = 1;
}
}
if (!oss->mmapped) {
err = munmap (oss->pcm_buf, hw->bufsize);
if (err) {
dolog ("Failed to unmap OSS device\nReason: %s\n",
errstr ());
}
}
}
}
if (!oss->mmapped) {
oss->pcm_buf = qemu_mallocz (hw->bufsize);
if (!oss->pcm_buf) {
close (oss->fd);
oss->fd = -1;
return -1;
}
}
return 0;
}
static int oss_hw_ctl (HWVoice *hw, int cmd, ...)
{
int trig;
OSSVoice *oss = (OSSVoice *) hw;
if (!oss->mmapped)
return 0;
switch (cmd) {
case VOICE_ENABLE:
ldebug ("enabling voice\n");
pcm_hw_clear (hw, oss->pcm_buf, hw->samples);
trig = PCM_ENABLE_OUTPUT;
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
"Reason: %s\n", errstr ());
return -1;
}
break;
case VOICE_DISABLE:
ldebug ("disabling voice\n");
trig = 0;
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n",
errstr ());
return -1;
}
break;
}
return 0;
}
static void *oss_audio_init (void)
{
conf.fragsize = audio_get_conf_int (QC_OSS_FRAGSIZE, conf.fragsize);
conf.nfrags = audio_get_conf_int (QC_OSS_NFRAGS, conf.nfrags);
conf.try_mmap = audio_get_conf_int (QC_OSS_MMAP, conf.try_mmap);
conf.dspname = audio_get_conf_str (QC_OSS_DEV, conf.dspname);
return &conf;
}
static void oss_audio_fini (void *opaque)
{
}
struct pcm_ops oss_pcm_ops = {
oss_hw_init,
oss_hw_fini,
oss_hw_run,
oss_hw_write,
oss_hw_ctl
};
struct audio_output_driver oss_output_driver = {
"oss",
oss_audio_init,
oss_audio_fini,
&oss_pcm_ops,
1,
INT_MAX,
sizeof (OSSVoice)
};
-332
View File
@@ -1,332 +0,0 @@
/*
* QEMU SDL audio output driver
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <SDL.h>
#include <SDL_thread.h>
#include "vl.h"
#include "audio/audio_int.h"
typedef struct SDLVoice {
HWVoice hw;
} SDLVoice;
#define dolog(...) AUD_log ("sdl", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
#define QC_SDL_SAMPLES "QEMU_SDL_SAMPLES"
#define errstr() SDL_GetError ()
static struct {
int nb_samples;
} conf = {
1024
};
struct SDLAudioState {
int exit;
SDL_mutex *mutex;
SDL_sem *sem;
int initialized;
} glob_sdl;
typedef struct SDLAudioState SDLAudioState;
static void sdl_hw_run (HWVoice *hw)
{
(void) hw;
}
static int sdl_lock (SDLAudioState *s)
{
if (SDL_LockMutex (s->mutex)) {
dolog ("SDL_LockMutex failed\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int sdl_unlock (SDLAudioState *s)
{
if (SDL_UnlockMutex (s->mutex)) {
dolog ("SDL_UnlockMutex failed\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int sdl_post (SDLAudioState *s)
{
if (SDL_SemPost (s->sem)) {
dolog ("SDL_SemPost failed\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int sdl_wait (SDLAudioState *s)
{
if (SDL_SemWait (s->sem)) {
dolog ("SDL_SemWait failed\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int sdl_unlock_and_post (SDLAudioState *s)
{
if (sdl_unlock (s))
return -1;
return sdl_post (s);
}
static int sdl_hw_write (SWVoice *sw, void *buf, int len)
{
int ret;
SDLAudioState *s = &glob_sdl;
sdl_lock (s);
ret = pcm_hw_write (sw, buf, len);
sdl_unlock_and_post (s);
return ret;
}
static int AUD_to_sdlfmt (audfmt_e fmt, int *shift)
{
*shift = 0;
switch (fmt) {
case AUD_FMT_S8: return AUDIO_S8;
case AUD_FMT_U8: return AUDIO_U8;
case AUD_FMT_S16: *shift = 1; return AUDIO_S16LSB;
case AUD_FMT_U16: *shift = 1; return AUDIO_U16LSB;
default:
dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
exit (EXIT_FAILURE);
}
}
static int sdl_to_audfmt (int fmt)
{
switch (fmt) {
case AUDIO_S8: return AUD_FMT_S8;
case AUDIO_U8: return AUD_FMT_U8;
case AUDIO_S16LSB: return AUD_FMT_S16;
case AUDIO_U16LSB: return AUD_FMT_U16;
default:
dolog ("Internal logic error: Unrecognized SDL audio format %d\n"
"Aborting\n", fmt);
exit (EXIT_FAILURE);
}
}
static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
{
int status;
status = SDL_OpenAudio (req, obt);
if (status) {
dolog ("SDL_OpenAudio failed\nReason: %s\n", errstr ());
}
return status;
}
static void sdl_close (SDLAudioState *s)
{
if (s->initialized) {
sdl_lock (s);
s->exit = 1;
sdl_unlock_and_post (s);
SDL_PauseAudio (1);
SDL_CloseAudio ();
s->initialized = 0;
}
}
static void sdl_callback (void *opaque, Uint8 *buf, int len)
{
SDLVoice *sdl = opaque;
SDLAudioState *s = &glob_sdl;
HWVoice *hw = &sdl->hw;
int samples = len >> hw->shift;
if (s->exit) {
return;
}
while (samples) {
int to_mix, live, decr;
/* dolog ("in callback samples=%d\n", samples); */
sdl_wait (s);
if (s->exit) {
return;
}
sdl_lock (s);
live = pcm_hw_get_live (hw);
if (live <= 0)
goto again;
/* dolog ("in callback live=%d\n", live); */
to_mix = audio_MIN (samples, live);
decr = to_mix;
while (to_mix) {
int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);
st_sample_t *src = hw->mix_buf + hw->rpos;
/* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
hw->clip (buf, src, chunk);
memset (src, 0, chunk * sizeof (st_sample_t));
hw->rpos = (hw->rpos + chunk) % hw->samples;
to_mix -= chunk;
buf += chunk << hw->shift;
}
samples -= decr;
pcm_hw_dec_live (hw, decr);
again:
sdl_unlock (s);
}
/* dolog ("done len=%d\n", len); */
}
static void sdl_hw_fini (HWVoice *hw)
{
ldebug ("sdl_hw_fini %d fixed=%d\n",
glob_sdl.initialized, audio_state.fixed_format);
sdl_close (&glob_sdl);
}
static int sdl_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
SDLVoice *sdl = (SDLVoice *) hw;
SDLAudioState *s = &glob_sdl;
SDL_AudioSpec req, obt;
int shift;
ldebug ("sdl_hw_init %d freq=%d fixed=%d\n",
s->initialized, freq, audio_state.fixed_format);
if (nchannels != 2) {
dolog ("Bogus channel count %d\n", nchannels);
return -1;
}
req.freq = freq;
req.format = AUD_to_sdlfmt (fmt, &shift);
req.channels = nchannels;
req.samples = conf.nb_samples;
shift <<= nchannels == 2;
req.callback = sdl_callback;
req.userdata = sdl;
if (sdl_open (&req, &obt))
return -1;
hw->freq = obt.freq;
hw->fmt = sdl_to_audfmt (obt.format);
hw->nchannels = obt.channels;
hw->bufsize = obt.samples << shift;
s->initialized = 1;
s->exit = 0;
SDL_PauseAudio (0);
return 0;
}
static int sdl_hw_ctl (HWVoice *hw, int cmd, ...)
{
(void) hw;
switch (cmd) {
case VOICE_ENABLE:
SDL_PauseAudio (0);
break;
case VOICE_DISABLE:
SDL_PauseAudio (1);
break;
}
return 0;
}
static void *sdl_audio_init (void)
{
SDLAudioState *s = &glob_sdl;
conf.nb_samples = audio_get_conf_int (QC_SDL_SAMPLES, conf.nb_samples);
if (SDL_InitSubSystem (SDL_INIT_AUDIO)) {
dolog ("SDL failed to initialize audio subsystem\nReason: %s\n",
errstr ());
return NULL;
}
s->mutex = SDL_CreateMutex ();
if (!s->mutex) {
dolog ("Failed to create SDL mutex\nReason: %s\n", errstr ());
SDL_QuitSubSystem (SDL_INIT_AUDIO);
return NULL;
}
s->sem = SDL_CreateSemaphore (0);
if (!s->sem) {
dolog ("Failed to create SDL semaphore\nReason: %s\n", errstr ());
SDL_DestroyMutex (s->mutex);
SDL_QuitSubSystem (SDL_INIT_AUDIO);
return NULL;
}
return s;
}
static void sdl_audio_fini (void *opaque)
{
SDLAudioState *s = opaque;
sdl_close (s);
SDL_DestroySemaphore (s->sem);
SDL_DestroyMutex (s->mutex);
SDL_QuitSubSystem (SDL_INIT_AUDIO);
}
struct pcm_ops sdl_pcm_ops = {
sdl_hw_init,
sdl_hw_fini,
sdl_hw_run,
sdl_hw_write,
sdl_hw_ctl
};
struct audio_output_driver sdl_output_driver = {
"sdl",
sdl_audio_init,
sdl_audio_fini,
&sdl_pcm_ops,
1,
1,
sizeof (SDLVoice)
};
-217
View File
@@ -1,217 +0,0 @@
/*
* QEMU WAV audio output driver
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "audio/audio_int.h"
typedef struct WAVVoice {
HWVoice hw;
QEMUFile *f;
int64_t old_ticks;
void *pcm_buf;
int total_samples;
} WAVVoice;
#define dolog(...) AUD_log ("wav", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
static struct {
const char *wav_path;
} conf = {
.wav_path = "qemu.wav"
};
static void wav_hw_run (HWVoice *hw)
{
WAVVoice *wav = (WAVVoice *) hw;
int rpos, live, decr, samples;
uint8_t *dst;
st_sample_t *src;
int64_t now = qemu_get_clock (vm_clock);
int64_t ticks = now - wav->old_ticks;
int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec;
if (bytes > INT_MAX)
samples = INT_MAX >> hw->shift;
else
samples = bytes >> hw->shift;
live = pcm_hw_get_live (hw);
if (live <= 0)
return;
wav->old_ticks = now;
decr = audio_MIN (live, samples);
samples = decr;
rpos = hw->rpos;
while (samples) {
int left_till_end_samples = hw->samples - rpos;
int convert_samples = audio_MIN (samples, left_till_end_samples);
src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
dst = advance (wav->pcm_buf, rpos << hw->shift);
hw->clip (dst, src, convert_samples);
qemu_put_buffer (wav->f, dst, convert_samples << hw->shift);
memset (src, 0, convert_samples * sizeof (st_sample_t));
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
wav->total_samples += convert_samples;
}
pcm_hw_dec_live (hw, decr);
hw->rpos = rpos;
}
static int wav_hw_write (SWVoice *sw, void *buf, int len)
{
return pcm_hw_write (sw, buf, len);
}
/* VICE code: Store number as little endian. */
static void le_store (uint8_t *buf, uint32_t val, int len)
{
int i;
for (i = 0; i < len; i++) {
buf[i] = (uint8_t) (val & 0xff);
val >>= 8;
}
}
static int wav_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
WAVVoice *wav = (WAVVoice *) hw;
int bits16 = 0, stereo = audio_state.fixed_channels == 2;
uint8_t hdr[] = {
0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
};
switch (audio_state.fixed_fmt) {
case AUD_FMT_S8:
case AUD_FMT_U8:
break;
case AUD_FMT_S16:
case AUD_FMT_U16:
bits16 = 1;
break;
}
hdr[34] = bits16 ? 0x10 : 0x08;
hw->freq = 44100;
hw->nchannels = stereo ? 2 : 1;
hw->fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
hw->bufsize = 4096;
wav->pcm_buf = qemu_mallocz (hw->bufsize);
if (!wav->pcm_buf)
return -1;
le_store (hdr + 22, hw->nchannels, 2);
le_store (hdr + 24, hw->freq, 4);
le_store (hdr + 28, hw->freq << (bits16 + stereo), 4);
le_store (hdr + 32, 1 << (bits16 + stereo), 2);
wav->f = fopen (conf.wav_path, "wb");
if (!wav->f) {
dolog ("failed to open wave file `%s'\nReason: %s\n",
conf.wav_path, strerror (errno));
qemu_free (wav->pcm_buf);
wav->pcm_buf = NULL;
return -1;
}
qemu_put_buffer (wav->f, hdr, sizeof (hdr));
return 0;
}
static void wav_hw_fini (HWVoice *hw)
{
WAVVoice *wav = (WAVVoice *) hw;
int stereo = hw->nchannels == 2;
uint8_t rlen[4];
uint8_t dlen[4];
uint32_t rifflen = (wav->total_samples << stereo) + 36;
uint32_t datalen = wav->total_samples << stereo;
if (!wav->f || !hw->active)
return;
le_store (rlen, rifflen, 4);
le_store (dlen, datalen, 4);
qemu_fseek (wav->f, 4, SEEK_SET);
qemu_put_buffer (wav->f, rlen, 4);
qemu_fseek (wav->f, 32, SEEK_CUR);
qemu_put_buffer (wav->f, dlen, 4);
fclose (wav->f);
wav->f = NULL;
qemu_free (wav->pcm_buf);
wav->pcm_buf = NULL;
}
static int wav_hw_ctl (HWVoice *hw, int cmd, ...)
{
(void) hw;
(void) cmd;
return 0;
}
static void *wav_audio_init (void)
{
return &conf;
}
static void wav_audio_fini (void *opaque)
{
ldebug ("wav_fini");
}
struct pcm_ops wav_pcm_ops = {
wav_hw_init,
wav_hw_fini,
wav_hw_run,
wav_hw_write,
wav_hw_ctl
};
struct audio_output_driver wav_output_driver = {
"wav",
wav_audio_init,
wav_audio_fini,
&wav_pcm_ops,
1,
1,
sizeof (WAVVoice)
};
-224
View File
@@ -1,224 +0,0 @@
/*
* Block driver for the various disk image formats used by Bochs
* Currently only for "growing" type in read-only mode
*
* Copyright (c) 2005 Alex Beregszaszi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "block_int.h"
/**************************************************************/
#define HEADER_MAGIC "Bochs Virtual HD Image"
#define HEADER_VERSION 0x00010000
#define HEADER_SIZE 512
#define REDOLOG_TYPE "Redolog"
#define GROWING_TYPE "Growing"
// not allocated: 0xffffffff
// always little-endian
struct bochs_header {
char magic[32]; // "Bochs Virtual HD Image"
char type[16]; // "Redolog"
char subtype[16]; // "Undoable" / "Volatile" / "Growing"
uint32_t version;
uint32_t header; // size of header
union {
struct {
uint32_t catalog; // num of entries
uint32_t bitmap; // bitmap size
uint32_t extent; // extent size
uint64_t disk; // disk size
char padding[HEADER_SIZE - 64 - 8 - 20];
} redolog;
char padding[HEADER_SIZE - 64 - 8];
} extra;
};
typedef struct BDRVBochsState {
int fd;
uint32_t *catalog_bitmap;
int catalog_size;
int data_offset;
int bitmap_blocks;
int extent_blocks;
int extent_size;
} BDRVBochsState;
static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
{
const struct bochs_header *bochs = (const void *)buf;
if (buf_size < HEADER_SIZE)
return 0;
if (!strcmp(bochs->magic, HEADER_MAGIC) &&
!strcmp(bochs->type, REDOLOG_TYPE) &&
!strcmp(bochs->subtype, GROWING_TYPE) &&
(le32_to_cpu(bochs->version) == HEADER_VERSION))
return 100;
return 0;
}
static int bochs_open(BlockDriverState *bs, const char *filename)
{
BDRVBochsState *s = bs->opaque;
int fd, i;
struct bochs_header bochs;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
}
bs->read_only = 1; // no write support yet
s->fd = fd;
if (read(fd, &bochs, sizeof(bochs)) != sizeof(bochs)) {
goto fail;
}
if (strcmp(bochs.magic, HEADER_MAGIC) ||
strcmp(bochs.type, REDOLOG_TYPE) ||
strcmp(bochs.subtype, GROWING_TYPE) ||
(le32_to_cpu(bochs.version) != HEADER_VERSION)) {
goto fail;
}
bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
lseek(s->fd, le32_to_cpu(bochs.header), SEEK_SET);
s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog);
s->catalog_bitmap = qemu_malloc(s->catalog_size * 4);
if (!s->catalog_bitmap)
goto fail;
if (read(s->fd, s->catalog_bitmap, s->catalog_size * 4) !=
s->catalog_size * 4)
goto fail;
for (i = 0; i < s->catalog_size; i++)
le32_to_cpus(&s->catalog_bitmap[i]);
s->data_offset = le32_to_cpu(bochs.header) + (s->catalog_size * 4);
s->bitmap_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.bitmap) - 1) / 512;
s->extent_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.extent) - 1) / 512;
s->extent_size = le32_to_cpu(bochs.extra.redolog.extent);
return 0;
fail:
close(fd);
return -1;
}
static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
{
BDRVBochsState *s = bs->opaque;
int64_t offset = sector_num * 512;
int64_t extent_index, extent_offset, bitmap_offset, block_offset;
char bitmap_entry;
// seek to sector
extent_index = offset / s->extent_size;
extent_offset = (offset % s->extent_size) / 512;
if (s->catalog_bitmap[extent_index] == 0xffffffff)
{
// fprintf(stderr, "page not allocated [%x - %x:%x]\n",
// sector_num, extent_index, extent_offset);
return -1; // not allocated
}
bitmap_offset = s->data_offset + (512 * s->catalog_bitmap[extent_index] *
(s->extent_blocks + s->bitmap_blocks));
block_offset = bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
// fprintf(stderr, "sect: %x [ext i: %x o: %x] -> %x bitmap: %x block: %x\n",
// sector_num, extent_index, extent_offset,
// le32_to_cpu(s->catalog_bitmap[extent_index]),
// bitmap_offset, block_offset);
// read in bitmap for current extent
lseek(s->fd, bitmap_offset + (extent_offset / 8), SEEK_SET);
read(s->fd, &bitmap_entry, 1);
if (!((bitmap_entry >> (extent_offset % 8)) & 1))
{
// fprintf(stderr, "sector (%x) in bitmap not allocated\n",
// sector_num);
return -1; // not allocated
}
lseek(s->fd, block_offset, SEEK_SET);
return 0;
}
static int bochs_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVBochsState *s = bs->opaque;
int ret;
while (nb_sectors > 0) {
if (!seek_to_sector(bs, sector_num))
{
ret = read(s->fd, buf, 512);
if (ret != 512)
return -1;
}
else
memset(buf, 0, 512);
nb_sectors--;
sector_num++;
buf += 512;
}
return 0;
}
static void bochs_close(BlockDriverState *bs)
{
BDRVBochsState *s = bs->opaque;
qemu_free(s->catalog_bitmap);
close(s->fd);
}
BlockDriver bdrv_bochs = {
"bochs",
sizeof(BDRVBochsState),
bochs_probe,
bochs_open,
bochs_read,
NULL,
bochs_close,
};
-169
View File
@@ -1,169 +0,0 @@
/*
* QEMU Block driver for CLOOP images
*
* Copyright (c) 2004 Johannes E. Schindelin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "block_int.h"
#include <zlib.h>
typedef struct BDRVCloopState {
int fd;
uint32_t block_size;
uint32_t n_blocks;
uint64_t* offsets;
uint32_t sectors_per_block;
uint32_t current_block;
char* compressed_block;
char* uncompressed_block;
z_stream zstream;
} BDRVCloopState;
static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
{
const char* magic_version_2_0="#!/bin/sh\n"
"#V2.0 Format\n"
"modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n";
int length=strlen(magic_version_2_0);
if(length>buf_size)
length=buf_size;
if(!memcmp(magic_version_2_0,buf,length))
return 2;
return 0;
}
static int cloop_open(BlockDriverState *bs, const char *filename)
{
BDRVCloopState *s = bs->opaque;
uint32_t offsets_size,max_compressed_block_size=1,i;
s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (s->fd < 0)
return -1;
bs->read_only = 1;
/* read header */
if(lseek(s->fd,128,SEEK_SET)<0) {
cloop_close:
close(s->fd);
return -1;
}
if(read(s->fd,&s->block_size,4)<4)
goto cloop_close;
s->block_size=be32_to_cpu(s->block_size);
if(read(s->fd,&s->n_blocks,4)<4)
goto cloop_close;
s->n_blocks=be32_to_cpu(s->n_blocks);
/* read offsets */
offsets_size=s->n_blocks*sizeof(uint64_t);
if(!(s->offsets=(uint64_t*)malloc(offsets_size)))
goto cloop_close;
if(read(s->fd,s->offsets,offsets_size)<offsets_size)
goto cloop_close;
for(i=0;i<s->n_blocks;i++) {
s->offsets[i]=be64_to_cpu(s->offsets[i]);
if(i>0) {
uint32_t size=s->offsets[i]-s->offsets[i-1];
if(size>max_compressed_block_size)
max_compressed_block_size=size;
}
}
/* initialize zlib engine */
if(!(s->compressed_block=(char*)malloc(max_compressed_block_size+1)))
goto cloop_close;
if(!(s->uncompressed_block=(char*)malloc(s->block_size)))
goto cloop_close;
if(inflateInit(&s->zstream) != Z_OK)
goto cloop_close;
s->current_block=s->n_blocks;
s->sectors_per_block = s->block_size/512;
bs->total_sectors = s->n_blocks*s->sectors_per_block;
return 0;
}
static inline int cloop_read_block(BDRVCloopState *s,int block_num)
{
if(s->current_block != block_num) {
int ret;
uint32_t bytes = s->offsets[block_num+1]-s->offsets[block_num];
lseek(s->fd, s->offsets[block_num], SEEK_SET);
ret = read(s->fd, s->compressed_block, bytes);
if (ret != bytes)
return -1;
s->zstream.next_in = s->compressed_block;
s->zstream.avail_in = bytes;
s->zstream.next_out = s->uncompressed_block;
s->zstream.avail_out = s->block_size;
ret = inflateReset(&s->zstream);
if(ret != Z_OK)
return -1;
ret = inflate(&s->zstream, Z_FINISH);
if(ret != Z_STREAM_END || s->zstream.total_out != s->block_size)
return -1;
s->current_block = block_num;
}
return 0;
}
static int cloop_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVCloopState *s = bs->opaque;
int i;
for(i=0;i<nb_sectors;i++) {
uint32_t sector_offset_in_block=((sector_num+i)%s->sectors_per_block),
block_num=(sector_num+i)/s->sectors_per_block;
if(cloop_read_block(s, block_num) != 0)
return -1;
memcpy(buf+i*512,s->uncompressed_block+sector_offset_in_block*512,512);
}
return 0;
}
static void cloop_close(BlockDriverState *bs)
{
BDRVCloopState *s = bs->opaque;
close(s->fd);
if(s->n_blocks>0)
free(s->offsets);
free(s->compressed_block);
free(s->uncompressed_block);
inflateEnd(&s->zstream);
}
BlockDriver bdrv_cloop = {
"cloop",
sizeof(BDRVCloopState),
cloop_probe,
cloop_open,
cloop_read,
NULL,
cloop_close,
};
-264
View File
@@ -1,264 +0,0 @@
/*
* Block driver for the COW format
*
* Copyright (c) 2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _WIN32
#include "vl.h"
#include "block_int.h"
#include <sys/mman.h>
/**************************************************************/
/* COW block driver using file system holes */
/* user mode linux compatible COW file */
#define COW_MAGIC 0x4f4f4f4d /* MOOO */
#define COW_VERSION 2
struct cow_header_v2 {
uint32_t magic;
uint32_t version;
char backing_file[1024];
int32_t mtime;
uint64_t size;
uint32_t sectorsize;
};
typedef struct BDRVCowState {
int fd;
uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */
uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */
int cow_bitmap_size;
int64_t cow_sectors_offset;
} BDRVCowState;
static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
{
const struct cow_header_v2 *cow_header = (const void *)buf;
if (buf_size >= sizeof(struct cow_header_v2) &&
be32_to_cpu(cow_header->magic) == COW_MAGIC &&
be32_to_cpu(cow_header->version) == COW_VERSION)
return 100;
else
return 0;
}
static int cow_open(BlockDriverState *bs, const char *filename)
{
BDRVCowState *s = bs->opaque;
int fd;
struct cow_header_v2 cow_header;
int64_t size;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
}
s->fd = fd;
/* see if it is a cow image */
if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) {
goto fail;
}
if (be32_to_cpu(cow_header.magic) != COW_MAGIC ||
be32_to_cpu(cow_header.version) != COW_VERSION) {
goto fail;
}
/* cow image found */
size = be64_to_cpu(cow_header.size);
bs->total_sectors = size / 512;
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
cow_header.backing_file);
#if 0
if (cow_header.backing_file[0] != '\0') {
if (stat(cow_header.backing_file, &st) != 0) {
fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
goto fail;
}
if (st.st_mtime != be32_to_cpu(cow_header.mtime)) {
fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file);
goto fail;
}
fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE);
if (fd < 0)
goto fail;
bs->fd = fd;
}
#endif
/* mmap the bitmap */
s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size),
s->cow_bitmap_size,
PROT_READ | PROT_WRITE,
MAP_SHARED, s->fd, 0);
if (s->cow_bitmap_addr == MAP_FAILED)
goto fail;
s->cow_bitmap = s->cow_bitmap_addr + sizeof(cow_header);
s->cow_sectors_offset = (s->cow_bitmap_size + 511) & ~511;
return 0;
fail:
close(fd);
return -1;
}
static inline void cow_set_bit(uint8_t *bitmap, int64_t bitnum)
{
bitmap[bitnum / 8] |= (1 << (bitnum%8));
}
static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum)
{
return !!(bitmap[bitnum / 8] & (1 << (bitnum%8)));
}
/* Return true if first block has been changed (ie. current version is
* in COW file). Set the number of continuous blocks for which that
* is true. */
static inline int is_changed(uint8_t *bitmap,
int64_t sector_num, int nb_sectors,
int *num_same)
{
int changed;
if (!bitmap || nb_sectors == 0) {
*num_same = nb_sectors;
return 0;
}
changed = is_bit_set(bitmap, sector_num);
for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
if (is_bit_set(bitmap, sector_num + *num_same) != changed)
break;
}
return changed;
}
static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum)
{
BDRVCowState *s = bs->opaque;
return is_changed(s->cow_bitmap, sector_num, nb_sectors, pnum);
}
static int cow_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVCowState *s = bs->opaque;
int ret, n;
while (nb_sectors > 0) {
if (is_changed(s->cow_bitmap, sector_num, nb_sectors, &n)) {
lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
ret = read(s->fd, buf, n * 512);
if (ret != n * 512)
return -1;
} else {
memset(buf, 0, n * 512);
}
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
return 0;
}
static int cow_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVCowState *s = bs->opaque;
int ret, i;
lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
ret = write(s->fd, buf, nb_sectors * 512);
if (ret != nb_sectors * 512)
return -1;
for (i = 0; i < nb_sectors; i++)
cow_set_bit(s->cow_bitmap, sector_num + i);
return 0;
}
static void cow_close(BlockDriverState *bs)
{
BDRVCowState *s = bs->opaque;
munmap(s->cow_bitmap_addr, s->cow_bitmap_size);
close(s->fd);
}
static int cow_create(const char *filename, int64_t image_sectors,
const char *image_filename, int flags)
{
int fd, cow_fd;
struct cow_header_v2 cow_header;
struct stat st;
if (flags)
return -ENOTSUP;
cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
0644);
if (cow_fd < 0)
return -1;
memset(&cow_header, 0, sizeof(cow_header));
cow_header.magic = cpu_to_be32(COW_MAGIC);
cow_header.version = cpu_to_be32(COW_VERSION);
if (image_filename) {
fd = open(image_filename, O_RDONLY | O_BINARY);
if (fd < 0) {
close(cow_fd);
return -1;
}
if (fstat(fd, &st) != 0) {
close(fd);
return -1;
}
close(fd);
cow_header.mtime = cpu_to_be32(st.st_mtime);
realpath(image_filename, cow_header.backing_file);
}
cow_header.sectorsize = cpu_to_be32(512);
cow_header.size = cpu_to_be64(image_sectors * 512);
write(cow_fd, &cow_header, sizeof(cow_header));
/* resize to include at least all the bitmap */
ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3));
close(cow_fd);
return 0;
}
BlockDriver bdrv_cow = {
"cow",
sizeof(BDRVCowState),
cow_probe,
cow_open,
cow_read,
cow_write,
cow_close,
cow_create,
cow_is_allocated,
};
#endif
-297
View File
@@ -1,297 +0,0 @@
/*
* QEMU Block driver for DMG images
*
* Copyright (c) 2004 Johannes E. Schindelin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "block_int.h"
#include "bswap.h"
#include <zlib.h>
typedef struct BDRVDMGState {
int fd;
/* each chunk contains a certain number of sectors,
* offsets[i] is the offset in the .dmg file,
* lengths[i] is the length of the compressed chunk,
* sectors[i] is the sector beginning at offsets[i],
* sectorcounts[i] is the number of sectors in that chunk,
* the sectors array is ordered
* 0<=i<n_chunks */
uint32_t n_chunks;
uint32_t* types;
uint64_t* offsets;
uint64_t* lengths;
uint64_t* sectors;
uint64_t* sectorcounts;
uint32_t current_chunk;
char* compressed_chunk;
char* uncompressed_chunk;
z_stream zstream;
} BDRVDMGState;
static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename)
{
int len=strlen(filename);
if(len>4 && !strcmp(filename+len-4,".dmg"))
return 2;
return 0;
}
static off_t read_off(int fd)
{
uint64_t buffer;
if(read(fd,&buffer,8)<8)
return 0;
return be64_to_cpu(buffer);
}
static off_t read_uint32(int fd)
{
uint32_t buffer;
if(read(fd,&buffer,4)<4)
return 0;
return be32_to_cpu(buffer);
}
static int dmg_open(BlockDriverState *bs, const char *filename)
{
BDRVDMGState *s = bs->opaque;
off_t info_begin,info_end,last_in_offset,last_out_offset;
uint32_t count;
uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i;
s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (s->fd < 0)
return -1;
bs->read_only = 1;
s->n_chunks = 0;
s->offsets = s->lengths = s->sectors = s->sectorcounts = 0;
/* read offset of info blocks */
if(lseek(s->fd,-0x1d8,SEEK_END)<0) {
dmg_close:
close(s->fd);
/* open raw instead */
bs->drv=&bdrv_raw;
return bs->drv->bdrv_open(bs,filename);
}
info_begin=read_off(s->fd);
if(info_begin==0)
goto dmg_close;
if(lseek(s->fd,info_begin,SEEK_SET)<0)
goto dmg_close;
if(read_uint32(s->fd)!=0x100)
goto dmg_close;
if((count = read_uint32(s->fd))==0)
goto dmg_close;
info_end = info_begin+count;
if(lseek(s->fd,0xf8,SEEK_CUR)<0)
goto dmg_close;
/* read offsets */
last_in_offset = last_out_offset = 0;
while(lseek(s->fd,0,SEEK_CUR)<info_end) {
uint32_t type;
count = read_uint32(s->fd);
if(count==0)
goto dmg_close;
type = read_uint32(s->fd);
if(type!=0x6d697368 || count<244)
lseek(s->fd,count-4,SEEK_CUR);
else {
int new_size, chunk_count;
if(lseek(s->fd,200,SEEK_CUR)<0)
goto dmg_close;
chunk_count = (count-204)/40;
new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
s->types = realloc(s->types, new_size/2);
s->offsets = realloc(s->offsets, new_size);
s->lengths = realloc(s->lengths, new_size);
s->sectors = realloc(s->sectors, new_size);
s->sectorcounts = realloc(s->sectorcounts, new_size);
for(i=s->n_chunks;i<s->n_chunks+chunk_count;i++) {
s->types[i] = read_uint32(s->fd);
if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) {
if(s->types[i]==0xffffffff) {
last_in_offset = s->offsets[i-1]+s->lengths[i-1];
last_out_offset = s->sectors[i-1]+s->sectorcounts[i-1];
}
chunk_count--;
i--;
if(lseek(s->fd,36,SEEK_CUR)<0)
goto dmg_close;
continue;
}
read_uint32(s->fd);
s->sectors[i] = last_out_offset+read_off(s->fd);
s->sectorcounts[i] = read_off(s->fd);
s->offsets[i] = last_in_offset+read_off(s->fd);
s->lengths[i] = read_off(s->fd);
if(s->lengths[i]>max_compressed_size)
max_compressed_size = s->lengths[i];
if(s->sectorcounts[i]>max_sectors_per_chunk)
max_sectors_per_chunk = s->sectorcounts[i];
}
s->n_chunks+=chunk_count;
}
}
/* initialize zlib engine */
if(!(s->compressed_chunk=(char*)malloc(max_compressed_size+1)))
goto dmg_close;
if(!(s->uncompressed_chunk=(char*)malloc(512*max_sectors_per_chunk)))
goto dmg_close;
if(inflateInit(&s->zstream) != Z_OK)
goto dmg_close;
s->current_chunk = s->n_chunks;
return 0;
}
static inline int is_sector_in_chunk(BDRVDMGState* s,
uint32_t chunk_num,int sector_num)
{
if(chunk_num>=s->n_chunks || s->sectors[chunk_num]>sector_num ||
s->sectors[chunk_num]+s->sectorcounts[chunk_num]<=sector_num)
return 0;
else
return -1;
}
static inline uint32_t search_chunk(BDRVDMGState* s,int sector_num)
{
/* binary search */
uint32_t chunk1=0,chunk2=s->n_chunks,chunk3;
while(chunk1!=chunk2) {
chunk3 = (chunk1+chunk2)/2;
if(s->sectors[chunk3]>sector_num)
chunk2 = chunk3;
else if(s->sectors[chunk3]+s->sectorcounts[chunk3]>sector_num)
return chunk3;
else
chunk1 = chunk3;
}
return s->n_chunks; /* error */
}
static inline int dmg_read_chunk(BDRVDMGState *s,int sector_num)
{
if(!is_sector_in_chunk(s,s->current_chunk,sector_num)) {
int ret;
uint32_t chunk = search_chunk(s,sector_num);
if(chunk>=s->n_chunks)
return -1;
s->current_chunk = s->n_chunks;
switch(s->types[chunk]) {
case 0x80000005: { /* zlib compressed */
int i;
ret = lseek(s->fd, s->offsets[chunk], SEEK_SET);
if(ret<0)
return -1;
/* we need to buffer, because only the chunk as whole can be
* inflated. */
i=0;
do {
ret = read(s->fd, s->compressed_chunk+i, s->lengths[chunk]-i);
if(ret<0 && errno==EINTR)
ret=0;
i+=ret;
} while(ret>=0 && ret+i<s->lengths[chunk]);
if (ret != s->lengths[chunk])
return -1;
s->zstream.next_in = s->compressed_chunk;
s->zstream.avail_in = s->lengths[chunk];
s->zstream.next_out = s->uncompressed_chunk;
s->zstream.avail_out = 512*s->sectorcounts[chunk];
ret = inflateReset(&s->zstream);
if(ret != Z_OK)
return -1;
ret = inflate(&s->zstream, Z_FINISH);
if(ret != Z_STREAM_END || s->zstream.total_out != 512*s->sectorcounts[chunk])
return -1;
break; }
case 1: /* copy */
ret = read(s->fd, s->uncompressed_chunk, s->lengths[chunk]);
if (ret != s->lengths[chunk])
return -1;
break;
case 2: /* zero */
memset(s->uncompressed_chunk, 0, 512*s->sectorcounts[chunk]);
break;
}
s->current_chunk = chunk;
}
return 0;
}
static int dmg_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVDMGState *s = bs->opaque;
int i;
for(i=0;i<nb_sectors;i++) {
uint32_t sector_offset_in_chunk;
if(dmg_read_chunk(s, sector_num+i) != 0)
return -1;
sector_offset_in_chunk = sector_num+i-s->sectors[s->current_chunk];
memcpy(buf+i*512,s->uncompressed_chunk+sector_offset_in_chunk*512,512);
}
return 0;
}
static void dmg_close(BlockDriverState *bs)
{
BDRVDMGState *s = bs->opaque;
close(s->fd);
if(s->n_chunks>0) {
free(s->types);
free(s->offsets);
free(s->lengths);
free(s->sectors);
free(s->sectorcounts);
}
free(s->compressed_chunk);
free(s->uncompressed_chunk);
inflateEnd(&s->zstream);
}
BlockDriver bdrv_dmg = {
"dmg",
sizeof(BDRVDMGState),
dmg_probe,
dmg_open,
dmg_read,
NULL,
dmg_close,
};
-688
View File
@@ -1,688 +0,0 @@
/*
* Block driver for the QCOW format
*
* Copyright (c) 2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "block_int.h"
#include <zlib.h>
#include "aes.h"
/**************************************************************/
/* QEMU COW block driver with compression and encryption support */
#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
#define QCOW_VERSION 1
#define QCOW_CRYPT_NONE 0
#define QCOW_CRYPT_AES 1
#define QCOW_OFLAG_COMPRESSED (1LL << 63)
typedef struct QCowHeader {
uint32_t magic;
uint32_t version;
uint64_t backing_file_offset;
uint32_t backing_file_size;
uint32_t mtime;
uint64_t size; /* in bytes */
uint8_t cluster_bits;
uint8_t l2_bits;
uint32_t crypt_method;
uint64_t l1_table_offset;
} QCowHeader;
#define L2_CACHE_SIZE 16
typedef struct BDRVQcowState {
int fd;
int cluster_bits;
int cluster_size;
int cluster_sectors;
int l2_bits;
int l2_size;
int l1_size;
uint64_t cluster_offset_mask;
uint64_t l1_table_offset;
uint64_t *l1_table;
uint64_t *l2_cache;
uint64_t l2_cache_offsets[L2_CACHE_SIZE];
uint32_t l2_cache_counts[L2_CACHE_SIZE];
uint8_t *cluster_cache;
uint8_t *cluster_data;
uint64_t cluster_cache_offset;
uint32_t crypt_method; /* current crypt method, 0 if no key yet */
uint32_t crypt_method_header;
AES_KEY aes_encrypt_key;
AES_KEY aes_decrypt_key;
} BDRVQcowState;
static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset);
static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
{
const QCowHeader *cow_header = (const void *)buf;
if (buf_size >= sizeof(QCowHeader) &&
be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
be32_to_cpu(cow_header->version) == QCOW_VERSION)
return 100;
else
return 0;
}
static int qcow_open(BlockDriverState *bs, const char *filename)
{
BDRVQcowState *s = bs->opaque;
int fd, len, i, shift;
QCowHeader header;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
}
s->fd = fd;
if (read(fd, &header, sizeof(header)) != sizeof(header))
goto fail;
be32_to_cpus(&header.magic);
be32_to_cpus(&header.version);
be64_to_cpus(&header.backing_file_offset);
be32_to_cpus(&header.backing_file_size);
be32_to_cpus(&header.mtime);
be64_to_cpus(&header.size);
be32_to_cpus(&header.crypt_method);
be64_to_cpus(&header.l1_table_offset);
if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION)
goto fail;
if (header.size <= 1 || header.cluster_bits < 9)
goto fail;
if (header.crypt_method > QCOW_CRYPT_AES)
goto fail;
s->crypt_method_header = header.crypt_method;
if (s->crypt_method_header)
bs->encrypted = 1;
s->cluster_bits = header.cluster_bits;
s->cluster_size = 1 << s->cluster_bits;
s->cluster_sectors = 1 << (s->cluster_bits - 9);
s->l2_bits = header.l2_bits;
s->l2_size = 1 << s->l2_bits;
bs->total_sectors = header.size / 512;
s->cluster_offset_mask = (1LL << (63 - s->cluster_bits)) - 1;
/* read the level 1 table */
shift = s->cluster_bits + s->l2_bits;
s->l1_size = (header.size + (1LL << shift) - 1) >> shift;
s->l1_table_offset = header.l1_table_offset;
s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
if (!s->l1_table)
goto fail;
lseek(fd, s->l1_table_offset, SEEK_SET);
if (read(fd, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
s->l1_size * sizeof(uint64_t))
goto fail;
for(i = 0;i < s->l1_size; i++) {
be64_to_cpus(&s->l1_table[i]);
}
/* alloc L2 cache */
s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
if (!s->l2_cache)
goto fail;
s->cluster_cache = qemu_malloc(s->cluster_size);
if (!s->cluster_cache)
goto fail;
s->cluster_data = qemu_malloc(s->cluster_size);
if (!s->cluster_data)
goto fail;
s->cluster_cache_offset = -1;
/* read the backing file name */
if (header.backing_file_offset != 0) {
len = header.backing_file_size;
if (len > 1023)
len = 1023;
lseek(fd, header.backing_file_offset, SEEK_SET);
if (read(fd, bs->backing_file, len) != len)
goto fail;
bs->backing_file[len] = '\0';
}
return 0;
fail:
qemu_free(s->l1_table);
qemu_free(s->l2_cache);
qemu_free(s->cluster_cache);
qemu_free(s->cluster_data);
close(fd);
return -1;
}
static int qcow_set_key(BlockDriverState *bs, const char *key)
{
BDRVQcowState *s = bs->opaque;
uint8_t keybuf[16];
int len, i;
memset(keybuf, 0, 16);
len = strlen(key);
if (len > 16)
len = 16;
/* XXX: we could compress the chars to 7 bits to increase
entropy */
for(i = 0;i < len;i++) {
keybuf[i] = key[i];
}
s->crypt_method = s->crypt_method_header;
if (AES_set_encrypt_key(keybuf, 128, &s->aes_encrypt_key) != 0)
return -1;
if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0)
return -1;
#if 0
/* test */
{
uint8_t in[16];
uint8_t out[16];
uint8_t tmp[16];
for(i=0;i<16;i++)
in[i] = i;
AES_encrypt(in, tmp, &s->aes_encrypt_key);
AES_decrypt(tmp, out, &s->aes_decrypt_key);
for(i = 0; i < 16; i++)
printf(" %02x", tmp[i]);
printf("\n");
for(i = 0; i < 16; i++)
printf(" %02x", out[i]);
printf("\n");
}
#endif
return 0;
}
/* The crypt function is compatible with the linux cryptoloop
algorithm for < 4 GB images. NOTE: out_buf == in_buf is
supported */
static void encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
uint8_t *out_buf, const uint8_t *in_buf,
int nb_sectors, int enc,
const AES_KEY *key)
{
union {
uint64_t ll[2];
uint8_t b[16];
} ivec;
int i;
for(i = 0; i < nb_sectors; i++) {
ivec.ll[0] = cpu_to_le64(sector_num);
ivec.ll[1] = 0;
AES_cbc_encrypt(in_buf, out_buf, 512, key,
ivec.b, enc);
sector_num++;
in_buf += 512;
out_buf += 512;
}
}
/* 'allocate' is:
*
* 0 to not allocate.
*
* 1 to allocate a normal cluster (for sector indexes 'n_start' to
* 'n_end')
*
* 2 to allocate a compressed cluster of size
* 'compressed_size'. 'compressed_size' must be > 0 and <
* cluster_size
*
* return 0 if not allocated.
*/
static uint64_t get_cluster_offset(BlockDriverState *bs,
uint64_t offset, int allocate,
int compressed_size,
int n_start, int n_end)
{
BDRVQcowState *s = bs->opaque;
int min_index, i, j, l1_index, l2_index;
uint64_t l2_offset, *l2_table, cluster_offset, tmp;
uint32_t min_count;
int new_l2_table;
l1_index = offset >> (s->l2_bits + s->cluster_bits);
l2_offset = s->l1_table[l1_index];
new_l2_table = 0;
if (!l2_offset) {
if (!allocate)
return 0;
/* allocate a new l2 entry */
l2_offset = lseek(s->fd, 0, SEEK_END);
/* round to cluster size */
l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);
/* update the L1 entry */
s->l1_table[l1_index] = l2_offset;
tmp = cpu_to_be64(l2_offset);
lseek(s->fd, s->l1_table_offset + l1_index * sizeof(tmp), SEEK_SET);
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
return 0;
new_l2_table = 1;
}
for(i = 0; i < L2_CACHE_SIZE; i++) {
if (l2_offset == s->l2_cache_offsets[i]) {
/* increment the hit count */
if (++s->l2_cache_counts[i] == 0xffffffff) {
for(j = 0; j < L2_CACHE_SIZE; j++) {
s->l2_cache_counts[j] >>= 1;
}
}
l2_table = s->l2_cache + (i << s->l2_bits);
goto found;
}
}
/* not found: load a new entry in the least used one */
min_index = 0;
min_count = 0xffffffff;
for(i = 0; i < L2_CACHE_SIZE; i++) {
if (s->l2_cache_counts[i] < min_count) {
min_count = s->l2_cache_counts[i];
min_index = i;
}
}
l2_table = s->l2_cache + (min_index << s->l2_bits);
lseek(s->fd, l2_offset, SEEK_SET);
if (new_l2_table) {
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
if (write(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) !=
s->l2_size * sizeof(uint64_t))
return 0;
} else {
if (read(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) !=
s->l2_size * sizeof(uint64_t))
return 0;
}
s->l2_cache_offsets[min_index] = l2_offset;
s->l2_cache_counts[min_index] = 1;
found:
l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
cluster_offset = be64_to_cpu(l2_table[l2_index]);
if (!cluster_offset ||
((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1)) {
if (!allocate)
return 0;
/* allocate a new cluster */
if ((cluster_offset & QCOW_OFLAG_COMPRESSED) &&
(n_end - n_start) < s->cluster_sectors) {
/* if the cluster is already compressed, we must
decompress it in the case it is not completely
overwritten */
if (decompress_cluster(s, cluster_offset) < 0)
return 0;
cluster_offset = lseek(s->fd, 0, SEEK_END);
cluster_offset = (cluster_offset + s->cluster_size - 1) &
~(s->cluster_size - 1);
/* write the cluster content */
lseek(s->fd, cluster_offset, SEEK_SET);
if (write(s->fd, s->cluster_cache, s->cluster_size) !=
s->cluster_size)
return -1;
} else {
cluster_offset = lseek(s->fd, 0, SEEK_END);
if (allocate == 1) {
/* round to cluster size */
cluster_offset = (cluster_offset + s->cluster_size - 1) &
~(s->cluster_size - 1);
ftruncate(s->fd, cluster_offset + s->cluster_size);
/* if encrypted, we must initialize the cluster
content which won't be written */
if (s->crypt_method &&
(n_end - n_start) < s->cluster_sectors) {
uint64_t start_sect;
start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
memset(s->cluster_data + 512, 0xaa, 512);
for(i = 0; i < s->cluster_sectors; i++) {
if (i < n_start || i >= n_end) {
encrypt_sectors(s, start_sect + i,
s->cluster_data,
s->cluster_data + 512, 1, 1,
&s->aes_encrypt_key);
lseek(s->fd, cluster_offset + i * 512, SEEK_SET);
if (write(s->fd, s->cluster_data, 512) != 512)
return -1;
}
}
}
} else {
cluster_offset |= QCOW_OFLAG_COMPRESSED |
(uint64_t)compressed_size << (63 - s->cluster_bits);
}
}
/* update L2 table */
tmp = cpu_to_be64(cluster_offset);
l2_table[l2_index] = tmp;
lseek(s->fd, l2_offset + l2_index * sizeof(tmp), SEEK_SET);
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
return 0;
}
return cluster_offset;
}
static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum)
{
BDRVQcowState *s = bs->opaque;
int index_in_cluster, n;
uint64_t cluster_offset;
cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
index_in_cluster = sector_num & (s->cluster_sectors - 1);
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
*pnum = n;
return (cluster_offset != 0);
}
static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
const uint8_t *buf, int buf_size)
{
z_stream strm1, *strm = &strm1;
int ret, out_len;
memset(strm, 0, sizeof(*strm));
strm->next_in = (uint8_t *)buf;
strm->avail_in = buf_size;
strm->next_out = out_buf;
strm->avail_out = out_buf_size;
ret = inflateInit2(strm, -12);
if (ret != Z_OK)
return -1;
ret = inflate(strm, Z_FINISH);
out_len = strm->next_out - out_buf;
if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) ||
out_len != out_buf_size) {
inflateEnd(strm);
return -1;
}
inflateEnd(strm);
return 0;
}
static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
{
int ret, csize;
uint64_t coffset;
coffset = cluster_offset & s->cluster_offset_mask;
if (s->cluster_cache_offset != coffset) {
csize = cluster_offset >> (63 - s->cluster_bits);
csize &= (s->cluster_size - 1);
lseek(s->fd, coffset, SEEK_SET);
ret = read(s->fd, s->cluster_data, csize);
if (ret != csize)
return -1;
if (decompress_buffer(s->cluster_cache, s->cluster_size,
s->cluster_data, csize) < 0) {
return -1;
}
s->cluster_cache_offset = coffset;
}
return 0;
}
static int qcow_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVQcowState *s = bs->opaque;
int ret, index_in_cluster, n;
uint64_t cluster_offset;
while (nb_sectors > 0) {
cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
index_in_cluster = sector_num & (s->cluster_sectors - 1);
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
if (!cluster_offset) {
memset(buf, 0, 512 * n);
} else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
if (decompress_cluster(s, cluster_offset) < 0)
return -1;
memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
} else {
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
ret = read(s->fd, buf, n * 512);
if (ret != n * 512)
return -1;
if (s->crypt_method) {
encrypt_sectors(s, sector_num, buf, buf, n, 0,
&s->aes_decrypt_key);
}
}
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
return 0;
}
static int qcow_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVQcowState *s = bs->opaque;
int ret, index_in_cluster, n;
uint64_t cluster_offset;
while (nb_sectors > 0) {
index_in_cluster = sector_num & (s->cluster_sectors - 1);
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0,
index_in_cluster,
index_in_cluster + n);
if (!cluster_offset)
return -1;
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
if (s->crypt_method) {
encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
&s->aes_encrypt_key);
ret = write(s->fd, s->cluster_data, n * 512);
} else {
ret = write(s->fd, buf, n * 512);
}
if (ret != n * 512)
return -1;
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
s->cluster_cache_offset = -1; /* disable compressed cache */
return 0;
}
static void qcow_close(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
qemu_free(s->l1_table);
qemu_free(s->l2_cache);
qemu_free(s->cluster_cache);
qemu_free(s->cluster_data);
close(s->fd);
}
static int qcow_create(const char *filename, int64_t total_size,
const char *backing_file, int flags)
{
int fd, header_size, backing_filename_len, l1_size, i, shift;
QCowHeader header;
char backing_filename[1024];
uint64_t tmp;
struct stat st;
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
0644);
if (fd < 0)
return -1;
memset(&header, 0, sizeof(header));
header.magic = cpu_to_be32(QCOW_MAGIC);
header.version = cpu_to_be32(QCOW_VERSION);
header.size = cpu_to_be64(total_size * 512);
header_size = sizeof(header);
backing_filename_len = 0;
if (backing_file) {
const char *p;
/* XXX: this is a hack: we do not attempt to check for URL
like syntax */
p = strchr(backing_file, ':');
if (p && (p - backing_file) >= 2) {
/* URL like but exclude "c:" like filenames */
pstrcpy(backing_filename, sizeof(backing_filename),
backing_file);
} else {
realpath(backing_file, backing_filename);
if (stat(backing_filename, &st) != 0) {
return -1;
}
}
header.mtime = cpu_to_be32(st.st_mtime);
header.backing_file_offset = cpu_to_be64(header_size);
backing_filename_len = strlen(backing_filename);
header.backing_file_size = cpu_to_be32(backing_filename_len);
header_size += backing_filename_len;
header.cluster_bits = 9; /* 512 byte cluster to avoid copying
unmodifyed sectors */
header.l2_bits = 12; /* 32 KB L2 tables */
} else {
header.cluster_bits = 12; /* 4 KB clusters */
header.l2_bits = 9; /* 4 KB L2 tables */
}
header_size = (header_size + 7) & ~7;
shift = header.cluster_bits + header.l2_bits;
l1_size = ((total_size * 512) + (1LL << shift) - 1) >> shift;
header.l1_table_offset = cpu_to_be64(header_size);
if (flags) {
header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
} else {
header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
}
/* write all the data */
write(fd, &header, sizeof(header));
if (backing_file) {
write(fd, backing_filename, backing_filename_len);
}
lseek(fd, header_size, SEEK_SET);
tmp = 0;
for(i = 0;i < l1_size; i++) {
write(fd, &tmp, sizeof(tmp));
}
close(fd);
return 0;
}
int qcow_get_cluster_size(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
if (bs->drv != &bdrv_qcow)
return -1;
return s->cluster_size;
}
/* XXX: put compressed sectors first, then all the cluster aligned
tables to avoid losing bytes in alignment */
int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf)
{
BDRVQcowState *s = bs->opaque;
z_stream strm;
int ret, out_len;
uint8_t *out_buf;
uint64_t cluster_offset;
if (bs->drv != &bdrv_qcow)
return -1;
out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
if (!out_buf)
return -1;
/* best compression, small window, no zlib header */
memset(&strm, 0, sizeof(strm));
ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,
Z_DEFLATED, -12,
9, Z_DEFAULT_STRATEGY);
if (ret != 0) {
qemu_free(out_buf);
return -1;
}
strm.avail_in = s->cluster_size;
strm.next_in = (uint8_t *)buf;
strm.avail_out = s->cluster_size;
strm.next_out = out_buf;
ret = deflate(&strm, Z_FINISH);
if (ret != Z_STREAM_END && ret != Z_OK) {
qemu_free(out_buf);
deflateEnd(&strm);
return -1;
}
out_len = strm.next_out - out_buf;
deflateEnd(&strm);
if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
/* could not compress: write normal cluster */
qcow_write(bs, sector_num, buf, s->cluster_sectors);
} else {
cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
out_len, 0, 0);
cluster_offset &= s->cluster_offset_mask;
lseek(s->fd, cluster_offset, SEEK_SET);
if (write(s->fd, out_buf, out_len) != out_len) {
qemu_free(out_buf);
return -1;
}
}
qemu_free(out_buf);
return 0;
}
BlockDriver bdrv_qcow = {
"qcow",
sizeof(BDRVQcowState),
qcow_probe,
qcow_open,
qcow_read,
qcow_write,
qcow_close,
qcow_create,
qcow_is_allocated,
qcow_set_key,
};
-439
View File
@@ -1,439 +0,0 @@
/*
* Block driver for the VMDK format
*
* Copyright (c) 2004 Fabrice Bellard
* Copyright (c) 2005 Filip Navara
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "block_int.h"
#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
#define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
typedef struct {
uint32_t version;
uint32_t flags;
uint32_t disk_sectors;
uint32_t granularity;
uint32_t l1dir_offset;
uint32_t l1dir_size;
uint32_t file_sectors;
uint32_t cylinders;
uint32_t heads;
uint32_t sectors_per_track;
} VMDK3Header;
typedef struct {
uint32_t version;
uint32_t flags;
int64_t capacity;
int64_t granularity;
int64_t desc_offset;
int64_t desc_size;
int32_t num_gtes_per_gte;
int64_t rgd_offset;
int64_t gd_offset;
int64_t grain_offset;
char filler[1];
char check_bytes[4];
} __attribute__((packed)) VMDK4Header;
#define L2_CACHE_SIZE 16
typedef struct BDRVVmdkState {
int fd;
int64_t l1_table_offset;
int64_t l1_backup_table_offset;
uint32_t *l1_table;
uint32_t *l1_backup_table;
unsigned int l1_size;
uint32_t l1_entry_sectors;
unsigned int l2_size;
uint32_t *l2_cache;
uint32_t l2_cache_offsets[L2_CACHE_SIZE];
uint32_t l2_cache_counts[L2_CACHE_SIZE];
unsigned int cluster_sectors;
} BDRVVmdkState;
static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
{
uint32_t magic;
if (buf_size < 4)
return 0;
magic = be32_to_cpu(*(uint32_t *)buf);
if (magic == VMDK3_MAGIC ||
magic == VMDK4_MAGIC)
return 100;
else
return 0;
}
static int vmdk_open(BlockDriverState *bs, const char *filename)
{
BDRVVmdkState *s = bs->opaque;
int fd, i;
uint32_t magic;
int l1_size;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
bs->read_only = 1;
}
if (read(fd, &magic, sizeof(magic)) != sizeof(magic))
goto fail;
magic = be32_to_cpu(magic);
if (magic == VMDK3_MAGIC) {
VMDK3Header header;
if (read(fd, &header, sizeof(header)) !=
sizeof(header))
goto fail;
s->cluster_sectors = le32_to_cpu(header.granularity);
s->l2_size = 1 << 9;
s->l1_size = 1 << 6;
bs->total_sectors = le32_to_cpu(header.disk_sectors);
s->l1_table_offset = le32_to_cpu(header.l1dir_offset) << 9;
s->l1_backup_table_offset = 0;
s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
} else if (magic == VMDK4_MAGIC) {
VMDK4Header header;
if (read(fd, &header, sizeof(header)) != sizeof(header))
goto fail;
bs->total_sectors = le32_to_cpu(header.capacity);
s->cluster_sectors = le32_to_cpu(header.granularity);
s->l2_size = le32_to_cpu(header.num_gtes_per_gte);
s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
if (s->l1_entry_sectors <= 0)
goto fail;
s->l1_size = (bs->total_sectors + s->l1_entry_sectors - 1)
/ s->l1_entry_sectors;
s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9;
s->l1_backup_table_offset = le64_to_cpu(header.gd_offset) << 9;
} else {
goto fail;
}
/* read the L1 table */
l1_size = s->l1_size * sizeof(uint32_t);
s->l1_table = qemu_malloc(l1_size);
if (!s->l1_table)
goto fail;
if (lseek(fd, s->l1_table_offset, SEEK_SET) == -1)
goto fail;
if (read(fd, s->l1_table, l1_size) != l1_size)
goto fail;
for(i = 0; i < s->l1_size; i++) {
le32_to_cpus(&s->l1_table[i]);
}
if (s->l1_backup_table_offset) {
s->l1_backup_table = qemu_malloc(l1_size);
if (!s->l1_backup_table)
goto fail;
if (lseek(fd, s->l1_backup_table_offset, SEEK_SET) == -1)
goto fail;
if (read(fd, s->l1_backup_table, l1_size) != l1_size)
goto fail;
for(i = 0; i < s->l1_size; i++) {
le32_to_cpus(&s->l1_backup_table[i]);
}
}
s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint32_t));
if (!s->l2_cache)
goto fail;
s->fd = fd;
return 0;
fail:
qemu_free(s->l1_backup_table);
qemu_free(s->l1_table);
qemu_free(s->l2_cache);
close(fd);
return -1;
}
static uint64_t get_cluster_offset(BlockDriverState *bs,
uint64_t offset, int allocate)
{
BDRVVmdkState *s = bs->opaque;
unsigned int l1_index, l2_offset, l2_index;
int min_index, i, j;
uint32_t min_count, *l2_table, tmp;
uint64_t cluster_offset;
l1_index = (offset >> 9) / s->l1_entry_sectors;
if (l1_index >= s->l1_size)
return 0;
l2_offset = s->l1_table[l1_index];
if (!l2_offset)
return 0;
for(i = 0; i < L2_CACHE_SIZE; i++) {
if (l2_offset == s->l2_cache_offsets[i]) {
/* increment the hit count */
if (++s->l2_cache_counts[i] == 0xffffffff) {
for(j = 0; j < L2_CACHE_SIZE; j++) {
s->l2_cache_counts[j] >>= 1;
}
}
l2_table = s->l2_cache + (i * s->l2_size);
goto found;
}
}
/* not found: load a new entry in the least used one */
min_index = 0;
min_count = 0xffffffff;
for(i = 0; i < L2_CACHE_SIZE; i++) {
if (s->l2_cache_counts[i] < min_count) {
min_count = s->l2_cache_counts[i];
min_index = i;
}
}
l2_table = s->l2_cache + (min_index * s->l2_size);
lseek(s->fd, (int64_t)l2_offset * 512, SEEK_SET);
if (read(s->fd, l2_table, s->l2_size * sizeof(uint32_t)) !=
s->l2_size * sizeof(uint32_t))
return 0;
s->l2_cache_offsets[min_index] = l2_offset;
s->l2_cache_counts[min_index] = 1;
found:
l2_index = ((offset >> 9) / s->cluster_sectors) % s->l2_size;
cluster_offset = le32_to_cpu(l2_table[l2_index]);
if (!cluster_offset) {
if (!allocate)
return 0;
cluster_offset = lseek(s->fd, 0, SEEK_END);
ftruncate(s->fd, cluster_offset + (s->cluster_sectors << 9));
cluster_offset >>= 9;
/* update L2 table */
tmp = cpu_to_le32(cluster_offset);
l2_table[l2_index] = tmp;
lseek(s->fd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), SEEK_SET);
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
return 0;
/* update backup L2 table */
if (s->l1_backup_table_offset != 0) {
l2_offset = s->l1_backup_table[l1_index];
lseek(s->fd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), SEEK_SET);
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
return 0;
}
}
cluster_offset <<= 9;
return cluster_offset;
}
static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum)
{
BDRVVmdkState *s = bs->opaque;
int index_in_cluster, n;
uint64_t cluster_offset;
cluster_offset = get_cluster_offset(bs, sector_num << 9, 0);
index_in_cluster = sector_num % s->cluster_sectors;
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
*pnum = n;
return (cluster_offset != 0);
}
static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVVmdkState *s = bs->opaque;
int ret, index_in_cluster, n;
uint64_t cluster_offset;
while (nb_sectors > 0) {
cluster_offset = get_cluster_offset(bs, sector_num << 9, 0);
index_in_cluster = sector_num % s->cluster_sectors;
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
if (!cluster_offset) {
memset(buf, 0, 512 * n);
} else {
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
ret = read(s->fd, buf, n * 512);
if (ret != n * 512)
return -1;
}
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
return 0;
}
static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVVmdkState *s = bs->opaque;
int ret, index_in_cluster, n;
uint64_t cluster_offset;
while (nb_sectors > 0) {
index_in_cluster = sector_num & (s->cluster_sectors - 1);
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
cluster_offset = get_cluster_offset(bs, sector_num << 9, 1);
if (!cluster_offset)
return -1;
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
ret = write(s->fd, buf, n * 512);
if (ret != n * 512)
return -1;
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
return 0;
}
static int vmdk_create(const char *filename, int64_t total_size,
const char *backing_file, int flags)
{
int fd, i;
VMDK4Header header;
uint32_t tmp, magic, grains, gd_size, gt_size, gt_count;
char *desc_template =
"# Disk DescriptorFile\n"
"version=1\n"
"CID=%x\n"
"parentCID=ffffffff\n"
"createType=\"monolithicSparse\"\n"
"\n"
"# Extent description\n"
"RW %lu SPARSE \"%s\"\n"
"\n"
"# The Disk Data Base \n"
"#DDB\n"
"\n"
"ddb.virtualHWVersion = \"3\"\n"
"ddb.geometry.cylinders = \"%lu\"\n"
"ddb.geometry.heads = \"16\"\n"
"ddb.geometry.sectors = \"63\"\n"
"ddb.adapterType = \"ide\"\n";
char desc[1024];
const char *real_filename, *temp_str;
/* XXX: add support for backing file */
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
0644);
if (fd < 0)
return -1;
magic = cpu_to_be32(VMDK4_MAGIC);
memset(&header, 0, sizeof(header));
header.version = cpu_to_le32(1);
header.flags = cpu_to_le32(3); /* ?? */
header.capacity = cpu_to_le64(total_size);
header.granularity = cpu_to_le64(128);
header.num_gtes_per_gte = cpu_to_le32(512);
grains = (total_size + header.granularity - 1) / header.granularity;
gt_size = ((header.num_gtes_per_gte * sizeof(uint32_t)) + 511) >> 9;
gt_count = (grains + header.num_gtes_per_gte - 1) / header.num_gtes_per_gte;
gd_size = (gt_count * sizeof(uint32_t) + 511) >> 9;
header.desc_offset = 1;
header.desc_size = 20;
header.rgd_offset = header.desc_offset + header.desc_size;
header.gd_offset = header.rgd_offset + gd_size + (gt_size * gt_count);
header.grain_offset =
((header.gd_offset + gd_size + (gt_size * gt_count) +
header.granularity - 1) / header.granularity) *
header.granularity;
header.desc_offset = cpu_to_le64(header.desc_offset);
header.desc_size = cpu_to_le64(header.desc_size);
header.rgd_offset = cpu_to_le64(header.rgd_offset);
header.gd_offset = cpu_to_le64(header.gd_offset);
header.grain_offset = cpu_to_le64(header.grain_offset);
header.check_bytes[0] = 0xa;
header.check_bytes[1] = 0x20;
header.check_bytes[2] = 0xd;
header.check_bytes[3] = 0xa;
/* write all the data */
write(fd, &magic, sizeof(magic));
write(fd, &header, sizeof(header));
ftruncate(fd, header.grain_offset << 9);
/* write grain directory */
lseek(fd, le64_to_cpu(header.rgd_offset) << 9, SEEK_SET);
for (i = 0, tmp = header.rgd_offset + gd_size;
i < gt_count; i++, tmp += gt_size)
write(fd, &tmp, sizeof(tmp));
/* write backup grain directory */
lseek(fd, le64_to_cpu(header.gd_offset) << 9, SEEK_SET);
for (i = 0, tmp = header.gd_offset + gd_size;
i < gt_count; i++, tmp += gt_size)
write(fd, &tmp, sizeof(tmp));
/* compose the descriptor */
real_filename = filename;
if ((temp_str = strrchr(real_filename, '\\')) != NULL)
real_filename = temp_str + 1;
if ((temp_str = strrchr(real_filename, '/')) != NULL)
real_filename = temp_str + 1;
if ((temp_str = strrchr(real_filename, ':')) != NULL)
real_filename = temp_str + 1;
sprintf(desc, desc_template, time(NULL), (unsigned long)total_size,
real_filename, total_size / (63 * 16));
/* write the descriptor */
lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET);
write(fd, desc, strlen(desc));
close(fd);
return 0;
}
static void vmdk_close(BlockDriverState *bs)
{
BDRVVmdkState *s = bs->opaque;
qemu_free(s->l1_table);
qemu_free(s->l2_cache);
close(s->fd);
}
BlockDriver bdrv_vmdk = {
"vmdk",
sizeof(BDRVVmdkState),
vmdk_probe,
vmdk_open,
vmdk_read,
vmdk_write,
vmdk_close,
vmdk_create,
vmdk_is_allocated,
};
-242
View File
@@ -1,242 +0,0 @@
/*
* Block driver for Conectix/Microsoft Virtual PC images
*
* Copyright (c) 2005 Alex Beregszaszi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "block_int.h"
/**************************************************************/
#define HEADER_SIZE 512
//#define CACHE
// always big-endian
struct vpc_subheader {
char magic[8]; // "conectix" / "cxsparse"
union {
struct {
uint32_t unk1[2];
uint32_t unk2; // always zero?
uint32_t subheader_offset;
uint32_t unk3; // some size?
char creator[4]; // "vpc "
uint16_t major;
uint16_t minor;
char guest[4]; // "Wi2k"
uint32_t unk4[7];
uint8_t vnet_id[16]; // virtual network id, purpose unknown
// next 16 longs are used, but dunno the purpose
// next 6 longs unknown, following 7 long maybe a serial
char padding[HEADER_SIZE - 84];
} main;
struct {
uint32_t unk1[2]; // all bits set
uint32_t unk2; // always zero?
uint32_t pagetable_offset;
uint32_t unk3;
uint32_t pagetable_entries; // 32bit/entry
uint32_t pageentry_size; // 512*8*512
uint32_t nb_sectors;
char padding[HEADER_SIZE - 40];
} sparse;
char padding[HEADER_SIZE - 8];
} type;
};
typedef struct BDRVVPCState {
int fd;
int pagetable_entries;
uint32_t *pagetable;
uint32_t pageentry_size;
#ifdef CACHE
uint8_t *pageentry_u8;
uint32_t *pageentry_u32;
uint16_t *pageentry_u16;
uint64_t last_bitmap;
#endif
} BDRVVPCState;
static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
{
if (buf_size >= 8 && !strncmp(buf, "conectix", 8))
return 100;
return 0;
}
static int vpc_open(BlockDriverState *bs, const char *filename)
{
BDRVVPCState *s = bs->opaque;
int fd, i;
struct vpc_subheader header;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
}
bs->read_only = 1; // no write support yet
s->fd = fd;
if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
goto fail;
if (strncmp(header.magic, "conectix", 8))
goto fail;
lseek(s->fd, be32_to_cpu(header.type.main.subheader_offset), SEEK_SET);
if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
goto fail;
if (strncmp(header.magic, "cxsparse", 8))
goto fail;
bs->total_sectors = ((uint64_t)be32_to_cpu(header.type.sparse.pagetable_entries) *
be32_to_cpu(header.type.sparse.pageentry_size)) / 512;
lseek(s->fd, be32_to_cpu(header.type.sparse.pagetable_offset), SEEK_SET);
s->pagetable_entries = be32_to_cpu(header.type.sparse.pagetable_entries);
s->pagetable = qemu_malloc(s->pagetable_entries * 4);
if (!s->pagetable)
goto fail;
if (read(s->fd, s->pagetable, s->pagetable_entries * 4) !=
s->pagetable_entries * 4)
goto fail;
for (i = 0; i < s->pagetable_entries; i++)
be32_to_cpus(&s->pagetable[i]);
s->pageentry_size = be32_to_cpu(header.type.sparse.pageentry_size);
#ifdef CACHE
s->pageentry_u8 = qemu_malloc(512);
if (!s->pageentry_u8)
goto fail;
s->pageentry_u32 = s->pageentry_u8;
s->pageentry_u16 = s->pageentry_u8;
s->last_pagetable = -1;
#endif
return 0;
fail:
close(fd);
return -1;
}
static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
{
BDRVVPCState *s = bs->opaque;
uint64_t offset = sector_num * 512;
uint64_t bitmap_offset, block_offset;
uint32_t pagetable_index, pageentry_index;
pagetable_index = offset / s->pageentry_size;
pageentry_index = (offset % s->pageentry_size) / 512;
if (pagetable_index > s->pagetable_entries || s->pagetable[pagetable_index] == 0xffffffff)
return -1; // not allocated
bitmap_offset = 512 * s->pagetable[pagetable_index];
block_offset = bitmap_offset + 512 + (512 * pageentry_index);
// printf("sector: %llx, index: %x, offset: %x, bioff: %llx, bloff: %llx\n",
// sector_num, pagetable_index, pageentry_index,
// bitmap_offset, block_offset);
// disabled by reason
#if 0
#ifdef CACHE
if (bitmap_offset != s->last_bitmap)
{
lseek(s->fd, bitmap_offset, SEEK_SET);
s->last_bitmap = bitmap_offset;
// Scary! Bitmap is stored as big endian 32bit entries,
// while we used to look it up byte by byte
read(s->fd, s->pageentry_u8, 512);
for (i = 0; i < 128; i++)
be32_to_cpus(&s->pageentry_u32[i]);
}
if ((s->pageentry_u8[pageentry_index / 8] >> (pageentry_index % 8)) & 1)
return -1;
#else
lseek(s->fd, bitmap_offset + (pageentry_index / 8), SEEK_SET);
read(s->fd, &bitmap_entry, 1);
if ((bitmap_entry >> (pageentry_index % 8)) & 1)
return -1; // not allocated
#endif
#endif
lseek(s->fd, block_offset, SEEK_SET);
return 0;
}
static int vpc_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVVPCState *s = bs->opaque;
int ret;
while (nb_sectors > 0) {
if (!seek_to_sector(bs, sector_num))
{
ret = read(s->fd, buf, 512);
if (ret != 512)
return -1;
}
else
memset(buf, 0, 512);
nb_sectors--;
sector_num++;
buf += 512;
}
return 0;
}
static void vpc_close(BlockDriverState *bs)
{
BDRVVPCState *s = bs->opaque;
qemu_free(s->pagetable);
#ifdef CACHE
qemu_free(s->pageentry_u8);
#endif
close(s->fd);
}
BlockDriver bdrv_vpc = {
"vpc",
sizeof(BDRVVPCState),
vpc_probe,
vpc_open,
vpc_read,
NULL,
vpc_close,
};
-1742
View File
File diff suppressed because it is too large. Load diff
-660
View File
@@ -1,660 +0,0 @@
/*
* QEMU System Emulator block driver
*
* Copyright (c) 2003 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "block_int.h"
#ifdef _BSD
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/queue.h>
#include <sys/disk.h>
#endif
static BlockDriverState *bdrv_first;
static BlockDriver *first_drv;
void bdrv_register(BlockDriver *bdrv)
{
bdrv->next = first_drv;
first_drv = bdrv;
}
/* create a new block device (by default it is empty) */
BlockDriverState *bdrv_new(const char *device_name)
{
BlockDriverState **pbs, *bs;
bs = qemu_mallocz(sizeof(BlockDriverState));
if(!bs)
return NULL;
pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
if (device_name[0] != '\0') {
/* insert at the end */
pbs = &bdrv_first;
while (*pbs != NULL)
pbs = &(*pbs)->next;
*pbs = bs;
}
return bs;
}
BlockDriver *bdrv_find_format(const char *format_name)
{
BlockDriver *drv1;
for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
if (!strcmp(drv1->format_name, format_name))
return drv1;
}
return NULL;
}
int bdrv_create(BlockDriver *drv,
const char *filename, int64_t size_in_sectors,
const char *backing_file, int flags)
{
if (!drv->bdrv_create)
return -ENOTSUP;
return drv->bdrv_create(filename, size_in_sectors, backing_file, flags);
}
#ifdef _WIN32
static void get_tmp_filename(char *filename, int size)
{
/* XXX: find a better function */
tmpnam(filename);
}
#else
static void get_tmp_filename(char *filename, int size)
{
int fd;
/* XXX: race condition possible */
pstrcpy(filename, size, "/tmp/vl.XXXXXX");
fd = mkstemp(filename);
close(fd);
}
#endif
/* XXX: force raw format if block or character device ? It would
simplify the BSD case */
static BlockDriver *find_image_format(const char *filename)
{
int fd, ret, score, score_max;
BlockDriver *drv1, *drv;
uint8_t *buf;
size_t bufsize = 1024;
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0) {
buf = NULL;
ret = 0;
} else {
#ifdef DIOCGSECTORSIZE
{
unsigned int sectorsize = 512;
if (!ioctl(fd, DIOCGSECTORSIZE, &sectorsize) &&
sectorsize > bufsize)
bufsize = sectorsize;
}
#endif
buf = qemu_malloc(bufsize);
if (!buf)
return NULL;
ret = read(fd, buf, bufsize);
if (ret < 0) {
close(fd);
qemu_free(buf);
return NULL;
}
close(fd);
}
drv = NULL;
score_max = 0;
for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
score = drv1->bdrv_probe(buf, ret, filename);
if (score > score_max) {
score_max = score;
drv = drv1;
}
}
qemu_free(buf);
return drv;
}
int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot)
{
return bdrv_open2(bs, filename, snapshot, NULL);
}
int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot,
BlockDriver *drv)
{
int ret;
char tmp_filename[1024];
bs->read_only = 0;
bs->is_temporary = 0;
bs->encrypted = 0;
if (snapshot) {
BlockDriverState *bs1;
int64_t total_size;
/* if snapshot, we create a temporary backing file and open it
instead of opening 'filename' directly */
/* if there is a backing file, use it */
bs1 = bdrv_new("");
if (!bs1) {
return -1;
}
if (bdrv_open(bs1, filename, 0) < 0) {
bdrv_delete(bs1);
return -1;
}
total_size = bs1->total_sectors;
bdrv_delete(bs1);
get_tmp_filename(tmp_filename, sizeof(tmp_filename));
/* XXX: use cow for linux as it is more efficient ? */
if (bdrv_create(&bdrv_qcow, tmp_filename,
total_size, filename, 0) < 0) {
return -1;
}
filename = tmp_filename;
bs->is_temporary = 1;
}
pstrcpy(bs->filename, sizeof(bs->filename), filename);
if (!drv) {
drv = find_image_format(filename);
if (!drv)
return -1;
}
bs->drv = drv;
bs->opaque = qemu_mallocz(drv->instance_size);
if (bs->opaque == NULL && drv->instance_size > 0)
return -1;
ret = drv->bdrv_open(bs, filename);
if (ret < 0) {
qemu_free(bs->opaque);
return -1;
}
#ifndef _WIN32
if (bs->is_temporary) {
unlink(filename);
}
#endif
if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) {
/* if there is a backing file, use it */
bs->backing_hd = bdrv_new("");
if (!bs->backing_hd) {
fail:
bdrv_close(bs);
return -1;
}
if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0)
goto fail;
}
bs->inserted = 1;
/* call the change callback */
if (bs->change_cb)
bs->change_cb(bs->change_opaque);
return 0;
}
void bdrv_close(BlockDriverState *bs)
{
if (bs->inserted) {
if (bs->backing_hd)
bdrv_delete(bs->backing_hd);
bs->drv->bdrv_close(bs);
qemu_free(bs->opaque);
#ifdef _WIN32
if (bs->is_temporary) {
unlink(bs->filename);
}
#endif
bs->opaque = NULL;
bs->drv = NULL;
bs->inserted = 0;
/* call the change callback */
if (bs->change_cb)
bs->change_cb(bs->change_opaque);
}
}
void bdrv_delete(BlockDriverState *bs)
{
/* XXX: remove the driver list */
bdrv_close(bs);
qemu_free(bs);
}
/* commit COW file into the raw image */
int bdrv_commit(BlockDriverState *bs)
{
int64_t i;
int n, j;
unsigned char sector[512];
if (!bs->inserted)
return -ENOENT;
if (bs->read_only) {
return -EACCES;
}
if (!bs->backing_hd) {
return -ENOTSUP;
}
for (i = 0; i < bs->total_sectors;) {
if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) {
for(j = 0; j < n; j++) {
if (bdrv_read(bs, i, sector, 1) != 0) {
return -EIO;
}
if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) {
return -EIO;
}
i++;
}
} else {
i += n;
}
}
return 0;
}
/* return -1 if error */
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
int ret, n;
BlockDriver *drv = bs->drv;
if (!bs->inserted)
return -1;
while (nb_sectors > 0) {
if (sector_num == 0 && bs->boot_sector_enabled) {
memcpy(buf, bs->boot_sector_data, 512);
n = 1;
} else if (bs->backing_hd) {
if (drv->bdrv_is_allocated(bs, sector_num, nb_sectors, &n)) {
ret = drv->bdrv_read(bs, sector_num, buf, n);
if (ret < 0)
return -1;
} else {
/* read from the base image */
ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
if (ret < 0)
return -1;
}
} else {
ret = drv->bdrv_read(bs, sector_num, buf, nb_sectors);
if (ret < 0)
return -1;
/* no need to loop */
break;
}
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
return 0;
}
/* return -1 if error */
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
if (!bs->inserted)
return -1;
if (bs->read_only)
return -1;
return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors);
}
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
{
*nb_sectors_ptr = bs->total_sectors;
}
/* force a given boot sector. */
void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size)
{
bs->boot_sector_enabled = 1;
if (size > 512)
size = 512;
memcpy(bs->boot_sector_data, data, size);
memset(bs->boot_sector_data + size, 0, 512 - size);
}
void bdrv_set_geometry_hint(BlockDriverState *bs,
int cyls, int heads, int secs)
{
bs->cyls = cyls;
bs->heads = heads;
bs->secs = secs;
}
void bdrv_set_type_hint(BlockDriverState *bs, int type)
{
bs->type = type;
bs->removable = ((type == BDRV_TYPE_CDROM ||
type == BDRV_TYPE_FLOPPY));
}
void bdrv_set_translation_hint(BlockDriverState *bs, int translation)
{
bs->translation = translation;
}
void bdrv_get_geometry_hint(BlockDriverState *bs,
int *pcyls, int *pheads, int *psecs)
{
*pcyls = bs->cyls;
*pheads = bs->heads;
*psecs = bs->secs;
}
int bdrv_get_type_hint(BlockDriverState *bs)
{
return bs->type;
}
int bdrv_get_translation_hint(BlockDriverState *bs)
{
return bs->translation;
}
int bdrv_is_removable(BlockDriverState *bs)
{
return bs->removable;
}
int bdrv_is_read_only(BlockDriverState *bs)
{
return bs->read_only;
}
int bdrv_is_inserted(BlockDriverState *bs)
{
return bs->inserted;
}
int bdrv_is_locked(BlockDriverState *bs)
{
return bs->locked;
}
void bdrv_set_locked(BlockDriverState *bs, int locked)
{
bs->locked = locked;
}
void bdrv_set_change_cb(BlockDriverState *bs,
void (*change_cb)(void *opaque), void *opaque)
{
bs->change_cb = change_cb;
bs->change_opaque = opaque;
}
int bdrv_is_encrypted(BlockDriverState *bs)
{
if (bs->backing_hd && bs->backing_hd->encrypted)
return 1;
return bs->encrypted;
}
int bdrv_set_key(BlockDriverState *bs, const char *key)
{
int ret;
if (bs->backing_hd && bs->backing_hd->encrypted) {
ret = bdrv_set_key(bs->backing_hd, key);
if (ret < 0)
return ret;
if (!bs->encrypted)
return 0;
}
if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key)
return -1;
return bs->drv->bdrv_set_key(bs, key);
}
void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size)
{
if (!bs->inserted || !bs->drv) {
buf[0] = '\0';
} else {
pstrcpy(buf, buf_size, bs->drv->format_name);
}
}
void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
void *opaque)
{
BlockDriver *drv;
for (drv = first_drv; drv != NULL; drv = drv->next) {
it(opaque, drv->format_name);
}
}
BlockDriverState *bdrv_find(const char *name)
{
BlockDriverState *bs;
for (bs = bdrv_first; bs != NULL; bs = bs->next) {
if (!strcmp(name, bs->device_name))
return bs;
}
return NULL;
}
void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque)
{
BlockDriverState *bs;
for (bs = bdrv_first; bs != NULL; bs = bs->next) {
it(opaque, bs->device_name);
}
}
const char *bdrv_get_device_name(BlockDriverState *bs)
{
return bs->device_name;
}
void bdrv_info(void)
{
BlockDriverState *bs;
for (bs = bdrv_first; bs != NULL; bs = bs->next) {
term_printf("%s:", bs->device_name);
term_printf(" type=");
switch(bs->type) {
case BDRV_TYPE_HD:
term_printf("hd");
break;
case BDRV_TYPE_CDROM:
term_printf("cdrom");
break;
case BDRV_TYPE_FLOPPY:
term_printf("floppy");
break;
}
term_printf(" removable=%d", bs->removable);
if (bs->removable) {
term_printf(" locked=%d", bs->locked);
}
if (bs->inserted) {
term_printf(" file=%s", bs->filename);
if (bs->backing_file[0] != '\0')
term_printf(" backing_file=%s", bs->backing_file);
term_printf(" ro=%d", bs->read_only);
term_printf(" drv=%s", bs->drv->format_name);
if (bs->encrypted)
term_printf(" encrypted");
} else {
term_printf(" [not inserted]");
}
term_printf("\n");
}
}
/**************************************************************/
/* RAW block driver */
typedef struct BDRVRawState {
int fd;
} BDRVRawState;
static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
{
return 1; /* maybe */
}
static int raw_open(BlockDriverState *bs, const char *filename)
{
BDRVRawState *s = bs->opaque;
int fd;
int64_t size;
#ifdef _BSD
struct stat sb;
#endif
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
bs->read_only = 1;
}
#ifdef _BSD
if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
#ifdef DIOCGMEDIASIZE
if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
#endif
size = lseek(fd, 0LL, SEEK_END);
} else
#endif
{
size = lseek(fd, 0, SEEK_END);
}
#ifdef _WIN32
/* On Windows hosts it can happen that we're unable to get file size
for CD-ROM raw device (it's inherent limitation of the CDFS driver). */
if (size == -1)
size = LONG_LONG_MAX;
#endif
bs->total_sectors = size / 512;
s->fd = fd;
return 0;
}
static int raw_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVRawState *s = bs->opaque;
int ret;
lseek(s->fd, sector_num * 512, SEEK_SET);
ret = read(s->fd, buf, nb_sectors * 512);
if (ret != nb_sectors * 512)
return -1;
return 0;
}
static int raw_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVRawState *s = bs->opaque;
int ret;
lseek(s->fd, sector_num * 512, SEEK_SET);
ret = write(s->fd, buf, nb_sectors * 512);
if (ret != nb_sectors * 512)
return -1;
return 0;
}
static void raw_close(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
close(s->fd);
}
static int raw_create(const char *filename, int64_t total_size,
const char *backing_file, int flags)
{
int fd;
if (flags || backing_file)
return -ENOTSUP;
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
0644);
if (fd < 0)
return -EIO;
ftruncate(fd, total_size * 512);
close(fd);
return 0;
}
BlockDriver bdrv_raw = {
"raw",
sizeof(BDRVRawState),
raw_probe,
raw_open,
raw_read,
raw_write,
raw_close,
raw_create,
};
void bdrv_init(void)
{
bdrv_register(&bdrv_raw);
#ifndef _WIN32
bdrv_register(&bdrv_cow);
#endif
bdrv_register(&bdrv_qcow);
bdrv_register(&bdrv_vmdk);
bdrv_register(&bdrv_cloop);
bdrv_register(&bdrv_dmg);
bdrv_register(&bdrv_bochs);
bdrv_register(&bdrv_vpc);
bdrv_register(&bdrv_vvfat);
}
-77
View File
@@ -1,77 +0,0 @@
/*
* QEMU System Emulator block driver
*
* Copyright (c) 2003 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef BLOCK_INT_H
#define BLOCK_INT_H
struct BlockDriver {
const char *format_name;
int instance_size;
int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
int (*bdrv_open)(BlockDriverState *bs, const char *filename);
int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors);
int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors);
void (*bdrv_close)(BlockDriverState *bs);
int (*bdrv_create)(const char *filename, int64_t total_sectors,
const char *backing_file, int flags);
int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum);
int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
struct BlockDriver *next;
};
struct BlockDriverState {
int64_t total_sectors;
int read_only; /* if true, the media is read only */
int inserted; /* if true, the media is present */
int removable; /* if true, the media can be removed */
int locked; /* if true, the media cannot temporarily be ejected */
int encrypted; /* if true, the media is encrypted */
/* event callback when inserting/removing */
void (*change_cb)(void *opaque);
void *change_opaque;
BlockDriver *drv;
void *opaque;
int boot_sector_enabled;
uint8_t boot_sector_data[512];
char filename[1024];
char backing_file[1024]; /* if non zero, the image is a diff of
this file image */
int is_temporary;
BlockDriverState *backing_hd;
/* NOTE: the following infos are only hints for real hardware
drivers. They are not used by the block driver */
int cyls, heads, secs, translation;
int type;
char device_name[32];
BlockDriverState *next;
};
#endif /* BLOCK_INT_H */
-202
View File
@@ -1,202 +0,0 @@
#ifndef BSWAP_H
#define BSWAP_H
#include "config-host.h"
#include <inttypes.h>
#ifdef HAVE_BYTESWAP_H
#include <byteswap.h>
#else
#define bswap_16(x) \
({ \
uint16_t __x = (x); \
((uint16_t)( \
(((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \
(((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \
})
#define bswap_32(x) \
({ \
uint32_t __x = (x); \
((uint32_t)( \
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
})
#define bswap_64(x) \
({ \
uint64_t __x = (x); \
((uint64_t)( \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \
})
#endif /* !HAVE_BYTESWAP_H */
static inline uint16_t bswap16(uint16_t x)
{
return bswap_16(x);
}
static inline uint32_t bswap32(uint32_t x)
{
return bswap_32(x);
}
static inline uint64_t bswap64(uint64_t x)
{
return bswap_64(x);
}
static inline void bswap16s(uint16_t *s)
{
*s = bswap16(*s);
}
static inline void bswap32s(uint32_t *s)
{
*s = bswap32(*s);
}
static inline void bswap64s(uint64_t *s)
{
*s = bswap64(*s);
}
#if defined(WORDS_BIGENDIAN)
#define be_bswap(v, size) (v)
#define le_bswap(v, size) bswap ## size(v)
#define be_bswaps(v, size)
#define le_bswaps(p, size) *p = bswap ## size(*p);
#else
#define le_bswap(v, size) (v)
#define be_bswap(v, size) bswap ## size(v)
#define le_bswaps(v, size)
#define be_bswaps(p, size) *p = bswap ## size(*p);
#endif
#define CPU_CONVERT(endian, size, type)\
static inline type endian ## size ## _to_cpu(type v)\
{\
return endian ## _bswap(v, size);\
}\
\
static inline type cpu_to_ ## endian ## size(type v)\
{\
return endian ## _bswap(v, size);\
}\
\
static inline void endian ## size ## _to_cpus(type *p)\
{\
endian ## _bswaps(p, size)\
}\
\
static inline void cpu_to_ ## endian ## size ## s(type *p)\
{\
endian ## _bswaps(p, size)\
}\
\
static inline type endian ## size ## _to_cpup(const type *p)\
{\
return endian ## size ## _to_cpu(*p);\
}\
\
static inline void cpu_to_ ## endian ## size ## w(type *p, type v)\
{\
*p = cpu_to_ ## endian ## size(v);\
}
CPU_CONVERT(be, 16, uint16_t)
CPU_CONVERT(be, 32, uint32_t)
CPU_CONVERT(be, 64, uint64_t)
CPU_CONVERT(le, 16, uint16_t)
CPU_CONVERT(le, 32, uint32_t)
CPU_CONVERT(le, 64, uint64_t)
/* unaligned versions (optimized for frequent unaligned accesses)*/
#if defined(__i386__) || defined(__powerpc__)
#define cpu_to_le16wu(p, v) cpu_to_le16w(p, v)
#define cpu_to_le32wu(p, v) cpu_to_le32w(p, v)
#define le16_to_cpupu(p) le16_to_cpup(p)
#define le32_to_cpupu(p) le32_to_cpup(p)
#define cpu_to_be16wu(p, v) cpu_to_be16w(p, v)
#define cpu_to_be32wu(p, v) cpu_to_be32w(p, v)
#else
static inline void cpu_to_le16wu(uint16_t *p, uint16_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v;
p1[1] = v >> 8;
}
static inline void cpu_to_le32wu(uint32_t *p, uint32_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v;
p1[1] = v >> 8;
p1[2] = v >> 16;
p1[3] = v >> 24;
}
static inline uint16_t le16_to_cpupu(const uint16_t *p)
{
const uint8_t *p1 = (const uint8_t *)p;
return p1[0] | (p1[1] << 8);
}
static inline uint32_t le32_to_cpupu(const uint32_t *p)
{
const uint8_t *p1 = (const uint8_t *)p;
return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24);
}
static inline void cpu_to_be16wu(uint16_t *p, uint16_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v >> 8;
p1[1] = v;
}
static inline void cpu_to_be32wu(uint32_t *p, uint32_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v >> 24;
p1[1] = v >> 16;
p1[2] = v >> 8;
p1[3] = v;
}
#endif
#ifdef WORDS_BIGENDIAN
#define cpu_to_32wu cpu_to_be32wu
#else
#define cpu_to_32wu cpu_to_le32wu
#endif
#undef le_bswap
#undef be_bswap
#undef le_bswaps
#undef be_bswaps
#endif /* BSWAP_H */
-614
View File
@@ -1,614 +0,0 @@
/*
* QEMU Cocoa display driver
*
* Copyright (c) 2005 Pierre d'Herbemont
* many code/inspiration from SDL 1.2 code (LGPL)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/*
Todo : x miniaturize window
x center the window
- save window position
- handle keyboard event
- handle mouse event
- non 32 bpp support
- full screen
- mouse focus
x simple graphical prompt to demo
- better graphical prompt
*/
#import <Cocoa/Cocoa.h>
#include "vl.h"
NSWindow *window = NULL;
NSQuickDrawView *qd_view = NULL;
int gArgc;
char **gArgv;
DisplayState current_ds;
/* main defined in qemu/vl.c */
int qemu_main(int argc, char **argv);
/* To deal with miniaturization */
@interface QemuWindow : NSWindow
{ }
@end
/*
------------------------------------------------------
Qemu Video Driver
------------------------------------------------------
*/
/*
------------------------------------------------------
cocoa_update
------------------------------------------------------
*/
static void cocoa_update(DisplayState *ds, int x, int y, int w, int h)
{
//printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
/* Use QDFlushPortBuffer() to flush content to display */
RgnHandle dirty = NewRgn ();
RgnHandle temp = NewRgn ();
SetEmptyRgn (dirty);
/* Build the region of dirty rectangles */
MacSetRectRgn (temp, x, y,
x + w, y + h);
MacUnionRgn (dirty, temp, dirty);
/* Flush the dirty region */
QDFlushPortBuffer ( [ qd_view qdPort ], dirty );
DisposeRgn (dirty);
DisposeRgn (temp);
}
/*
------------------------------------------------------
cocoa_resize
------------------------------------------------------
*/
static void cocoa_resize(DisplayState *ds, int w, int h)
{
const int device_bpp = 32;
static void *screen_pixels;
static int screen_pitch;
NSRect contentRect;
//printf("resizing to %d %d\n", w, h);
contentRect = NSMakeRect (0, 0, w, h);
if(window)
{
[window close];
[window release];
}
window = [ [ QemuWindow alloc ] initWithContentRect:contentRect
styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask
backing:NSBackingStoreBuffered defer:NO];
if(!window)
{
fprintf(stderr, "(cocoa) can't create window\n");
exit(1);
}
if(qd_view)
[qd_view release];
qd_view = [ [ NSQuickDrawView alloc ] initWithFrame:contentRect ];
if(!qd_view)
{
fprintf(stderr, "(cocoa) can't create qd_view\n");
exit(1);
}
[ window setAcceptsMouseMovedEvents:YES ];
[ window setTitle:@"Qemu" ];
[ window setReleasedWhenClosed:NO ];
/* Set screen to black */
[ window setBackgroundColor: [NSColor blackColor] ];
/* set window position */
[ window center ];
[ qd_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
[ [ window contentView ] addSubview:qd_view ];
[ qd_view release ];
[ window makeKeyAndOrderFront:nil ];
/* Careful here, the window seems to have to be onscreen to do that */
LockPortBits ( [ qd_view qdPort ] );
screen_pixels = GetPixBaseAddr ( GetPortPixMap ( [ qd_view qdPort ] ) );
screen_pitch = GetPixRowBytes ( GetPortPixMap ( [ qd_view qdPort ] ) );
UnlockPortBits ( [ qd_view qdPort ] );
{
int vOffset = [ window frame ].size.height -
[ qd_view frame ].size.height - [ qd_view frame ].origin.y;
int hOffset = [ qd_view frame ].origin.x;
screen_pixels += (vOffset * screen_pitch) + hOffset * (device_bpp/8);
}
ds->data = screen_pixels;
ds->linesize = screen_pitch;
ds->depth = device_bpp;
ds->width = w;
ds->height = h;
current_ds = *ds;
}
/*
------------------------------------------------------
keymap conversion
------------------------------------------------------
*/
static int keymap[] =
{
30, //'a' 0x0
31, //'s'
32, //'d'
33, //'f'
35, //'h'
34, //'g'
44, //'z'
45, //'x'
46, //'c'
47, //'v'
0, // 0 0x0a
48, //'b'
16, //'q'
17, //'w'
18, //'e'
19, //'r'
21, //'y' 0x10
20, //'t'
2, //'1'
3, //'2'
4, //'3'
5, //'4'
7, //'6'
6, //'5'
0, //'='
10, //'9'
8, //'7' 0x1A
0, //'-'
9, //'8'
11, //'0'
27, //']'
24, //'o'
22, //'u' 0x20
26, //'['
23, //'i'
25, //'p'
28, //'\n'
38, //'l'
36, //'j'
40, //'"'
37, //'k'
39, //';'
15, //'\t' 0x30
0, //' '
0, //'`'
14, //'<backspace>'
0, //'' 0x34
0, //'<esc>'
0, //'<esc>'
/* Not completed to finish see http://www.libsdl.org/cgi/cvsweb.cgi/SDL12/src/video/quartz/SDL_QuartzKeys.h?rev=1.6&content-type=text/x-cvsweb-markup */
};
static int cocoa_keycode_to_qemu(int keycode)
{
if(sizeof(keymap) <= keycode)
{
printf("(cocoa) warning unknow keycode 0x%x\n", keycode);
return 0;
}
return keymap[keycode];
}
/*
------------------------------------------------------
cocoa_refresh
------------------------------------------------------
*/
static void cocoa_refresh(DisplayState *ds)
{
//printf("cocoa_refresh \n");
NSDate *distantPast;
NSEvent *event;
NSAutoreleasePool *pool;
int grab = 1;
pool = [ [ NSAutoreleasePool alloc ] init ];
distantPast = [ NSDate distantPast ];
if (is_active_console(vga_console))
vga_update_display();
do {
event = [ NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
inMode: NSDefaultRunLoopMode dequeue:YES ];
if (event != nil) {
switch ([event type]) {
case NSKeyDown:
if(grab)
{
int keycode = cocoa_keycode_to_qemu([event keyCode]);
if (keycode & 0x80)
kbd_put_keycode(0xe0);
kbd_put_keycode(keycode & 0x7f);
}
break;
case NSKeyUp:
if(grab)
{
int keycode = cocoa_keycode_to_qemu([event keyCode]);
if (keycode & 0x80)
kbd_put_keycode(0xe0);
kbd_put_keycode(keycode | 0x80);
}
break;
case NSScrollWheel:
case NSLeftMouseDown:
case NSLeftMouseUp:
case NSOtherMouseDown:
case NSRightMouseDown:
case NSOtherMouseUp:
case NSRightMouseUp:
case NSMouseMoved:
case NSOtherMouseDragged:
case NSRightMouseDragged:
case NSLeftMouseDragged:
default: [NSApp sendEvent:event];
}
}
} while(event != nil);
}
/*
------------------------------------------------------
cocoa_cleanup
------------------------------------------------------
*/
static void cocoa_cleanup(void)
{
}
/*
------------------------------------------------------
cocoa_display_init
------------------------------------------------------
*/
void cocoa_display_init(DisplayState *ds, int full_screen)
{
ds->dpy_update = cocoa_update;
ds->dpy_resize = cocoa_resize;
ds->dpy_refresh = cocoa_refresh;
cocoa_resize(ds, 640, 400);
atexit(cocoa_cleanup);
}
/*
------------------------------------------------------
Interface with Cocoa
------------------------------------------------------
*/
/*
------------------------------------------------------
QemuWindow
Some trick from SDL to use miniwindow
------------------------------------------------------
*/
static void QZ_SetPortAlphaOpaque ()
{
/* Assume 32 bit if( bpp == 32 )*/
if ( 1 ) {
uint32_t *pixels = (uint32_t*) current_ds.data;
uint32_t rowPixels = current_ds.linesize / 4;
uint32_t i, j;
for (i = 0; i < current_ds.height; i++)
for (j = 0; j < current_ds.width; j++) {
pixels[ (i * rowPixels) + j ] |= 0xFF000000;
}
}
}
@implementation QemuWindow
- (void)miniaturize:(id)sender
{
/* make the alpha channel opaque so anim won't have holes in it */
QZ_SetPortAlphaOpaque ();
[ super miniaturize:sender ];
}
- (void)display
{
/*
This method fires just before the window deminaturizes from the Dock.
We'll save the current visible surface, let the window manager redraw any
UI elements, and restore the SDL surface. This way, no expose event
is required, and the deminiaturize works perfectly.
*/
/* make sure pixels are fully opaque */
QZ_SetPortAlphaOpaque ();
/* save current visible SDL surface */
[ self cacheImageInRect:[ qd_view frame ] ];
/* let the window manager redraw controls, border, etc */
[ super display ];
/* restore visible SDL surface */
[ self restoreCachedImage ];
}
@end
/*
------------------------------------------------------
QemuCocoaGUIController
NSApp's delegate - indeed main object
------------------------------------------------------
*/
@interface QemuCocoaGUIController : NSObject
{
}
- (void)applicationDidFinishLaunching: (NSNotification *) note;
- (void)applicationWillTerminate:(NSNotification *)aNotification;
- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
- (void)startEmulationWithArgc:(int)argc argv:(char**)argv;
@end
@implementation QemuCocoaGUIController
/* Called when the internal event loop has just started running */
- (void)applicationDidFinishLaunching: (NSNotification *) note
{
/* Display an open dialog box if no argument were passed or
if qemu was launched from the finder ( the Finder passes "-psn" ) */
if( gArgc <= 1 || strncmp (gArgv[1], "-psn", 4) == 0)
{
NSOpenPanel *op = [[NSOpenPanel alloc] init];
cocoa_resize(&current_ds, 640, 400);
[op setPrompt:@"Boot image"];
[op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"];
[op beginSheetForDirectory:nil file:nil types:[NSArray arrayWithObjects:@"img",@"iso",@"dmg",@"qcow",@"cow",@"cloop",@"vmdk",nil]
modalForWindow:window modalDelegate:self
didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
}
else
{
/* or Launch Qemu, with the global args */
[self startEmulationWithArgc:gArgc argv:gArgv];
}
}
- (void)applicationWillTerminate:(NSNotification *)aNotification
{
printf("Application will terminate\n");
qemu_system_shutdown_request();
/* In order to avoid a crash */
exit(0);
}
- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
if(returnCode == NSCancelButton)
{
exit(0);
}
if(returnCode == NSOKButton)
{
char *bin = "qemu";
char *img = (char*)[ [ sheet filename ] cString];
char **argv = (char**)malloc( sizeof(char*)*3 );
asprintf(&argv[0], "%s", bin);
asprintf(&argv[1], "-hda");
asprintf(&argv[2], "%s", img);
printf("Using argc %d argv %s -hda %s\n", 3, bin, img);
[self startEmulationWithArgc:3 argv:(char**)argv];
}
}
- (void)startEmulationWithArgc:(int)argc argv:(char**)argv
{
int status;
/* Launch Qemu */
printf("starting qemu...\n");
status = qemu_main (argc, argv);
exit(status);
}
@end
/*
------------------------------------------------------
Application Creation
------------------------------------------------------
*/
/* Dock Connection */
typedef struct CPSProcessSerNum
{
UInt32 lo;
UInt32 hi;
} CPSProcessSerNum;
extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
/* Menu Creation */
static void setApplicationMenu(void)
{
/* warning: this code is very odd */
NSMenu *appleMenu;
NSMenuItem *menuItem;
NSString *title;
NSString *appName;
appName = @"Qemu";
appleMenu = [[NSMenu alloc] initWithTitle:@""];
/* Add menu items */
title = [@"About " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
[appleMenu addItem:[NSMenuItem separatorItem]];
title = [@"Hide " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
[menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
[appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
[appleMenu addItem:[NSMenuItem separatorItem]];
title = [@"Quit " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
/* Put menu into the menubar */
menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
[menuItem setSubmenu:appleMenu];
[[NSApp mainMenu] addItem:menuItem];
/* Tell the application object that this is now the application menu */
[NSApp setAppleMenu:appleMenu];
/* Finally give up our references to the objects */
[appleMenu release];
[menuItem release];
}
/* Create a window menu */
static void setupWindowMenu(void)
{
NSMenu *windowMenu;
NSMenuItem *windowMenuItem;
NSMenuItem *menuItem;
windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
/* "Minimize" item */
menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
[windowMenu addItem:menuItem];
[menuItem release];
/* Put menu into the menubar */
windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
[windowMenuItem setSubmenu:windowMenu];
[[NSApp mainMenu] addItem:windowMenuItem];
/* Tell the application object that this is now the window menu */
[NSApp setWindowsMenu:windowMenu];
/* Finally give up our references to the objects */
[windowMenu release];
[windowMenuItem release];
}
static void CustomApplicationMain (argc, argv)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
QemuCocoaGUIController *gui_controller;
CPSProcessSerNum PSN;
[NSApplication sharedApplication];
if (!CPSGetCurrentProcess(&PSN))
if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
if (!CPSSetFrontProcess(&PSN))
[NSApplication sharedApplication];
/* Set up the menubar */
[NSApp setMainMenu:[[NSMenu alloc] init]];
setApplicationMenu();
setupWindowMenu();
/* Create SDLMain and make it the app delegate */
gui_controller = [[QemuCocoaGUIController alloc] init];
[NSApp setDelegate:gui_controller];
/* Start the main event loop */
[NSApp run];
[gui_controller release];
[pool release];
}
/* Real main of qemu-cocoa */
int main(int argc, char **argv)
{
gArgc = argc;
gArgv = argv;
CustomApplicationMain (argc, argv);
return 0;
}
Vendored
-761
View File
@@ -1,761 +0,0 @@
#!/bin/sh
#
# qemu configure script (c) 2003 Fabrice Bellard
#
# set temporary file name
if test ! -z "$TMPDIR" ; then
TMPDIR1="${TMPDIR}"
elif test ! -z "$TEMPDIR" ; then
TMPDIR1="${TEMPDIR}"
else
TMPDIR1="/tmp"
fi
TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c"
TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o"
TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}"
TMPS="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.S"
# default parameters
prefix=""
interp_prefix="/usr/gnemul/qemu-%M"
static="no"
cross_prefix=""
cc="gcc"
host_cc="gcc"
ar="ar"
make="make"
strip="strip"
cpu=`uname -m`
target_list=""
case "$cpu" in
i386|i486|i586|i686|i86pc|BePC)
cpu="i386"
;;
armv*b)
cpu="armv4b"
;;
armv*l)
cpu="armv4l"
;;
alpha)
cpu="alpha"
;;
"Power Macintosh"|ppc|ppc64)
cpu="powerpc"
;;
mips)
cpu="mips"
;;
s390)
cpu="s390"
;;
sparc)
cpu="sparc"
;;
sparc64)
cpu="sparc64"
;;
ia64)
cpu="ia64"
;;
m68k)
cpu="m68k"
;;
x86_64|amd64)
cpu="x86_64"
;;
*)
cpu="unknown"
;;
esac
gprof="no"
bigendian="no"
mingw32="no"
EXESUF=""
gdbstub="yes"
slirp="yes"
adlib="no"
oss="no"
fmod="no"
fmod_lib=""
fmod_inc=""
linux="no"
kqemu="no"
kernel_path=""
cocoa="no"
check_gfx="yes"
# OS specific
targetos=`uname -s`
case $targetos in
CYGWIN*)
mingw32="yes"
CFLAGS="-O2 -mno-cygwin"
;;
MINGW32*)
mingw32="yes"
;;
FreeBSD)
bsd="yes"
oss="yes"
if [ "$cpu" = "i386" ] ; then
kqemu="yes"
fi
;;
NetBSD)
bsd="yes"
oss="yes"
;;
OpenBSD)
bsd="yes"
oss="yes"
;;
Darwin)
bsd="yes"
darwin="yes"
;;
*)
oss="yes"
linux="yes"
if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
kqemu="yes"
fi
;;
esac
if [ "$bsd" = "yes" ] ; then
if [ ! "$darwin" = "yes" ] ; then
make="gmake"
fi
fi
# find source path
# XXX: we assume an absolute path is given when launching configure,
# except in './configure' case.
source_path=${0%configure}
source_path=${source_path%/}
source_path_used="yes"
if test -z "$source_path" -o "$source_path" = "." ; then
source_path=`pwd`
source_path_used="no"
fi
for opt do
case "$opt" in
--prefix=*) prefix=`echo $opt | cut -d '=' -f 2`
;;
--interp-prefix=*) interp_prefix=`echo $opt | cut -d '=' -f 2`
;;
--source-path=*) source_path=`echo $opt | cut -d '=' -f 2`
;;
--cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2`
;;
--cc=*) cc=`echo $opt | cut -d '=' -f 2`
;;
--host-cc=*) host_cc=`echo $opt | cut -d '=' -f 2`
;;
--make=*) make=`echo $opt | cut -d '=' -f 2`
;;
--extra-cflags=*) CFLAGS="${opt#--extra-cflags=}"
;;
--extra-ldflags=*) LDFLAGS="${opt#--extra-ldflags=}"
;;
--cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
;;
--target-list=*) target_list=${opt#--target-list=}
;;
--enable-gprof) gprof="yes"
;;
--static) static="yes"
;;
--disable-sdl) sdl="no"
;;
--enable-fmod) fmod="yes"
;;
--fmod-lib=*) fmod_lib=${opt#--fmod-lib=}
;;
--fmod-inc=*) fmod_inc=${opt#--fmod-inc=}
;;
--enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-"
;;
--disable-slirp) slirp="no"
;;
--enable-adlib) adlib="yes"
;;
--disable-kqemu) kqemu="no"
;;
--kernel-path=*) kernel_path=${opt#--kernel-path=}
;;
--enable-cocoa) cocoa="yes" ; sdl="no"
;;
--disable-gfx-check) check_gfx="no"
;;
esac
done
# Checking for CFLAGS
if test -z "$CFLAGS"; then
CFLAGS="-O2"
fi
cc="${cross_prefix}${cc}"
ar="${cross_prefix}${ar}"
strip="${cross_prefix}${strip}"
if test "$mingw32" = "yes" ; then
linux="no"
EXESUF=".exe"
gdbstub="no"
oss="no"
if [ "$cpu" = "i386" ] ; then
kqemu="yes"
fi
fi
if test -z "$target_list" ; then
# these targets are portable
target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu"
# the following are Linux specific
if [ "$linux" = "yes" ] ; then
target_list="i386-user arm-user armeb-user sparc-user ppc-user $target_list"
fi
else
target_list=$(echo "$target_list" | sed -e 's/,/ /g')
fi
if test -z "$cross_prefix" ; then
# ---
# big/little endian test
cat > $TMPC << EOF
#include <inttypes.h>
int main(int argc, char ** argv){
volatile uint32_t i=0x01234567;
return (*((uint8_t*)(&i))) == 0x67;
}
EOF
if $cc -o $TMPE $TMPC 2>/dev/null ; then
$TMPE && bigendian="yes"
else
echo big/little test failed
fi
else
# if cross compiling, cannot launch a program, so make a static guess
if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k" -o "$cpu" = "armv4b"; then
bigendian="yes"
fi
fi
# host long bits test
hostlongbits="32"
if test "$cpu" = "sparc64" -o "$cpu" = "ia64" -o "$cpu" = "x86_64" -o "$cpu" = "alpha"; then
hostlongbits="64"
fi
# check gcc options support
cat > $TMPC <<EOF
int main(void) {
}
EOF
have_gcc3_options="no"
if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/null ; then
have_gcc3_options="yes"
fi
##########################################
# SDL probe
sdl_too_old=no
if test -z "$sdl" ; then
sdl_config="sdl-config"
sdl=no
sdl_static=no
if test "$mingw32" = "yes" -a ! -z "$cross_prefix" ; then
# win32 cross compilation case
sdl_config="i386-mingw32msvc-sdl-config"
sdl=yes
else
# normal SDL probe
cat > $TMPC << EOF
#include <SDL.h>
#undef main /* We don't want SDL to override our main() */
int main( void ) { return SDL_Init (SDL_INIT_VIDEO); }
EOF
if $cc -o $TMPE `$sdl_config --cflags 2> /dev/null` $TMPC `$sdl_config --libs 2> /dev/null` 2> /dev/null ; then
_sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'`
if test "$_sdlversion" -lt 121 ; then
sdl_too_old=yes
else
sdl=yes
fi
# static link with sdl ?
if test "$sdl" = "yes" ; then
aa="no"
`$sdl_config --static-libs | grep \\\-laa > /dev/null` && aa="yes"
sdl_static_libs=`$sdl_config --static-libs`
if [ "$aa" = "yes" ] ; then
sdl_static_libs="$sdl_static_libs `aalib-config --static-libs`"
fi
if $cc -o $TMPE `$sdl_config --cflags 2> /dev/null` $TMPC $sdl_static_libs 2> /dev/null; then
sdl_static=yes
fi
fi # static link
fi # sdl compile test
fi # cross compilation
fi # -z $sdl
if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
cat << EOF
Usage: configure [options]
Options: [defaults in brackets after descriptions]
EOF
echo "Standard options:"
echo " --help print this message"
echo " --prefix=PREFIX install in PREFIX [$prefix]"
echo " --interp-prefix=PREFIX where to find shared libraries, etc."
echo " use %M for cpu name [$interp_prefix]"
echo " --target-list=LIST set target list [$target_list]"
echo ""
echo "kqemu kernel acceleration support:"
echo " --disable-kqemu disable kqemu build"
echo " --kernel-path=PATH set the kernel path (configure probes it)"
echo ""
echo "Advanced options (experts only):"
echo " --source-path=PATH path of source code [$source_path]"
echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]"
echo " --cc=CC use C compiler CC [$cc]"
echo " --host-cc=CC use C compiler CC [$cc] for dyngen etc."
echo " --make=MAKE use specified make [$make]"
echo " --static enable static build [$static]"
echo " --enable-mingw32 enable Win32 cross compilation with mingw32"
echo " --enable-adlib enable Adlib emulation"
echo " --enable-fmod enable FMOD audio output driver"
echo " --fmod-lib path to FMOD library"
echo " --fmod-inc path to FMOD includes"
echo ""
echo "NOTE: The object files are build at the place where configure is launched"
exit 1
fi
if test "$mingw32" = "yes" ; then
if test -z "$prefix" ; then
prefix="/c/Program Files/Qemu"
fi
mandir="$prefix"
datadir="$prefix"
docdir="$prefix"
bindir="$prefix"
else
if test -z "$prefix" ; then
prefix="/usr/local"
fi
mandir="$prefix/share/man"
datadir="$prefix/share/qemu"
docdir="$prefix/share/doc/qemu"
bindir="$prefix/bin"
fi
# kqemu support
if test $kqemu = "yes" ; then
# test if the source code is installed
if test '!' -f "kqemu/Makefile" ; then
kqemu="no"
fi
fi
# Linux specific kqemu configuration
if test $kqemu = "yes" -a $linux = "yes" ; then
# find the kernel path
if test -z "$kernel_path" ; then
kernel_version=`uname -r`
kernel_path="/lib/modules/$kernel_version/build"
if test '!' -d "$kernel_path/include" ; then
kernel_path="/usr/src/linux"
if test '!' -d "$kernel_path/include" ; then
echo "Could not find kernel includes in /lib/modules or /usr/src/linux - cannot build the kqemu module"
kqemu="no"
fi
fi
fi
if test $kqemu = "yes" ; then
# test that the kernel config is present
if test '!' -f "$kernel_path/Makefile" ; then
echo "No Makefile file present in $kernel_path - kqemu cannot be built"
kqemu="no"
fi
# find build system (2.6 or legacy)
kbuild26="yes"
if grep -q "PATCHLEVEL = 4" $kernel_path/Makefile ; then
kbuild26="no"
fi
fi # kqemu
fi # kqemu and linux
echo "Install prefix $prefix"
echo "BIOS directory $datadir"
echo "binary directory $bindir"
if test "$mingw32" = "no" ; then
echo "Manual directory $mandir"
echo "ELF interp prefix $interp_prefix"
fi
echo "Source path $source_path"
echo "C compiler $cc"
echo "Host C compiler $host_cc"
echo "make $make"
echo "host CPU $cpu"
echo "host big endian $bigendian"
echo "target list $target_list"
echo "gprof enabled $gprof"
echo "static build $static"
if test "$darwin" = "yes" ; then
echo "Cocoa support $cocoa"
fi
echo "SDL support $sdl"
if test "$sdl" != "no" ; then
echo "SDL static link $sdl_static"
fi
echo "mingw32 support $mingw32"
echo "Adlib support $adlib"
echo -n "FMOD support $fmod"
if test $fmod = "yes"; then
echo -n " (lib='$fmod_lib' include='$fmod_inc')"
fi
echo ""
echo "kqemu support $kqemu"
if test $kqemu = "yes" -a $linux = "yes" ; then
echo ""
echo "KQEMU Linux module configuration:"
echo "kernel sources $kernel_path"
echo -n "kbuild type "
if test $kbuild26 = "yes"; then
echo "2.6"
else
echo "2.4"
fi
fi
if test $sdl_too_old = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
fi
#if test "$sdl_static" = "no"; then
# echo "WARNING: cannot compile statically with SDL - qemu-fast won't have a graphical output"
#fi
config_mak="config-host.mak"
config_h="config-host.h"
#echo "Creating $config_mak and $config_h"
echo "# Automatically generated by configure - do not modify" > $config_mak
echo "/* Automatically generated by configure - do not modify */" > $config_h
echo "prefix=$prefix" >> $config_mak
echo "bindir=$bindir" >> $config_mak
echo "mandir=$mandir" >> $config_mak
echo "datadir=$datadir" >> $config_mak
echo "docdir=$docdir" >> $config_mak
echo "#define CONFIG_QEMU_SHAREDIR \"$datadir\"" >> $config_h
echo "MAKE=$make" >> $config_mak
echo "CC=$cc" >> $config_mak
if test "$have_gcc3_options" = "yes" ; then
echo "HAVE_GCC3_OPTIONS=yes" >> $config_mak
fi
echo "HOST_CC=$host_cc" >> $config_mak
echo "AR=$ar" >> $config_mak
echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak
echo "CFLAGS=$CFLAGS" >> $config_mak
echo "LDFLAGS=$LDFLAGS" >> $config_mak
echo "EXESUF=$EXESUF" >> $config_mak
if test "$cpu" = "i386" ; then
echo "ARCH=i386" >> $config_mak
echo "#define HOST_I386 1" >> $config_h
elif test "$cpu" = "x86_64" ; then
echo "ARCH=x86_64" >> $config_mak
echo "#define HOST_X86_64 1" >> $config_h
elif test "$cpu" = "armv4b" ; then
echo "ARCH=arm" >> $config_mak
echo "#define HOST_ARM 1" >> $config_h
elif test "$cpu" = "armv4l" ; then
echo "ARCH=arm" >> $config_mak
echo "#define HOST_ARM 1" >> $config_h
elif test "$cpu" = "powerpc" ; then
echo "ARCH=ppc" >> $config_mak
echo "#define HOST_PPC 1" >> $config_h
elif test "$cpu" = "mips" ; then
echo "ARCH=mips" >> $config_mak
echo "#define HOST_MIPS 1" >> $config_h
elif test "$cpu" = "s390" ; then
echo "ARCH=s390" >> $config_mak
echo "#define HOST_S390 1" >> $config_h
elif test "$cpu" = "alpha" ; then
echo "ARCH=alpha" >> $config_mak
echo "#define HOST_ALPHA 1" >> $config_h
elif test "$cpu" = "sparc" ; then
echo "ARCH=sparc" >> $config_mak
echo "#define HOST_SPARC 1" >> $config_h
elif test "$cpu" = "sparc64" ; then
echo "ARCH=sparc64" >> $config_mak
echo "#define HOST_SPARC64 1" >> $config_h
elif test "$cpu" = "ia64" ; then
echo "ARCH=ia64" >> $config_mak
echo "#define HOST_IA64 1" >> $config_h
elif test "$cpu" = "m68k" ; then
echo "ARCH=m68k" >> $config_mak
echo "#define HOST_M68K 1" >> $config_h
else
echo "Unsupported CPU"
exit 1
fi
if test "$bigendian" = "yes" ; then
echo "WORDS_BIGENDIAN=yes" >> $config_mak
echo "#define WORDS_BIGENDIAN 1" >> $config_h
fi
echo "#define HOST_LONG_BITS $hostlongbits" >> $config_h
if test "$mingw32" = "yes" ; then
echo "CONFIG_WIN32=yes" >> $config_mak
echo "#define CONFIG_WIN32 1" >> $config_h
elif test -f "/usr/include/byteswap.h" ; then
echo "#define HAVE_BYTESWAP_H 1" >> $config_h
fi
if test "$darwin" = "yes" ; then
echo "CONFIG_DARWIN=yes" >> $config_mak
echo "#define CONFIG_DARWIN 1" >> $config_h
fi
if test "$gdbstub" = "yes" ; then
echo "CONFIG_GDBSTUB=yes" >> $config_mak
echo "#define CONFIG_GDBSTUB 1" >> $config_h
fi
if test "$gprof" = "yes" ; then
echo "TARGET_GPROF=yes" >> $config_mak
echo "#define HAVE_GPROF 1" >> $config_h
fi
if test "$static" = "yes" ; then
echo "CONFIG_STATIC=yes" >> $config_mak
echo "#define CONFIG_STATIC 1" >> $config_h
fi
if test "$slirp" = "yes" ; then
echo "CONFIG_SLIRP=yes" >> $config_mak
echo "#define CONFIG_SLIRP 1" >> $config_h
fi
if test "$adlib" = "yes" ; then
echo "CONFIG_ADLIB=yes" >> $config_mak
echo "#define CONFIG_ADLIB 1" >> $config_h
fi
if test "$oss" = "yes" ; then
echo "CONFIG_OSS=yes" >> $config_mak
echo "#define CONFIG_OSS 1" >> $config_h
fi
if test "$fmod" = "yes" ; then
echo "CONFIG_FMOD=yes" >> $config_mak
echo "CONFIG_FMOD_LIB=$fmod_lib" >> $config_mak
echo "CONFIG_FMOD_INC=$fmod_inc" >> $config_mak
echo "#define CONFIG_FMOD 1" >> $config_h
fi
echo -n "VERSION=" >>$config_mak
head $source_path/VERSION >>$config_mak
echo "" >>$config_mak
echo -n "#define QEMU_VERSION \"" >> $config_h
head $source_path/VERSION >> $config_h
echo "\"" >> $config_h
if test $kqemu = "yes" ; then
echo "CONFIG_KQEMU=yes" >> $config_mak
if test $linux = "yes" ; then
echo "KERNEL_PATH=$kernel_path" >> $config_mak
if test $kbuild26 = "yes" ; then
echo "CONFIG_KBUILD26=yes" >> $config_mak
fi
fi
fi
echo "SRC_PATH=$source_path" >> $config_mak
echo "TARGET_DIRS=$target_list" >> $config_mak
# XXX: suppress that
if [ "$bsd" = "yes" ] ; then
echo "#define O_LARGEFILE 0" >> $config_h
echo "#define MAP_ANONYMOUS MAP_ANON" >> $config_h
echo "#define _BSD 1" >> $config_h
fi
for target in $target_list; do
target_dir="$target"
config_mak=$target_dir/config.mak
config_h=$target_dir/config.h
target_cpu=`echo $target | cut -d '-' -f 1`
target_bigendian="no"
[ "$target_cpu" = "armeb" ] && target_bigendian=yes
[ "$target_cpu" = "sparc" ] && target_bigendian=yes
[ "$target_cpu" = "sparc64" ] && target_bigendian=yes
[ "$target_cpu" = "ppc" ] && target_bigendian=yes
[ "$target_cpu" = "ppc64" ] && target_bigendian=yes
[ "$target_cpu" = "mips" ] && target_bigendian=yes
target_softmmu="no"
if expr $target : '.*-softmmu' > /dev/null ; then
target_softmmu="yes"
fi
target_user_only="no"
if expr $target : '.*-user' > /dev/null ; then
target_user_only="yes"
fi
if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \
-a "$sdl" = "no" -a "$cocoa" = "no" ; then
echo "ERROR: QEMU requires SDL or Cocoa for graphical output"
echo "To build QEMU with graphical output configure with --disable-gfx-check"
echo "Note that this will disable all output from the virtual graphics card."
exit 1;
fi
#echo "Creating $config_mak, $config_h and $target_dir/Makefile"
mkdir -p $target_dir
mkdir -p $target_dir/fpu
if test "$target" = "arm-user" -o "$target" = "armeb-user" ; then
mkdir -p $target_dir/nwfpe
fi
if test "$target_user_only" = "no" ; then
mkdir -p $target_dir/slirp
fi
ln -sf $source_path/Makefile.target $target_dir/Makefile
echo "# Automatically generated by configure - do not modify" > $config_mak
echo "/* Automatically generated by configure - do not modify */" > $config_h
echo "include ../config-host.mak" >> $config_mak
echo "#include \"../config-host.h\"" >> $config_h
interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"`
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h
if test "$target_cpu" = "i386" ; then
echo "TARGET_ARCH=i386" >> $config_mak
echo "#define TARGET_ARCH \"i386\"" >> $config_h
echo "#define TARGET_I386 1" >> $config_h
if test $kqemu = "yes" -a "$target_softmmu" = "yes" -a $cpu = "i386" ; then
echo "#define USE_KQEMU 1" >> $config_h
fi
elif test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then
echo "TARGET_ARCH=arm" >> $config_mak
echo "#define TARGET_ARCH \"arm\"" >> $config_h
echo "#define TARGET_ARM 1" >> $config_h
elif test "$target_cpu" = "sparc" ; then
echo "TARGET_ARCH=sparc" >> $config_mak
echo "#define TARGET_ARCH \"sparc\"" >> $config_h
echo "#define TARGET_SPARC 1" >> $config_h
elif test "$target_cpu" = "sparc64" ; then
echo "TARGET_ARCH=sparc64" >> $config_mak
echo "#define TARGET_ARCH \"sparc64\"" >> $config_h
echo "#define TARGET_SPARC 1" >> $config_h
echo "#define TARGET_SPARC64 1" >> $config_h
elif test "$target_cpu" = "ppc" ; then
echo "TARGET_ARCH=ppc" >> $config_mak
echo "#define TARGET_ARCH \"ppc\"" >> $config_h
echo "#define TARGET_PPC 1" >> $config_h
elif test "$target_cpu" = "ppc64" ; then
echo "TARGET_ARCH=ppc64" >> $config_mak
echo "#define TARGET_ARCH \"ppc64\"" >> $config_h
echo "#define TARGET_PPC 1" >> $config_h
echo "#define TARGET_PPC64 1" >> $config_h
elif test "$target_cpu" = "x86_64" ; then
echo "TARGET_ARCH=x86_64" >> $config_mak
echo "#define TARGET_ARCH \"x86_64\"" >> $config_h
echo "#define TARGET_I386 1" >> $config_h
echo "#define TARGET_X86_64 1" >> $config_h
if test $kqemu = "yes" -a "$target_softmmu" = "yes" -a $cpu = "x86_64" ; then
echo "#define USE_KQEMU 1" >> $config_h
fi
elif test "$target_cpu" = "mips" ; then
echo "TARGET_ARCH=mips" >> $config_mak
echo "#define TARGET_ARCH \"mips\"" >> $config_h
echo "#define TARGET_MIPS 1" >> $config_h
else
echo "Unsupported target CPU"
exit 1
fi
if test "$target_bigendian" = "yes" ; then
echo "TARGET_WORDS_BIGENDIAN=yes" >> $config_mak
echo "#define TARGET_WORDS_BIGENDIAN 1" >> $config_h
fi
if test "$target_softmmu" = "yes" ; then
echo "CONFIG_SOFTMMU=yes" >> $config_mak
echo "#define CONFIG_SOFTMMU 1" >> $config_h
fi
if test "$target_user_only" = "yes" ; then
echo "CONFIG_USER_ONLY=yes" >> $config_mak
echo "#define CONFIG_USER_ONLY 1" >> $config_h
fi
if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then
echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
fi
# sdl defines
if test "$target_user_only" = "no"; then
if test "$target_softmmu" = "no" -o "$static" = "yes"; then
sdl1=$sdl_static
else
sdl1=$sdl
fi
if test "$sdl1" = "yes" ; then
echo "#define CONFIG_SDL 1" >> $config_h
echo "CONFIG_SDL=yes" >> $config_mak
if test "$target_softmmu" = "no" -o "$static" = "yes"; then
echo "SDL_LIBS=$sdl_static_libs" >> $config_mak
else
echo "SDL_LIBS=`$sdl_config --libs`" >> $config_mak
fi
echo -n "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak
if [ "${aa}" = "yes" ] ; then
echo -n " `aalib-config --cflags`" >> $config_mak ;
fi
echo "" >> $config_mak
fi
fi
if test "$cocoa" = "yes" ; then
echo "#define CONFIG_COCOA 1" >> $config_h
echo "CONFIG_COCOA=yes" >> $config_mak
fi
done # for target in $targets
# build tree in object directory if source path is different from current one
if test "$source_path_used" = "yes" ; then
DIRS="tests"
FILES="Makefile tests/Makefile"
for dir in $DIRS ; do
mkdir -p $dir
done
for f in $FILES ; do
ln -sf $source_path/$f $f
done
fi
rm -f $TMPO $TMPC $TMPE $TMPS
-731
View File
@@ -1,731 +0,0 @@
/*
* QEMU graphical console
*
* Copyright (c) 2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#define DEFAULT_BACKSCROLL 512
#define MAX_CONSOLES 12
#define RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
#define RGB(r, g, b) RGBA(r, g, b, 0xff)
typedef struct TextCell {
uint8_t ch;
uint8_t bgcol:4;
uint8_t fgcol:4;
} TextCell;
#define MAX_ESC_PARAMS 3
enum TTYState {
TTY_STATE_NORM,
TTY_STATE_ESC,
TTY_STATE_CSI,
};
struct TextConsole {
int text_console; /* true if text console */
DisplayState *ds;
int g_width, g_height;
int width;
int height;
int total_height;
int backscroll_height;
int fgcol;
int bgcol;
int x, y;
int y_displayed;
int y_base;
TextCell *cells;
enum TTYState state;
int esc_params[MAX_ESC_PARAMS];
int nb_esc_params;
/* kbd read handler */
IOReadHandler *fd_read;
void *fd_opaque;
};
static TextConsole *active_console;
static TextConsole *consoles[MAX_CONSOLES];
static int nb_consoles = 0;
/* convert a RGBA color to a color index usable in graphic primitives */
static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
{
unsigned int r, g, b, color;
switch(ds->depth) {
#if 0
case 8:
r = (rgba >> 16) & 0xff;
g = (rgba >> 8) & 0xff;
b = (rgba) & 0xff;
color = (rgb_to_index[r] * 6 * 6) +
(rgb_to_index[g] * 6) +
(rgb_to_index[b]);
break;
#endif
case 15:
r = (rgba >> 16) & 0xff;
g = (rgba >> 8) & 0xff;
b = (rgba) & 0xff;
color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
break;
case 16:
r = (rgba >> 16) & 0xff;
g = (rgba >> 8) & 0xff;
b = (rgba) & 0xff;
color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
break;
case 32:
default:
color = rgba;
break;
}
return color;
}
static void vga_fill_rect (DisplayState *ds,
int posx, int posy, int width, int height, uint32_t color)
{
uint8_t *d, *d1;
int x, y, bpp;
bpp = (ds->depth + 7) >> 3;
d1 = ds->data +
ds->linesize * posy + bpp * posx;
for (y = 0; y < height; y++) {
d = d1;
switch(bpp) {
case 1:
for (x = 0; x < width; x++) {
*((uint8_t *)d) = color;
d++;
}
break;
case 2:
for (x = 0; x < width; x++) {
*((uint16_t *)d) = color;
d += 2;
}
break;
case 4:
for (x = 0; x < width; x++) {
*((uint32_t *)d) = color;
d += 4;
}
break;
}
d1 += ds->linesize;
}
}
/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
{
const uint8_t *s;
uint8_t *d;
int wb, y, bpp;
bpp = (ds->depth + 7) >> 3;
wb = w * bpp;
if (yd <= ys) {
s = ds->data +
ds->linesize * ys + bpp * xs;
d = ds->data +
ds->linesize * yd + bpp * xd;
for (y = 0; y < h; y++) {
memmove(d, s, wb);
d += ds->linesize;
s += ds->linesize;
}
} else {
s = ds->data +
ds->linesize * (ys + h - 1) + bpp * xs;
d = ds->data +
ds->linesize * (yd + h - 1) + bpp * xd;
for (y = 0; y < h; y++) {
memmove(d, s, wb);
d -= ds->linesize;
s -= ds->linesize;
}
}
}
/***********************************************************/
/* basic char display */
#define FONT_HEIGHT 16
#define FONT_WIDTH 8
#include "vgafont.h"
#define cbswap_32(__x) \
((uint32_t)( \
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
#ifdef WORDS_BIGENDIAN
#define PAT(x) x
#else
#define PAT(x) cbswap_32(x)
#endif
static const uint32_t dmask16[16] = {
PAT(0x00000000),
PAT(0x000000ff),
PAT(0x0000ff00),
PAT(0x0000ffff),
PAT(0x00ff0000),
PAT(0x00ff00ff),
PAT(0x00ffff00),
PAT(0x00ffffff),
PAT(0xff000000),
PAT(0xff0000ff),
PAT(0xff00ff00),
PAT(0xff00ffff),
PAT(0xffff0000),
PAT(0xffff00ff),
PAT(0xffffff00),
PAT(0xffffffff),
};
static const uint32_t dmask4[4] = {
PAT(0x00000000),
PAT(0x0000ffff),
PAT(0xffff0000),
PAT(0xffffffff),
};
static uint32_t color_table[8];
static const uint32_t color_table_rgb[8] = {
RGB(0x00, 0x00, 0x00),
RGB(0xff, 0x00, 0x00),
RGB(0x00, 0xff, 0x00),
RGB(0xff, 0xff, 0x00),
RGB(0x00, 0x00, 0xff),
RGB(0xff, 0x00, 0xff),
RGB(0x00, 0xff, 0xff),
RGB(0xff, 0xff, 0xff),
};
static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
{
switch(ds->depth) {
case 8:
col |= col << 8;
col |= col << 16;
break;
case 15:
case 16:
col |= col << 16;
break;
default:
break;
}
return col;
}
static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
unsigned int fgcol, unsigned int bgcol)
{
uint8_t *d;
const uint8_t *font_ptr;
unsigned int font_data, linesize, xorcol, bpp;
int i;
bpp = (ds->depth + 7) >> 3;
d = ds->data +
ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
linesize = ds->linesize;
font_ptr = vgafont16 + FONT_HEIGHT * ch;
xorcol = bgcol ^ fgcol;
switch(ds->depth) {
case 8:
for(i = 0; i < FONT_HEIGHT; i++) {
font_data = *font_ptr++;
((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
d += linesize;
}
break;
case 16:
case 15:
for(i = 0; i < FONT_HEIGHT; i++) {
font_data = *font_ptr++;
((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
d += linesize;
}
break;
case 32:
for(i = 0; i < FONT_HEIGHT; i++) {
font_data = *font_ptr++;
((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
d += linesize;
}
break;
}
}
static void text_console_resize(TextConsole *s)
{
TextCell *cells, *c, *c1;
int w1, x, y, last_width;
last_width = s->width;
s->width = s->g_width / FONT_WIDTH;
s->height = s->g_height / FONT_HEIGHT;
w1 = last_width;
if (s->width < w1)
w1 = s->width;
cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
for(y = 0; y < s->total_height; y++) {
c = &cells[y * s->width];
if (w1 > 0) {
c1 = &s->cells[y * last_width];
for(x = 0; x < w1; x++) {
*c++ = *c1++;
}
}
for(x = w1; x < s->width; x++) {
c->ch = ' ';
c->fgcol = 7;
c->bgcol = 0;
c++;
}
}
free(s->cells);
s->cells = cells;
}
static void update_xy(TextConsole *s, int x, int y)
{
TextCell *c;
int y1, y2;
if (s == active_console) {
y1 = (s->y_base + y) % s->total_height;
y2 = y1 - s->y_displayed;
if (y2 < 0)
y2 += s->total_height;
if (y2 < s->height) {
c = &s->cells[y1 * s->width + x];
vga_putcharxy(s->ds, x, y2, c->ch,
color_table[c->fgcol], color_table[c->bgcol]);
dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
FONT_WIDTH, FONT_HEIGHT);
}
}
}
static void console_show_cursor(TextConsole *s, int show)
{
TextCell *c;
int y, y1;
if (s == active_console) {
y1 = (s->y_base + s->y) % s->total_height;
y = y1 - s->y_displayed;
if (y < 0)
y += s->total_height;
if (y < s->height) {
c = &s->cells[y1 * s->width + s->x];
if (show) {
vga_putcharxy(s->ds, s->x, y, c->ch,
color_table[0], color_table[7]);
} else {
vga_putcharxy(s->ds, s->x, y, c->ch,
color_table[c->fgcol], color_table[c->bgcol]);
}
dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT,
FONT_WIDTH, FONT_HEIGHT);
}
}
}
static void console_refresh(TextConsole *s)
{
TextCell *c;
int x, y, y1;
if (s != active_console)
return;
vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
color_table[0]);
y1 = s->y_displayed;
for(y = 0; y < s->height; y++) {
c = s->cells + y1 * s->width;
for(x = 0; x < s->width; x++) {
vga_putcharxy(s->ds, x, y, c->ch,
color_table[c->fgcol], color_table[c->bgcol]);
c++;
}
if (++y1 == s->total_height)
y1 = 0;
}
dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
console_show_cursor(s, 1);
}
static void console_scroll(int ydelta)
{
TextConsole *s;
int i, y1;
s = active_console;
if (!s || !s->text_console)
return;
if (ydelta > 0) {
for(i = 0; i < ydelta; i++) {
if (s->y_displayed == s->y_base)
break;
if (++s->y_displayed == s->total_height)
s->y_displayed = 0;
}
} else {
ydelta = -ydelta;
i = s->backscroll_height;
if (i > s->total_height - s->height)
i = s->total_height - s->height;
y1 = s->y_base - i;
if (y1 < 0)
y1 += s->total_height;
for(i = 0; i < ydelta; i++) {
if (s->y_displayed == y1)
break;
if (--s->y_displayed < 0)
s->y_displayed = s->total_height - 1;
}
}
console_refresh(s);
}
static void console_put_lf(TextConsole *s)
{
TextCell *c;
int x, y1;
s->x = 0;
s->y++;
if (s->y >= s->height) {
s->y = s->height - 1;
if (s->y_displayed == s->y_base) {
if (++s->y_displayed == s->total_height)
s->y_displayed = 0;
}
if (++s->y_base == s->total_height)
s->y_base = 0;
if (s->backscroll_height < s->total_height)
s->backscroll_height++;
y1 = (s->y_base + s->height - 1) % s->total_height;
c = &s->cells[y1 * s->width];
for(x = 0; x < s->width; x++) {
c->ch = ' ';
c->fgcol = s->fgcol;
c->bgcol = s->bgcol;
c++;
}
if (s == active_console && s->y_displayed == s->y_base) {
vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
s->width * FONT_WIDTH,
(s->height - 1) * FONT_HEIGHT);
vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
s->width * FONT_WIDTH, FONT_HEIGHT,
color_table[s->bgcol]);
dpy_update(s->ds, 0, 0,
s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
}
}
}
static void console_putchar(TextConsole *s, int ch)
{
TextCell *c;
int y1, i, x;
switch(s->state) {
case TTY_STATE_NORM:
switch(ch) {
case '\r':
s->x = 0;
break;
case '\n':
console_put_lf(s);
break;
case 27:
s->state = TTY_STATE_ESC;
break;
default:
y1 = (s->y_base + s->y) % s->total_height;
c = &s->cells[y1 * s->width + s->x];
c->ch = ch;
c->fgcol = s->fgcol;
c->bgcol = s->bgcol;
update_xy(s, s->x, s->y);
s->x++;
if (s->x >= s->width)
console_put_lf(s);
break;
}
break;
case TTY_STATE_ESC:
if (ch == '[') {
for(i=0;i<MAX_ESC_PARAMS;i++)
s->esc_params[i] = 0;
s->nb_esc_params = 0;
s->state = TTY_STATE_CSI;
} else {
s->state = TTY_STATE_NORM;
}
break;
case TTY_STATE_CSI:
if (ch >= '0' && ch <= '9') {
if (s->nb_esc_params < MAX_ESC_PARAMS) {
s->esc_params[s->nb_esc_params] =
s->esc_params[s->nb_esc_params] * 10 + ch - '0';
}
} else {
s->nb_esc_params++;
if (ch == ';')
break;
s->state = TTY_STATE_NORM;
switch(ch) {
case 'D':
if (s->x > 0)
s->x--;
break;
case 'C':
if (s->x < (s->width - 1))
s->x++;
break;
case 'K':
/* clear to eol */
y1 = (s->y_base + s->y) % s->total_height;
for(x = s->x; x < s->width; x++) {
c = &s->cells[y1 * s->width + x];
c->ch = ' ';
c->fgcol = s->fgcol;
c->bgcol = s->bgcol;
c++;
update_xy(s, x, s->y);
}
break;
default:
break;
}
break;
}
}
}
void console_select(unsigned int index)
{
TextConsole *s;
if (index >= MAX_CONSOLES)
return;
s = consoles[index];
if (s) {
active_console = s;
if (s->text_console) {
if (s->g_width != s->ds->width ||
s->g_height != s->ds->height) {
s->g_width = s->ds->width;
s->g_height = s->ds->height;
text_console_resize(s);
}
console_refresh(s);
}
}
}
static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
{
TextConsole *s = chr->opaque;
int i;
console_show_cursor(s, 0);
for(i = 0; i < len; i++) {
console_putchar(s, buf[i]);
}
console_show_cursor(s, 1);
return len;
}
static void console_chr_add_read_handler(CharDriverState *chr,
IOCanRWHandler *fd_can_read,
IOReadHandler *fd_read, void *opaque)
{
TextConsole *s = chr->opaque;
s->fd_read = fd_read;
s->fd_opaque = opaque;
}
static void console_send_event(CharDriverState *chr, int event)
{
TextConsole *s = chr->opaque;
int i;
if (event == CHR_EVENT_FOCUS) {
for(i = 0; i < nb_consoles; i++) {
if (consoles[i] == s) {
console_select(i);
break;
}
}
}
}
/* called when an ascii key is pressed */
void kbd_put_keysym(int keysym)
{
TextConsole *s;
uint8_t buf[16], *q;
int c;
s = active_console;
if (!s || !s->text_console)
return;
switch(keysym) {
case QEMU_KEY_CTRL_UP:
console_scroll(-1);
break;
case QEMU_KEY_CTRL_DOWN:
console_scroll(1);
break;
case QEMU_KEY_CTRL_PAGEUP:
console_scroll(-10);
break;
case QEMU_KEY_CTRL_PAGEDOWN:
console_scroll(10);
break;
default:
if (s->fd_read) {
/* convert the QEMU keysym to VT100 key string */
q = buf;
if (keysym >= 0xe100 && keysym <= 0xe11f) {
*q++ = '\033';
*q++ = '[';
c = keysym - 0xe100;
if (c >= 10)
*q++ = '0' + (c / 10);
*q++ = '0' + (c % 10);
*q++ = '~';
} else if (keysym >= 0xe120 && keysym <= 0xe17f) {
*q++ = '\033';
*q++ = '[';
*q++ = keysym & 0xff;
} else {
*q++ = keysym;
}
s->fd_read(s->fd_opaque, buf, q - buf);
}
break;
}
}
TextConsole *graphic_console_init(DisplayState *ds)
{
TextConsole *s;
if (nb_consoles >= MAX_CONSOLES)
return NULL;
s = qemu_mallocz(sizeof(TextConsole));
if (!s) {
return NULL;
}
if (!active_console)
active_console = s;
s->ds = ds;
consoles[nb_consoles++] = s;
return s;
}
int is_active_console(TextConsole *s)
{
return s == active_console;
}
CharDriverState *text_console_init(DisplayState *ds)
{
CharDriverState *chr;
TextConsole *s;
int i;
static int color_inited;
chr = qemu_mallocz(sizeof(CharDriverState));
if (!chr)
return NULL;
s = graphic_console_init(ds);
if (!s) {
free(chr);
return NULL;
}
s->text_console = 1;
chr->opaque = s;
chr->chr_write = console_puts;
chr->chr_add_read_handler = console_chr_add_read_handler;
chr->chr_send_event = console_send_event;
if (!color_inited) {
color_inited = 1;
for(i = 0; i < 8; i++) {
color_table[i] = col_expand(s->ds,
vga_get_color(s->ds, color_table_rgb[i]));
}
}
s->y_displayed = 0;
s->y_base = 0;
s->total_height = DEFAULT_BACKSCROLL;
s->x = 0;
s->y = 0;
s->fgcol = 7;
s->bgcol = 0;
s->g_width = s->ds->width;
s->g_height = s->ds->height;
text_console_resize(s);
return chr;
}
-771
View File
@@ -1,771 +0,0 @@
/*
* defines common to all virtual CPUs
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef CPU_ALL_H
#define CPU_ALL_H
#if defined(__arm__) || defined(__sparc__)
#define WORDS_ALIGNED
#endif
/* some important defines:
*
* WORDS_ALIGNED : if defined, the host cpu can only make word aligned
* memory accesses.
*
* WORDS_BIGENDIAN : if defined, the host cpu is big endian and
* otherwise little endian.
*
* (TARGET_WORDS_ALIGNED : same for target cpu (not supported yet))
*
* TARGET_WORDS_BIGENDIAN : same for target cpu
*/
#include "bswap.h"
#if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
#define BSWAP_NEEDED
#endif
#ifdef BSWAP_NEEDED
static inline uint16_t tswap16(uint16_t s)
{
return bswap16(s);
}
static inline uint32_t tswap32(uint32_t s)
{
return bswap32(s);
}
static inline uint64_t tswap64(uint64_t s)
{
return bswap64(s);
}
static inline void tswap16s(uint16_t *s)
{
*s = bswap16(*s);
}
static inline void tswap32s(uint32_t *s)
{
*s = bswap32(*s);
}
static inline void tswap64s(uint64_t *s)
{
*s = bswap64(*s);
}
#else
static inline uint16_t tswap16(uint16_t s)
{
return s;
}
static inline uint32_t tswap32(uint32_t s)
{
return s;
}
static inline uint64_t tswap64(uint64_t s)
{
return s;
}
static inline void tswap16s(uint16_t *s)
{
}
static inline void tswap32s(uint32_t *s)
{
}
static inline void tswap64s(uint64_t *s)
{
}
#endif
#if TARGET_LONG_SIZE == 4
#define tswapl(s) tswap32(s)
#define tswapls(s) tswap32s((uint32_t *)(s))
#define bswaptls(s) bswap32s(s)
#else
#define tswapl(s) tswap64(s)
#define tswapls(s) tswap64s((uint64_t *)(s))
#define bswaptls(s) bswap64s(s)
#endif
/* NOTE: arm FPA is horrible as double 32 bit words are stored in big
endian ! */
typedef union {
float64 d;
#if defined(WORDS_BIGENDIAN) \
|| (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT))
struct {
uint32_t upper;
uint32_t lower;
} l;
#else
struct {
uint32_t lower;
uint32_t upper;
} l;
#endif
uint64_t ll;
} CPU_DoubleU;
/* CPU memory access without any memory or io remapping */
/*
* the generic syntax for the memory accesses is:
*
* load: ld{type}{sign}{size}{endian}_{access_type}(ptr)
*
* store: st{type}{size}{endian}_{access_type}(ptr, val)
*
* type is:
* (empty): integer access
* f : float access
*
* sign is:
* (empty): for floats or 32 bit size
* u : unsigned
* s : signed
*
* size is:
* b: 8 bits
* w: 16 bits
* l: 32 bits
* q: 64 bits
*
* endian is:
* (empty): target cpu endianness or 8 bit access
* r : reversed target cpu endianness (not implemented yet)
* be : big endian (not implemented yet)
* le : little endian (not implemented yet)
*
* access_type is:
* raw : host memory access
* user : user mode access using soft MMU
* kernel : kernel mode access using soft MMU
*/
static inline int ldub_p(void *ptr)
{
return *(uint8_t *)ptr;
}
static inline int ldsb_p(void *ptr)
{
return *(int8_t *)ptr;
}
static inline void stb_p(void *ptr, int v)
{
*(uint8_t *)ptr = v;
}
/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
kernel handles unaligned load/stores may give better results, but
it is a system wide setting : bad */
#if !defined(TARGET_WORDS_BIGENDIAN) && (defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED))
/* conservative code for little endian unaligned accesses */
static inline int lduw_p(void *ptr)
{
#ifdef __powerpc__
int val;
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
return val;
#else
uint8_t *p = ptr;
return p[0] | (p[1] << 8);
#endif
}
static inline int ldsw_p(void *ptr)
{
#ifdef __powerpc__
int val;
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
return (int16_t)val;
#else
uint8_t *p = ptr;
return (int16_t)(p[0] | (p[1] << 8));
#endif
}
static inline int ldl_p(void *ptr)
{
#ifdef __powerpc__
int val;
__asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
return val;
#else
uint8_t *p = ptr;
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
#endif
}
static inline uint64_t ldq_p(void *ptr)
{
uint8_t *p = ptr;
uint32_t v1, v2;
v1 = ldl_p(p);
v2 = ldl_p(p + 4);
return v1 | ((uint64_t)v2 << 32);
}
static inline void stw_p(void *ptr, int v)
{
#ifdef __powerpc__
__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
#else
uint8_t *p = ptr;
p[0] = v;
p[1] = v >> 8;
#endif
}
static inline void stl_p(void *ptr, int v)
{
#ifdef __powerpc__
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
#else
uint8_t *p = ptr;
p[0] = v;
p[1] = v >> 8;
p[2] = v >> 16;
p[3] = v >> 24;
#endif
}
static inline void stq_p(void *ptr, uint64_t v)
{
uint8_t *p = ptr;
stl_p(p, (uint32_t)v);
stl_p(p + 4, v >> 32);
}
/* float access */
static inline float32 ldfl_p(void *ptr)
{
union {
float32 f;
uint32_t i;
} u;
u.i = ldl_p(ptr);
return u.f;
}
static inline void stfl_p(void *ptr, float32 v)
{
union {
float32 f;
uint32_t i;
} u;
u.f = v;
stl_p(ptr, u.i);
}
static inline float64 ldfq_p(void *ptr)
{
CPU_DoubleU u;
u.l.lower = ldl_p(ptr);
u.l.upper = ldl_p(ptr + 4);
return u.d;
}
static inline void stfq_p(void *ptr, float64 v)
{
CPU_DoubleU u;
u.d = v;
stl_p(ptr, u.l.lower);
stl_p(ptr + 4, u.l.upper);
}
#elif defined(TARGET_WORDS_BIGENDIAN) && (!defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED))
static inline int lduw_p(void *ptr)
{
#if defined(__i386__)
int val;
asm volatile ("movzwl %1, %0\n"
"xchgb %b0, %h0\n"
: "=q" (val)
: "m" (*(uint16_t *)ptr));
return val;
#else
uint8_t *b = (uint8_t *) ptr;
return ((b[0] << 8) | b[1]);
#endif
}
static inline int ldsw_p(void *ptr)
{
#if defined(__i386__)
int val;
asm volatile ("movzwl %1, %0\n"
"xchgb %b0, %h0\n"
: "=q" (val)
: "m" (*(uint16_t *)ptr));
return (int16_t)val;
#else
uint8_t *b = (uint8_t *) ptr;
return (int16_t)((b[0] << 8) | b[1]);
#endif
}
static inline int ldl_p(void *ptr)
{
#if defined(__i386__) || defined(__x86_64__)
int val;
asm volatile ("movl %1, %0\n"
"bswap %0\n"
: "=r" (val)
: "m" (*(uint32_t *)ptr));
return val;
#else
uint8_t *b = (uint8_t *) ptr;
return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
#endif
}
static inline uint64_t ldq_p(void *ptr)
{
uint32_t a,b;
a = ldl_p(ptr);
b = ldl_p(ptr+4);
return (((uint64_t)a<<32)|b);
}
static inline void stw_p(void *ptr, int v)
{
#if defined(__i386__)
asm volatile ("xchgb %b0, %h0\n"
"movw %w0, %1\n"
: "=q" (v)
: "m" (*(uint16_t *)ptr), "0" (v));
#else
uint8_t *d = (uint8_t *) ptr;
d[0] = v >> 8;
d[1] = v;
#endif
}
static inline void stl_p(void *ptr, int v)
{
#if defined(__i386__) || defined(__x86_64__)
asm volatile ("bswap %0\n"
"movl %0, %1\n"
: "=r" (v)
: "m" (*(uint32_t *)ptr), "0" (v));
#else
uint8_t *d = (uint8_t *) ptr;
d[0] = v >> 24;
d[1] = v >> 16;
d[2] = v >> 8;
d[3] = v;
#endif
}
static inline void stq_p(void *ptr, uint64_t v)
{
stl_p(ptr, v >> 32);
stl_p(ptr + 4, v);
}
/* float access */
static inline float32 ldfl_p(void *ptr)
{
union {
float32 f;
uint32_t i;
} u;
u.i = ldl_p(ptr);
return u.f;
}
static inline void stfl_p(void *ptr, float32 v)
{
union {
float32 f;
uint32_t i;
} u;
u.f = v;
stl_p(ptr, u.i);
}
static inline float64 ldfq_p(void *ptr)
{
CPU_DoubleU u;
u.l.upper = ldl_p(ptr);
u.l.lower = ldl_p(ptr + 4);
return u.d;
}
static inline void stfq_p(void *ptr, float64 v)
{
CPU_DoubleU u;
u.d = v;
stl_p(ptr, u.l.upper);
stl_p(ptr + 4, u.l.lower);
}
#else
static inline int lduw_p(void *ptr)
{
return *(uint16_t *)ptr;
}
static inline int ldsw_p(void *ptr)
{
return *(int16_t *)ptr;
}
static inline int ldl_p(void *ptr)
{
return *(uint32_t *)ptr;
}
static inline uint64_t ldq_p(void *ptr)
{
return *(uint64_t *)ptr;
}
static inline void stw_p(void *ptr, int v)
{
*(uint16_t *)ptr = v;
}
static inline void stl_p(void *ptr, int v)
{
*(uint32_t *)ptr = v;
}
static inline void stq_p(void *ptr, uint64_t v)
{
*(uint64_t *)ptr = v;
}
/* float access */
static inline float32 ldfl_p(void *ptr)
{
return *(float32 *)ptr;
}
static inline float64 ldfq_p(void *ptr)
{
return *(float64 *)ptr;
}
static inline void stfl_p(void *ptr, float32 v)
{
*(float32 *)ptr = v;
}
static inline void stfq_p(void *ptr, float64 v)
{
*(float64 *)ptr = v;
}
#endif
/* MMU memory access macros */
/* NOTE: we use double casts if pointers and target_ulong have
different sizes */
#define ldub_raw(p) ldub_p((uint8_t *)(long)(p))
#define ldsb_raw(p) ldsb_p((uint8_t *)(long)(p))
#define lduw_raw(p) lduw_p((uint8_t *)(long)(p))
#define ldsw_raw(p) ldsw_p((uint8_t *)(long)(p))
#define ldl_raw(p) ldl_p((uint8_t *)(long)(p))
#define ldq_raw(p) ldq_p((uint8_t *)(long)(p))
#define ldfl_raw(p) ldfl_p((uint8_t *)(long)(p))
#define ldfq_raw(p) ldfq_p((uint8_t *)(long)(p))
#define stb_raw(p, v) stb_p((uint8_t *)(long)(p), v)
#define stw_raw(p, v) stw_p((uint8_t *)(long)(p), v)
#define stl_raw(p, v) stl_p((uint8_t *)(long)(p), v)
#define stq_raw(p, v) stq_p((uint8_t *)(long)(p), v)
#define stfl_raw(p, v) stfl_p((uint8_t *)(long)(p), v)
#define stfq_raw(p, v) stfq_p((uint8_t *)(long)(p), v)
#if defined(CONFIG_USER_ONLY)
/* if user mode, no other memory access functions */
#define ldub(p) ldub_raw(p)
#define ldsb(p) ldsb_raw(p)
#define lduw(p) lduw_raw(p)
#define ldsw(p) ldsw_raw(p)
#define ldl(p) ldl_raw(p)
#define ldq(p) ldq_raw(p)
#define ldfl(p) ldfl_raw(p)
#define ldfq(p) ldfq_raw(p)
#define stb(p, v) stb_raw(p, v)
#define stw(p, v) stw_raw(p, v)
#define stl(p, v) stl_raw(p, v)
#define stq(p, v) stq_raw(p, v)
#define stfl(p, v) stfl_raw(p, v)
#define stfq(p, v) stfq_raw(p, v)
#define ldub_code(p) ldub_raw(p)
#define ldsb_code(p) ldsb_raw(p)
#define lduw_code(p) lduw_raw(p)
#define ldsw_code(p) ldsw_raw(p)
#define ldl_code(p) ldl_raw(p)
#define ldub_kernel(p) ldub_raw(p)
#define ldsb_kernel(p) ldsb_raw(p)
#define lduw_kernel(p) lduw_raw(p)
#define ldsw_kernel(p) ldsw_raw(p)
#define ldl_kernel(p) ldl_raw(p)
#define ldfl_kernel(p) ldfl_raw(p)
#define ldfq_kernel(p) ldfq_raw(p)
#define stb_kernel(p, v) stb_raw(p, v)
#define stw_kernel(p, v) stw_raw(p, v)
#define stl_kernel(p, v) stl_raw(p, v)
#define stq_kernel(p, v) stq_raw(p, v)
#define stfl_kernel(p, v) stfl_raw(p, v)
#define stfq_kernel(p, vt) stfq_raw(p, v)
#endif /* defined(CONFIG_USER_ONLY) */
/* page related stuff */
#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS)
#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1)
#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK)
extern unsigned long qemu_real_host_page_size;
extern unsigned long qemu_host_page_bits;
extern unsigned long qemu_host_page_size;
extern unsigned long qemu_host_page_mask;
#define HOST_PAGE_ALIGN(addr) (((addr) + qemu_host_page_size - 1) & qemu_host_page_mask)
/* same as PROT_xxx */
#define PAGE_READ 0x0001
#define PAGE_WRITE 0x0002
#define PAGE_EXEC 0x0004
#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC)
#define PAGE_VALID 0x0008
/* original state of the write flag (used when tracking self-modifying
code */
#define PAGE_WRITE_ORG 0x0010
void page_dump(FILE *f);
int page_get_flags(unsigned long address);
void page_set_flags(unsigned long start, unsigned long end, int flags);
void page_unprotect_range(uint8_t *data, unsigned long data_size);
#define SINGLE_CPU_DEFINES
#ifdef SINGLE_CPU_DEFINES
#if defined(TARGET_I386)
#define CPUState CPUX86State
#define cpu_init cpu_x86_init
#define cpu_exec cpu_x86_exec
#define cpu_gen_code cpu_x86_gen_code
#define cpu_signal_handler cpu_x86_signal_handler
#elif defined(TARGET_ARM)
#define CPUState CPUARMState
#define cpu_init cpu_arm_init
#define cpu_exec cpu_arm_exec
#define cpu_gen_code cpu_arm_gen_code
#define cpu_signal_handler cpu_arm_signal_handler
#elif defined(TARGET_SPARC)
#define CPUState CPUSPARCState
#define cpu_init cpu_sparc_init
#define cpu_exec cpu_sparc_exec
#define cpu_gen_code cpu_sparc_gen_code
#define cpu_signal_handler cpu_sparc_signal_handler
#elif defined(TARGET_PPC)
#define CPUState CPUPPCState
#define cpu_init cpu_ppc_init
#define cpu_exec cpu_ppc_exec
#define cpu_gen_code cpu_ppc_gen_code
#define cpu_signal_handler cpu_ppc_signal_handler
#elif defined(TARGET_MIPS)
#define CPUState CPUMIPSState
#define cpu_init cpu_mips_init
#define cpu_exec cpu_mips_exec
#define cpu_gen_code cpu_mips_gen_code
#define cpu_signal_handler cpu_mips_signal_handler
#else
#error unsupported target CPU
#endif
#endif /* SINGLE_CPU_DEFINES */
void cpu_dump_state(CPUState *env, FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
int flags);
void cpu_abort(CPUState *env, const char *fmt, ...);
extern CPUState *cpu_single_env;
extern int code_copy_enabled;
#define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */
#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */
#define CPU_INTERRUPT_EXITTB 0x04 /* exit the current TB (use for x86 a20 case) */
#define CPU_INTERRUPT_TIMER 0x08 /* internal timer exception pending */
void cpu_interrupt(CPUState *s, int mask);
void cpu_reset_interrupt(CPUState *env, int mask);
int cpu_breakpoint_insert(CPUState *env, target_ulong pc);
int cpu_breakpoint_remove(CPUState *env, target_ulong pc);
void cpu_single_step(CPUState *env, int enabled);
void cpu_reset(CPUState *s);
/* Return the physical page corresponding to a virtual one. Use it
only for debugging because no protection checks are done. Return -1
if no page found. */
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr);
#define CPU_LOG_TB_OUT_ASM (1 << 0)
#define CPU_LOG_TB_IN_ASM (1 << 1)
#define CPU_LOG_TB_OP (1 << 2)
#define CPU_LOG_TB_OP_OPT (1 << 3)
#define CPU_LOG_INT (1 << 4)
#define CPU_LOG_EXEC (1 << 5)
#define CPU_LOG_PCALL (1 << 6)
#define CPU_LOG_IOPORT (1 << 7)
#define CPU_LOG_TB_CPU (1 << 8)
/* define log items */
typedef struct CPULogItem {
int mask;
const char *name;
const char *help;
} CPULogItem;
extern CPULogItem cpu_log_items[];
void cpu_set_log(int log_flags);
void cpu_set_log_filename(const char *filename);
int cpu_str_to_log_mask(const char *str);
/* IO ports API */
/* NOTE: as these functions may be even used when there is an isa
brige on non x86 targets, we always defined them */
#ifndef NO_CPU_IO_DEFS
void cpu_outb(CPUState *env, int addr, int val);
void cpu_outw(CPUState *env, int addr, int val);
void cpu_outl(CPUState *env, int addr, int val);
int cpu_inb(CPUState *env, int addr);
int cpu_inw(CPUState *env, int addr);
int cpu_inl(CPUState *env, int addr);
#endif
/* memory API */
extern int phys_ram_size;
extern int phys_ram_fd;
extern uint8_t *phys_ram_base;
extern uint8_t *phys_ram_dirty;
/* physical memory access */
#define IO_MEM_NB_ENTRIES 256
#define TLB_INVALID_MASK (1 << 3)
#define IO_MEM_SHIFT 4
#define IO_MEM_RAM (0 << IO_MEM_SHIFT) /* hardcoded offset */
#define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */
#define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT)
#define IO_MEM_CODE (3 << IO_MEM_SHIFT) /* used internally, never use directly */
#define IO_MEM_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */
typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
void cpu_register_physical_memory(target_phys_addr_t start_addr,
unsigned long size,
unsigned long phys_offset);
int cpu_register_io_memory(int io_index,
CPUReadMemoryFunc **mem_read,
CPUWriteMemoryFunc **mem_write,
void *opaque);
CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index);
CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index);
void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
int len, int is_write);
static inline void cpu_physical_memory_read(target_phys_addr_t addr,
uint8_t *buf, int len)
{
cpu_physical_memory_rw(addr, buf, len, 0);
}
static inline void cpu_physical_memory_write(target_phys_addr_t addr,
const uint8_t *buf, int len)
{
cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1);
}
uint32_t ldl_phys(target_phys_addr_t addr);
void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val);
void stl_phys(target_phys_addr_t addr, uint32_t val);
int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
uint8_t *buf, int len, int is_write);
#define VGA_DIRTY_FLAG 0x01
/* read dirty bit (return 0 or 1) */
static inline int cpu_physical_memory_is_dirty(target_ulong addr)
{
return phys_ram_dirty[addr >> TARGET_PAGE_BITS] == 0xff;
}
static inline int cpu_physical_memory_get_dirty(target_ulong addr,
int dirty_flags)
{
return phys_ram_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags;
}
static inline void cpu_physical_memory_set_dirty(target_ulong addr)
{
phys_ram_dirty[addr >> TARGET_PAGE_BITS] = 0xff;
}
void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end,
int dirty_flags);
void dump_exec_info(FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
#endif /* CPU_ALL_H */
-91
View File
@@ -1,91 +0,0 @@
/*
* common defines for all CPUs
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef CPU_DEFS_H
#define CPU_DEFS_H
#include "config.h"
#include <setjmp.h>
#include <inttypes.h>
#include "osdep.h"
#ifndef TARGET_LONG_BITS
#error TARGET_LONG_BITS must be defined before including this header
#endif
#ifndef TARGET_PHYS_ADDR_BITS
#if TARGET_LONG_BITS >= HOST_LONG_BITS
#define TARGET_PHYS_ADDR_BITS TARGET_LONG_BITS
#else
#define TARGET_PHYS_ADDR_BITS HOST_LONG_BITS
#endif
#endif
#define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8)
/* target_ulong is the type of a virtual address */
#if TARGET_LONG_SIZE == 4
typedef int32_t target_long;
typedef uint32_t target_ulong;
#define TARGET_FMT_lx "%08x"
#elif TARGET_LONG_SIZE == 8
typedef int64_t target_long;
typedef uint64_t target_ulong;
#define TARGET_FMT_lx "%016llx"
#else
#error TARGET_LONG_SIZE undefined
#endif
/* target_phys_addr_t is the type of a physical address (its size can
be different from 'target_ulong'). We have sizeof(target_phys_addr)
= max(sizeof(unsigned long),
sizeof(size_of_target_physical_address)) because we must pass a
host pointer to memory operations in some cases */
#if TARGET_PHYS_ADDR_BITS == 32
typedef uint32_t target_phys_addr_t;
#elif TARGET_PHYS_ADDR_BITS == 64
typedef uint64_t target_phys_addr_t;
#else
#error TARGET_PHYS_ADDR_BITS undefined
#endif
#define HOST_LONG_SIZE (HOST_LONG_BITS / 8)
#define EXCP_INTERRUPT 0x10000 /* async interruption */
#define EXCP_HLT 0x10001 /* hlt instruction reached */
#define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */
#define MAX_BREAKPOINTS 32
#define CPU_TLB_SIZE 256
typedef struct CPUTLBEntry {
/* bit 31 to TARGET_PAGE_BITS : virtual address
bit TARGET_PAGE_BITS-1..IO_MEM_SHIFT : if non zero, memory io
zone number
bit 3 : indicates that the entry is invalid
bit 2..0 : zero
*/
target_ulong address;
/* addend to virtual address to get physical address */
target_phys_addr_t addend;
} CPUTLBEntry;
#endif
-1306
View File
File diff suppressed because it is too large. Load diff
-429
View File
@@ -1,429 +0,0 @@
/* Interface between the opcode library and its callers.
Written by Cygnus Support, 1993.
The opcode library (libopcodes.a) provides instruction decoders for
a large variety of instruction sets, callable with an identical
interface, for making instruction-processing programs more independent
of the instruction set being processed. */
#ifndef DIS_ASM_H
#define DIS_ASM_H
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#define PARAMS(x) x
typedef void *PTR;
typedef uint64_t bfd_vma;
typedef int64_t bfd_signed_vma;
typedef uint8_t bfd_byte;
#define sprintf_vma(s,x) sprintf (s, "%0" PRIx64, x)
#define BFD64
enum bfd_flavour {
bfd_target_unknown_flavour,
bfd_target_aout_flavour,
bfd_target_coff_flavour,
bfd_target_ecoff_flavour,
bfd_target_elf_flavour,
bfd_target_ieee_flavour,
bfd_target_nlm_flavour,
bfd_target_oasys_flavour,
bfd_target_tekhex_flavour,
bfd_target_srec_flavour,
bfd_target_ihex_flavour,
bfd_target_som_flavour,
bfd_target_os9k_flavour,
bfd_target_versados_flavour,
bfd_target_msdos_flavour,
bfd_target_evax_flavour
};
enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN };
enum bfd_architecture
{
bfd_arch_unknown, /* File arch not known */
bfd_arch_obscure, /* Arch known, not one of these */
bfd_arch_m68k, /* Motorola 68xxx */
#define bfd_mach_m68000 1
#define bfd_mach_m68008 2
#define bfd_mach_m68010 3
#define bfd_mach_m68020 4
#define bfd_mach_m68030 5
#define bfd_mach_m68040 6
#define bfd_mach_m68060 7
bfd_arch_vax, /* DEC Vax */
bfd_arch_i960, /* Intel 960 */
/* The order of the following is important.
lower number indicates a machine type that
only accepts a subset of the instructions
available to machines with higher numbers.
The exception is the "ca", which is
incompatible with all other machines except
"core". */
#define bfd_mach_i960_core 1
#define bfd_mach_i960_ka_sa 2
#define bfd_mach_i960_kb_sb 3
#define bfd_mach_i960_mc 4
#define bfd_mach_i960_xa 5
#define bfd_mach_i960_ca 6
#define bfd_mach_i960_jx 7
#define bfd_mach_i960_hx 8
bfd_arch_a29k, /* AMD 29000 */
bfd_arch_sparc, /* SPARC */
#define bfd_mach_sparc 1
/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */
#define bfd_mach_sparc_sparclet 2
#define bfd_mach_sparc_sparclite 3
#define bfd_mach_sparc_v8plus 4
#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns. */
#define bfd_mach_sparc_sparclite_le 6
#define bfd_mach_sparc_v9 7
#define bfd_mach_sparc_v9a 8 /* with ultrasparc add'ns. */
#define bfd_mach_sparc_v8plusb 9 /* with cheetah add'ns. */
#define bfd_mach_sparc_v9b 10 /* with cheetah add'ns. */
/* Nonzero if MACH has the v9 instruction set. */
#define bfd_mach_sparc_v9_p(mach) \
((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \
&& (mach) != bfd_mach_sparc_sparclite_le)
bfd_arch_mips, /* MIPS Rxxxx */
#define bfd_mach_mips3000 3000
#define bfd_mach_mips3900 3900
#define bfd_mach_mips4000 4000
#define bfd_mach_mips4010 4010
#define bfd_mach_mips4100 4100
#define bfd_mach_mips4300 4300
#define bfd_mach_mips4400 4400
#define bfd_mach_mips4600 4600
#define bfd_mach_mips4650 4650
#define bfd_mach_mips5000 5000
#define bfd_mach_mips6000 6000
#define bfd_mach_mips8000 8000
#define bfd_mach_mips10000 10000
#define bfd_mach_mips16 16
bfd_arch_i386, /* Intel 386 */
#define bfd_mach_i386_i386 0
#define bfd_mach_i386_i8086 1
#define bfd_mach_i386_i386_intel_syntax 2
#define bfd_mach_x86_64 3
#define bfd_mach_x86_64_intel_syntax 4
bfd_arch_we32k, /* AT&T WE32xxx */
bfd_arch_tahoe, /* CCI/Harris Tahoe */
bfd_arch_i860, /* Intel 860 */
bfd_arch_romp, /* IBM ROMP PC/RT */
bfd_arch_alliant, /* Alliant */
bfd_arch_convex, /* Convex */
bfd_arch_m88k, /* Motorola 88xxx */
bfd_arch_pyramid, /* Pyramid Technology */
bfd_arch_h8300, /* Hitachi H8/300 */
#define bfd_mach_h8300 1
#define bfd_mach_h8300h 2
#define bfd_mach_h8300s 3
bfd_arch_powerpc, /* PowerPC */
#define bfd_mach_ppc 0
#define bfd_mach_ppc64 1
#define bfd_mach_ppc_403 403
#define bfd_mach_ppc_403gc 4030
#define bfd_mach_ppc_505 505
#define bfd_mach_ppc_601 601
#define bfd_mach_ppc_602 602
#define bfd_mach_ppc_603 603
#define bfd_mach_ppc_ec603e 6031
#define bfd_mach_ppc_604 604
#define bfd_mach_ppc_620 620
#define bfd_mach_ppc_630 630
#define bfd_mach_ppc_750 750
#define bfd_mach_ppc_860 860
#define bfd_mach_ppc_a35 35
#define bfd_mach_ppc_rs64ii 642
#define bfd_mach_ppc_rs64iii 643
#define bfd_mach_ppc_7400 7400
bfd_arch_rs6000, /* IBM RS/6000 */
bfd_arch_hppa, /* HP PA RISC */
bfd_arch_d10v, /* Mitsubishi D10V */
bfd_arch_z8k, /* Zilog Z8000 */
#define bfd_mach_z8001 1
#define bfd_mach_z8002 2
bfd_arch_h8500, /* Hitachi H8/500 */
bfd_arch_sh, /* Hitachi SH */
#define bfd_mach_sh 0
#define bfd_mach_sh3 0x30
#define bfd_mach_sh3e 0x3e
#define bfd_mach_sh4 0x40
bfd_arch_alpha, /* Dec Alpha */
bfd_arch_arm, /* Advanced Risc Machines ARM */
#define bfd_mach_arm_2 1
#define bfd_mach_arm_2a 2
#define bfd_mach_arm_3 3
#define bfd_mach_arm_3M 4
#define bfd_mach_arm_4 5
#define bfd_mach_arm_4T 6
bfd_arch_ns32k, /* National Semiconductors ns32000 */
bfd_arch_w65, /* WDC 65816 */
bfd_arch_tic30, /* Texas Instruments TMS320C30 */
bfd_arch_v850, /* NEC V850 */
#define bfd_mach_v850 0
bfd_arch_arc, /* Argonaut RISC Core */
#define bfd_mach_arc_base 0
bfd_arch_m32r, /* Mitsubishi M32R/D */
#define bfd_mach_m32r 0 /* backwards compatibility */
bfd_arch_mn10200, /* Matsushita MN10200 */
bfd_arch_mn10300, /* Matsushita MN10300 */
bfd_arch_last
};
typedef struct symbol_cache_entry
{
const char *name;
union
{
PTR p;
bfd_vma i;
} udata;
} asymbol;
typedef int (*fprintf_ftype) PARAMS((FILE*, const char*, ...));
enum dis_insn_type {
dis_noninsn, /* Not a valid instruction */
dis_nonbranch, /* Not a branch instruction */
dis_branch, /* Unconditional branch */
dis_condbranch, /* Conditional branch */
dis_jsr, /* Jump to subroutine */
dis_condjsr, /* Conditional jump to subroutine */
dis_dref, /* Data reference instruction */
dis_dref2 /* Two data references in instruction */
};
/* This struct is passed into the instruction decoding routine,
and is passed back out into each callback. The various fields are used
for conveying information from your main routine into your callbacks,
for passing information into the instruction decoders (such as the
addresses of the callback functions), or for passing information
back from the instruction decoders to their callers.
It must be initialized before it is first passed; this can be done
by hand, or using one of the initialization macros below. */
typedef struct disassemble_info {
fprintf_ftype fprintf_func;
FILE *stream;
PTR application_data;
/* Target description. We could replace this with a pointer to the bfd,
but that would require one. There currently isn't any such requirement
so to avoid introducing one we record these explicitly. */
/* The bfd_flavour. This can be bfd_target_unknown_flavour. */
enum bfd_flavour flavour;
/* The bfd_arch value. */
enum bfd_architecture arch;
/* The bfd_mach value. */
unsigned long mach;
/* Endianness (for bi-endian cpus). Mono-endian cpus can ignore this. */
enum bfd_endian endian;
/* An array of pointers to symbols either at the location being disassembled
or at the start of the function being disassembled. The array is sorted
so that the first symbol is intended to be the one used. The others are
present for any misc. purposes. This is not set reliably, but if it is
not NULL, it is correct. */
asymbol **symbols;
/* Number of symbols in array. */
int num_symbols;
/* For use by the disassembler.
The top 16 bits are reserved for public use (and are documented here).
The bottom 16 bits are for the internal use of the disassembler. */
unsigned long flags;
#define INSN_HAS_RELOC 0x80000000
PTR private_data;
/* Function used to get bytes to disassemble. MEMADDR is the
address of the stuff to be disassembled, MYADDR is the address to
put the bytes in, and LENGTH is the number of bytes to read.
INFO is a pointer to this struct.
Returns an errno value or 0 for success. */
int (*read_memory_func)
PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, int length,
struct disassemble_info *info));
/* Function which should be called if we get an error that we can't
recover from. STATUS is the errno value from read_memory_func and
MEMADDR is the address that we were trying to read. INFO is a
pointer to this struct. */
void (*memory_error_func)
PARAMS ((int status, bfd_vma memaddr, struct disassemble_info *info));
/* Function called to print ADDR. */
void (*print_address_func)
PARAMS ((bfd_vma addr, struct disassemble_info *info));
/* Function called to determine if there is a symbol at the given ADDR.
If there is, the function returns 1, otherwise it returns 0.
This is used by ports which support an overlay manager where
the overlay number is held in the top part of an address. In
some circumstances we want to include the overlay number in the
address, (normally because there is a symbol associated with
that address), but sometimes we want to mask out the overlay bits. */
int (* symbol_at_address_func)
PARAMS ((bfd_vma addr, struct disassemble_info * info));
/* These are for buffer_read_memory. */
bfd_byte *buffer;
bfd_vma buffer_vma;
int buffer_length;
/* This variable may be set by the instruction decoder. It suggests
the number of bytes objdump should display on a single line. If
the instruction decoder sets this, it should always set it to
the same value in order to get reasonable looking output. */
int bytes_per_line;
/* the next two variables control the way objdump displays the raw data */
/* For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the */
/* output will look like this:
00: 00000000 00000000
with the chunks displayed according to "display_endian". */
int bytes_per_chunk;
enum bfd_endian display_endian;
/* Results from instruction decoders. Not all decoders yet support
this information. This info is set each time an instruction is
decoded, and is only valid for the last such instruction.
To determine whether this decoder supports this information, set
insn_info_valid to 0, decode an instruction, then check it. */
char insn_info_valid; /* Branch info has been set. */
char branch_delay_insns; /* How many sequential insn's will run before
a branch takes effect. (0 = normal) */
char data_size; /* Size of data reference in insn, in bytes */
enum dis_insn_type insn_type; /* Type of instruction */
bfd_vma target; /* Target address of branch or dref, if known;
zero if unknown. */
bfd_vma target2; /* Second target address for dref2 */
/* Command line options specific to the target disassembler. */
char * disassembler_options;
} disassemble_info;
/* Standard disassemblers. Disassemble one instruction at the given
target address. Return number of bytes processed. */
typedef int (*disassembler_ftype)
PARAMS((bfd_vma, disassemble_info *));
extern int print_insn_big_mips PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_little_mips PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_i386 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_m68k PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_z8001 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_z8002 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_h8300 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_h8300h PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_h8300s PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_h8500 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*));
extern disassembler_ftype arc_get_disassembler PARAMS ((int, int));
extern int print_insn_arm PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_sparc PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_big_a29k PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_little_a29k PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_i960 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_sh PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_shl PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_hppa PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_m32r PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_m88k PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_mn10200 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_mn10300 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_ns32k PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_big_powerpc PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_little_powerpc PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_rs6000 PARAMS ((bfd_vma, disassemble_info*));
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. */
extern disassembler_ftype disassembler PARAMS ((bfd *));
#endif
/* This block of definitions is for particular callers who read instructions
into a buffer before calling the instruction decoder. */
/* Here is a function which callers may wish to use for read_memory_func.
It gets bytes from a buffer. */
extern int buffer_read_memory
PARAMS ((bfd_vma, bfd_byte *, int, struct disassemble_info *));
/* This function goes with buffer_read_memory.
It prints a message using info->fprintf_func and info->stream. */
extern void perror_memory PARAMS ((int, bfd_vma, struct disassemble_info *));
/* Just print the address in hex. This is included for completeness even
though both GDB and objdump provide their own (to print symbolic
addresses). */
extern void generic_print_address
PARAMS ((bfd_vma, struct disassemble_info *));
/* Always true. */
extern int generic_symbol_at_address
PARAMS ((bfd_vma, struct disassemble_info *));
/* Macro to initialize a disassemble_info struct. This should be called
by all applications creating such a struct. */
#define INIT_DISASSEMBLE_INFO(INFO, STREAM, FPRINTF_FUNC) \
(INFO).flavour = bfd_target_unknown_flavour, \
(INFO).arch = bfd_arch_unknown, \
(INFO).mach = 0, \
(INFO).endian = BFD_ENDIAN_UNKNOWN, \
INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC)
/* Call this macro to initialize only the internal variables for the
disassembler. Architecture dependent things such as byte order, or machine
variant are not touched by this macro. This makes things much easier for
GDB which must initialize these things seperatly. */
#define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \
(INFO).fprintf_func = (FPRINTF_FUNC), \
(INFO).stream = (STREAM), \
(INFO).symbols = NULL, \
(INFO).num_symbols = 0, \
(INFO).buffer = NULL, \
(INFO).buffer_vma = 0, \
(INFO).buffer_length = 0, \
(INFO).read_memory_func = buffer_read_memory, \
(INFO).memory_error_func = perror_memory, \
(INFO).print_address_func = generic_print_address, \
(INFO).symbol_at_address_func = generic_symbol_at_address, \
(INFO).flags = 0, \
(INFO).bytes_per_line = 0, \
(INFO).bytes_per_chunk = 0, \
(INFO).display_endian = BFD_ENDIAN_UNKNOWN, \
(INFO).disassembler_options = NULL, \
(INFO).insn_info_valid = 0
#define _(x) x
/* from libbfd */
bfd_vma bfd_getl32 (const bfd_byte *addr);
bfd_vma bfd_getb32 (const bfd_byte *addr);
bfd_vma bfd_getl16 (const bfd_byte *addr);
bfd_vma bfd_getb16 (const bfd_byte *addr);
typedef enum bfd_boolean {false, true} boolean;
#endif /* ! defined (DIS_ASM_H) */
-386
View File
@@ -1,386 +0,0 @@
/* General "disassemble this chunk" code. Used for debugging. */
#include "config.h"
#include "dis-asm.h"
#include "elf.h"
#include <errno.h>
#include "cpu.h"
#include "exec-all.h"
#include "disas.h"
/* Filled in by elfload.c. Simplistic, but will do for now. */
struct syminfo *syminfos = NULL;
/* Get LENGTH bytes from info's buffer, at target address memaddr.
Transfer them to myaddr. */
int
buffer_read_memory (memaddr, myaddr, length, info)
bfd_vma memaddr;
bfd_byte *myaddr;
int length;
struct disassemble_info *info;
{
if (memaddr < info->buffer_vma
|| memaddr + length > info->buffer_vma + info->buffer_length)
/* Out of bounds. Use EIO because GDB uses it. */
return EIO;
memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
return 0;
}
/* Get LENGTH bytes from info's buffer, at target address memaddr.
Transfer them to myaddr. */
static int
target_read_memory (bfd_vma memaddr,
bfd_byte *myaddr,
int length,
struct disassemble_info *info)
{
int i;
for(i = 0; i < length; i++) {
myaddr[i] = ldub_code(memaddr + i);
}
return 0;
}
/* Print an error message. We can assume that this is in response to
an error return from buffer_read_memory. */
void
perror_memory (status, memaddr, info)
int status;
bfd_vma memaddr;
struct disassemble_info *info;
{
if (status != EIO)
/* Can't happen. */
(*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
else
/* Actually, address between memaddr and memaddr + len was
out of bounds. */
(*info->fprintf_func) (info->stream,
"Address 0x%llx is out of bounds.\n", memaddr);
}
/* This could be in a separate file, to save miniscule amounts of space
in statically linked executables. */
/* Just print the address is hex. This is included for completeness even
though both GDB and objdump provide their own (to print symbolic
addresses). */
void
generic_print_address (addr, info)
bfd_vma addr;
struct disassemble_info *info;
{
(*info->fprintf_func) (info->stream, "0x%llx", addr);
}
/* Just return the given address. */
int
generic_symbol_at_address (addr, info)
bfd_vma addr;
struct disassemble_info * info;
{
return 1;
}
bfd_vma bfd_getl32 (const bfd_byte *addr)
{
unsigned long v;
v = (unsigned long) addr[0];
v |= (unsigned long) addr[1] << 8;
v |= (unsigned long) addr[2] << 16;
v |= (unsigned long) addr[3] << 24;
return (bfd_vma) v;
}
bfd_vma bfd_getb32 (const bfd_byte *addr)
{
unsigned long v;
v = (unsigned long) addr[0] << 24;
v |= (unsigned long) addr[1] << 16;
v |= (unsigned long) addr[2] << 8;
v |= (unsigned long) addr[3];
return (bfd_vma) v;
}
bfd_vma bfd_getl16 (const bfd_byte *addr)
{
unsigned long v;
v = (unsigned long) addr[0];
v |= (unsigned long) addr[1] << 8;
return (bfd_vma) v;
}
bfd_vma bfd_getb16 (const bfd_byte *addr)
{
unsigned long v;
v = (unsigned long) addr[0] << 24;
v |= (unsigned long) addr[1] << 16;
return (bfd_vma) v;
}
#ifdef TARGET_ARM
static int
print_insn_thumb1(bfd_vma pc, disassemble_info *info)
{
return print_insn_arm(pc | 1, info);
}
#endif
/* Disassemble this for me please... (debugging). 'flags' has teh following
values:
i386 - nonzero means 16 bit code
arm - nonzero means thumb code
other targets - unused
*/
void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
{
target_ulong 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.read_memory_func = target_read_memory;
disasm_info.buffer_vma = code;
disasm_info.buffer_length = size;
#ifdef TARGET_WORDS_BIGENDIAN
disasm_info.endian = BFD_ENDIAN_BIG;
#else
disasm_info.endian = BFD_ENDIAN_LITTLE;
#endif
#if defined(TARGET_I386)
if (flags == 2)
disasm_info.mach = bfd_mach_x86_64;
else if (flags == 1)
disasm_info.mach = bfd_mach_i386_i8086;
else
disasm_info.mach = bfd_mach_i386_i386;
print_insn = print_insn_i386;
#elif defined(TARGET_ARM)
if (flags)
print_insn = print_insn_thumb1;
else
print_insn = print_insn_arm;
#elif defined(TARGET_SPARC)
print_insn = print_insn_sparc;
#ifdef TARGET_SPARC64
disasm_info.mach = bfd_mach_sparc_v9b;
#endif
#elif defined(TARGET_PPC)
if (cpu_single_env->msr[MSR_LE])
disasm_info.endian = BFD_ENDIAN_LITTLE;
#ifdef TARGET_PPC64
disasm_info.mach = bfd_mach_ppc64;
#else
disasm_info.mach = bfd_mach_ppc;
#endif
print_insn = print_insn_ppc;
#elif defined(TARGET_MIPS)
print_insn = print_insn_big_mips;
#else
fprintf(out, "0x" TARGET_FMT_lx
": Asm output not supported on this arch\n", code);
return;
#endif
for (pc = code; pc < code + size; pc += count) {
fprintf(out, "0x" TARGET_FMT_lx ": ", pc);
count = print_insn(pc, &disasm_info);
#if 0
{
int i;
uint8_t b;
fprintf(out, " {");
for(i = 0; i < count; i++) {
target_read_memory(pc + i, &b, 1, &disasm_info);
fprintf(out, " %02x", b);
}
fprintf(out, " }");
}
#endif
fprintf(out, "\n");
if (count < 0)
break;
}
}
/* Disassemble this for me please... (debugging). */
void disas(FILE *out, void *code, unsigned long size)
{
unsigned long 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;
#ifdef WORDS_BIGENDIAN
disasm_info.endian = BFD_ENDIAN_BIG;
#else
disasm_info.endian = BFD_ENDIAN_LITTLE;
#endif
#if defined(__i386__)
disasm_info.mach = bfd_mach_i386_i386;
print_insn = print_insn_i386;
#elif defined(__x86_64__)
disasm_info.mach = bfd_mach_x86_64;
print_insn = print_insn_i386;
#elif defined(__powerpc__)
print_insn = print_insn_ppc;
#elif defined(__alpha__)
print_insn = print_insn_alpha;
#elif defined(__sparc__)
print_insn = print_insn_sparc;
#elif defined(__arm__)
print_insn = print_insn_arm;
#elif defined(__MIPSEB__)
print_insn = print_insn_big_mips;
#elif defined(__MIPSEL__)
print_insn = print_insn_little_mips;
#else
fprintf(out, "0x%lx: Asm output not supported on this arch\n",
(long) code);
return;
#endif
for (pc = (unsigned long)code; pc < (unsigned long)code + size; pc += count) {
fprintf(out, "0x%08lx: ", pc);
#ifdef __arm__
/* since data are included in the code, it is better to
display code data too */
if (is_host) {
fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc));
}
#endif
count = print_insn(pc, &disasm_info);
fprintf(out, "\n");
if (count < 0)
break;
}
}
/* Look up symbol for debugging purpose. Returns "" if unknown. */
const char *lookup_symbol(target_ulong orig_addr)
{
unsigned int i;
/* Hack, because we know this is x86. */
Elf32_Sym *sym;
struct syminfo *s;
for (s = syminfos; s; s = s->next) {
sym = s->disas_symtab;
for (i = 0; i < s->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 (orig_addr >= sym[i].st_value
&& orig_addr < sym[i].st_value + sym[i].st_size)
return s->disas_strtab + sym[i].st_name;
}
}
return "";
}
#if !defined(CONFIG_USER_ONLY)
void term_vprintf(const char *fmt, va_list ap);
void term_printf(const char *fmt, ...);
static int monitor_disas_is_physical;
static int
monitor_read_memory (memaddr, myaddr, length, info)
bfd_vma memaddr;
bfd_byte *myaddr;
int length;
struct disassemble_info *info;
{
if (monitor_disas_is_physical) {
cpu_physical_memory_rw(memaddr, myaddr, length, 0);
} else {
cpu_memory_rw_debug(cpu_single_env, memaddr,myaddr, length, 0);
}
return 0;
}
static int monitor_fprintf(FILE *stream, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
term_vprintf(fmt, ap);
va_end(ap);
return 0;
}
void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags)
{
int count, i;
struct disassemble_info disasm_info;
int (*print_insn)(bfd_vma pc, disassemble_info *info);
INIT_DISASSEMBLE_INFO(disasm_info, NULL, monitor_fprintf);
monitor_disas_is_physical = is_physical;
disasm_info.read_memory_func = monitor_read_memory;
disasm_info.buffer_vma = pc;
#ifdef TARGET_WORDS_BIGENDIAN
disasm_info.endian = BFD_ENDIAN_BIG;
#else
disasm_info.endian = BFD_ENDIAN_LITTLE;
#endif
#if defined(TARGET_I386)
if (flags == 2)
disasm_info.mach = bfd_mach_x86_64;
else if (flags == 1)
disasm_info.mach = bfd_mach_i386_i8086;
else
disasm_info.mach = bfd_mach_i386_i386;
print_insn = print_insn_i386;
#elif defined(TARGET_ARM)
print_insn = print_insn_arm;
#elif defined(TARGET_SPARC)
print_insn = print_insn_sparc;
#elif defined(TARGET_PPC)
#ifdef TARGET_PPC64
disasm_info.mach = bfd_mach_ppc64;
#else
disasm_info.mach = bfd_mach_ppc;
#endif
print_insn = print_insn_ppc;
#elif defined(TARGET_MIPS)
print_insn = print_insn_big_mips;
#else
term_printf("0x" TARGET_FMT_lx
": Asm output not supported on this arch\n", pc);
return;
#endif
for(i = 0; i < nb_insn; i++) {
term_printf("0x" TARGET_FMT_lx ": ", pc);
count = print_insn(pc, &disasm_info);
term_printf("\n");
if (count < 0)
break;
pc += count;
}
}
#endif
-20
View File
@@ -1,20 +0,0 @@
#ifndef _QEMU_DISAS_H
#define _QEMU_DISAS_H
/* Disassemble this for me please... (debugging). */
void disas(FILE *out, void *code, unsigned long size);
void target_disas(FILE *out, target_ulong code, target_ulong size, int flags);
void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags);
/* Look up symbol for debugging purpose. Returns "" if unknown. */
const char *lookup_symbol(target_ulong orig_addr);
/* Filled in by elfload.c. Simplistic, but will do for now. */
extern struct syminfo {
unsigned int disas_num_syms;
void *disas_symtab;
const char *disas_strtab;
struct syminfo *next;
} *syminfos;
#endif /* _QEMU_DISAS_H */
-243
View File
@@ -1,243 +0,0 @@
/*
* dyngen defines for micro operation code
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if !defined(__DYNGEN_EXEC_H__)
#define __DYNGEN_EXEC_H__
/* NOTE: standard headers should be used with special care at this
point because host CPU registers are used as global variables. Some
host headers do not allow that. */
#include <stddef.h>
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
/* XXX may be done for all 64 bits targets ? */
#if defined (__x86_64__) || defined(__ia64)
typedef unsigned long uint64_t;
#else
typedef unsigned long long uint64_t;
#endif
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
#if defined (__x86_64__) || defined(__ia64)
typedef signed long int64_t;
#else
typedef signed long long int64_t;
#endif
#define INT8_MIN (-128)
#define INT16_MIN (-32767-1)
#define INT32_MIN (-2147483647-1)
#define INT64_MIN (-(int64_t)(9223372036854775807)-1)
#define INT8_MAX (127)
#define INT16_MAX (32767)
#define INT32_MAX (2147483647)
#define INT64_MAX ((int64_t)(9223372036854775807))
#define UINT8_MAX (255)
#define UINT16_MAX (65535)
#define UINT32_MAX (4294967295U)
#define UINT64_MAX ((uint64_t)(18446744073709551615))
typedef struct FILE FILE;
extern int fprintf(FILE *, const char *, ...);
extern int printf(const char *, ...);
#undef NULL
#define NULL 0
#ifdef __i386__
#define AREG0 "ebp"
#define AREG1 "ebx"
#define AREG2 "esi"
#define AREG3 "edi"
#endif
#ifdef __x86_64__
#define AREG0 "rbp"
#define AREG1 "rbx"
#define AREG2 "r12"
#define AREG3 "r13"
//#define AREG4 "r14"
//#define AREG5 "r15"
#endif
#ifdef __powerpc__
#define AREG0 "r27"
#define AREG1 "r24"
#define AREG2 "r25"
#define AREG3 "r26"
/* XXX: suppress this hack */
#if defined(CONFIG_USER_ONLY)
#define AREG4 "r16"
#define AREG5 "r17"
#define AREG6 "r18"
#define AREG7 "r19"
#define AREG8 "r20"
#define AREG9 "r21"
#define AREG10 "r22"
#define AREG11 "r23"
#endif
#define USE_INT_TO_FLOAT_HELPERS
#define BUGGY_GCC_DIV64
#endif
#ifdef __arm__
#define AREG0 "r7"
#define AREG1 "r4"
#define AREG2 "r5"
#define AREG3 "r6"
#endif
#ifdef __mips__
#define AREG0 "s3"
#define AREG1 "s0"
#define AREG2 "s1"
#define AREG3 "s2"
#endif
#ifdef __sparc__
#define AREG0 "g6"
#define AREG1 "g1"
#define AREG2 "g2"
#define AREG3 "g3"
#define AREG4 "l0"
#define AREG5 "l1"
#define AREG6 "l2"
#define AREG7 "l3"
#define AREG8 "l4"
#define AREG9 "l5"
#define AREG10 "l6"
#define AREG11 "l7"
#define USE_FP_CONVERT
#endif
#ifdef __s390__
#define AREG0 "r10"
#define AREG1 "r7"
#define AREG2 "r8"
#define AREG3 "r9"
#endif
#ifdef __alpha__
/* Note $15 is the frame pointer, so anything in op-i386.c that would
require a frame pointer, like alloca, would probably loose. */
#define AREG0 "$15"
#define AREG1 "$9"
#define AREG2 "$10"
#define AREG3 "$11"
#define AREG4 "$12"
#define AREG5 "$13"
#define AREG6 "$14"
#endif
#ifdef __mc68000
#define AREG0 "%a5"
#define AREG1 "%a4"
#define AREG2 "%d7"
#define AREG3 "%d6"
#define AREG4 "%d5"
#endif
#ifdef __ia64__
#define AREG0 "r7"
#define AREG1 "r4"
#define AREG2 "r5"
#define AREG3 "r6"
#endif
/* force GCC to generate only one epilog at the end of the function */
#define FORCE_RET() asm volatile ("");
#ifndef OPPROTO
#define OPPROTO
#endif
#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)
#define stringify(s) tostring(s)
#define tostring(s) #s
#ifdef __alpha__
/* the symbols are considered non exported so a br immediate is generated */
#define __hidden __attribute__((visibility("hidden")))
#else
#define __hidden
#endif
#if defined(__alpha__)
/* Suggested by Richard Henderson. This will result in code like
ldah $0,__op_param1($29) !gprelhigh
lda $0,__op_param1($0) !gprellow
We can then conveniently change $29 to $31 and adapt the offsets to
emit the appropriate constant. */
extern int __op_param1 __hidden;
extern int __op_param2 __hidden;
extern int __op_param3 __hidden;
#define PARAM1 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param1)); _r; })
#define PARAM2 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param2)); _r; })
#define PARAM3 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param3)); _r; })
#else
#if defined(__APPLE__)
static int __op_param1, __op_param2, __op_param3;
#else
extern int __op_param1, __op_param2, __op_param3;
#endif
#define PARAM1 ((long)(&__op_param1))
#define PARAM2 ((long)(&__op_param2))
#define PARAM3 ((long)(&__op_param3))
#endif /* !defined(__alpha__) */
extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
#if defined(_WIN32) || defined(__APPLE__)
#define ASM_NAME(x) "_" #x
#else
#define ASM_NAME(x) #x
#endif
#ifdef __i386__
#define EXIT_TB() asm volatile ("ret")
#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n)
#endif
#ifdef __x86_64__
#define EXIT_TB() asm volatile ("ret")
#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n)
#endif
#ifdef __powerpc__
#define EXIT_TB() asm volatile ("blr")
#define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n)
#endif
#ifdef __s390__
#define EXIT_TB() asm volatile ("br %r14")
#define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n)
#endif
#ifdef __alpha__
#define EXIT_TB() asm volatile ("ret")
#endif
#ifdef __ia64__
#define EXIT_TB() asm volatile ("br.ret.sptk.many b0;;")
#define GOTO_LABEL_PARAM(n) asm volatile ("br.sptk.many " \
ASM_NAME(__op_gen_label) #n)
#endif
#ifdef __sparc__
#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0\n" \
"nop")
#endif
#ifdef __arm__
#define EXIT_TB() asm volatile ("b exec_loop")
#define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n)
#endif
#ifdef __mc68000
#define EXIT_TB() asm volatile ("rts")
#endif
#endif /* !defined(__DYNGEN_EXEC_H__) */
-9
View File
@@ -1,9 +0,0 @@
static inline int gen_new_label(void)
{
return nb_gen_labels++;
}
static inline void gen_set_label(int n)
{
gen_labels[n] = gen_opc_ptr - gen_opc_buf;
}
-2542
View File
File diff suppressed because it is too large. Load diff
-426
View File
@@ -1,426 +0,0 @@
/*
* dyngen helpers
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
int __op_param1, __op_param2, __op_param3;
int __op_gen_label1, __op_gen_label2, __op_gen_label3;
int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
#ifdef __i386__
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
}
#endif
#ifdef __x86_64__
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
}
#endif
#ifdef __s390__
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
}
#endif
#ifdef __ia64__
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
while (start < stop) {
asm volatile ("fc %0" :: "r"(start));
start += 32;
}
asm volatile (";;sync.i;;srlz.i;;");
}
#endif
#ifdef __powerpc__
#define MIN_CACHE_LINE_SIZE 8 /* conservative value */
static void inline flush_icache_range(unsigned long start, unsigned long stop)
{
unsigned long p;
p = start & ~(MIN_CACHE_LINE_SIZE - 1);
stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1);
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
asm volatile ("dcbst 0,%0" : : "r"(p) : "memory");
}
asm volatile ("sync" : : : "memory");
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
asm volatile ("icbi 0,%0" : : "r"(p) : "memory");
}
asm volatile ("sync" : : : "memory");
asm volatile ("isync" : : : "memory");
}
#endif
#ifdef __alpha__
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
asm ("imb");
}
#endif
#ifdef __sparc__
static void inline flush_icache_range(unsigned long start, unsigned long stop)
{
unsigned long p;
p = start & ~(8UL - 1UL);
stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL);
for (; p < stop; p += 8)
__asm__ __volatile__("flush\t%0" : : "r" (p));
}
#endif
#ifdef __arm__
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
register unsigned long _beg __asm ("a1") = start;
register unsigned long _end __asm ("a2") = stop;
register unsigned long _flg __asm ("a3") = 0;
__asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg));
}
#endif
#ifdef __mc68000
#include <asm/cachectl.h>
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
cacheflush(start,FLUSH_SCOPE_LINE,FLUSH_CACHE_BOTH,stop-start+16);
}
#endif
#ifdef __alpha__
register int gp asm("$29");
static inline void immediate_ldah(void *p, int val) {
uint32_t *dest = p;
long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff;
*dest &= ~0xffff;
*dest |= high;
*dest |= 31 << 16;
}
static inline void immediate_lda(void *dest, int val) {
*(uint16_t *) dest = val;
}
void fix_bsr(void *p, int offset) {
uint32_t *dest = p;
*dest &= ~((1 << 21) - 1);
*dest |= (offset >> 2) & ((1 << 21) - 1);
}
#endif /* __alpha__ */
#ifdef __arm__
#define MAX_OP_SIZE (128 * 4) /* in bytes */
/* max size of the code that can be generated without calling arm_flush_ldr */
#define MAX_FRAG_SIZE (1024 * 4)
//#define MAX_FRAG_SIZE (135 * 4) /* for testing */
typedef struct LDREntry {
uint8_t *ptr;
uint32_t *data_ptr;
} LDREntry;
static LDREntry arm_ldr_table[1024];
static uint32_t arm_data_table[1024];
extern char exec_loop;
static inline void arm_reloc_pc24(uint32_t *ptr, uint32_t insn, int val)
{
*ptr = (insn & ~0xffffff) | ((insn + ((val - (int)ptr) >> 2)) & 0xffffff);
}
static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
LDREntry *ldr_start, LDREntry *ldr_end,
uint32_t *data_start, uint32_t *data_end,
int gen_jmp)
{
LDREntry *le;
uint32_t *ptr;
int offset, data_size, target;
uint8_t *data_ptr;
uint32_t insn;
data_size = (uint8_t *)data_end - (uint8_t *)data_start;
if (gen_jmp) {
/* generate branch to skip the data */
if (data_size == 0)
return gen_code_ptr;
target = (long)gen_code_ptr + data_size + 4;
arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, target);
gen_code_ptr += 4;
}
/* copy the data */
data_ptr = gen_code_ptr;
memcpy(gen_code_ptr, data_start, data_size);
gen_code_ptr += data_size;
/* patch the ldr to point to the data */
for(le = ldr_start; le < ldr_end; le++) {
ptr = (uint32_t *)le->ptr;
offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) +
(unsigned long)data_ptr -
(unsigned long)ptr - 8;
insn = *ptr & ~(0xfff | 0x00800000);
if (offset < 0) {
offset = - offset;
} else {
insn |= 0x00800000;
}
if (offset > 0xfff) {
fprintf(stderr, "Error ldr offset\n");
abort();
}
insn |= offset;
*ptr = insn;
}
return gen_code_ptr;
}
#endif /* __arm__ */
#ifdef __ia64
/* Patch instruction with "val" where "mask" has 1 bits. */
static inline void ia64_patch (uint64_t insn_addr, uint64_t mask, uint64_t val)
{
uint64_t m0, m1, v0, v1, b0, b1, *b = (uint64_t *) (insn_addr & -16);
# define insn_mask ((1UL << 41) - 1)
unsigned long shift;
b0 = b[0]; b1 = b[1];
shift = 5 + 41 * (insn_addr % 16); /* 5 template, 3 x 41-bit insns */
if (shift >= 64) {
m1 = mask << (shift - 64);
v1 = val << (shift - 64);
} else {
m0 = mask << shift; m1 = mask >> (64 - shift);
v0 = val << shift; v1 = val >> (64 - shift);
b[0] = (b0 & ~m0) | (v0 & m0);
}
b[1] = (b1 & ~m1) | (v1 & m1);
}
static inline void ia64_patch_imm60 (uint64_t insn_addr, uint64_t val)
{
ia64_patch(insn_addr,
0x011ffffe000UL,
( ((val & 0x0800000000000000UL) >> 23) /* bit 59 -> 36 */
| ((val & 0x00000000000fffffUL) << 13) /* bit 0 -> 13 */));
ia64_patch(insn_addr - 1, 0x1fffffffffcUL, val >> 18);
}
static inline void ia64_imm64 (void *insn, uint64_t val)
{
/* Ignore the slot number of the relocation; GCC and Intel
toolchains differed for some time on whether IMM64 relocs are
against slot 1 (Intel) or slot 2 (GCC). */
uint64_t insn_addr = (uint64_t) insn & ~3UL;
ia64_patch(insn_addr + 2,
0x01fffefe000UL,
( ((val & 0x8000000000000000UL) >> 27) /* bit 63 -> 36 */
| ((val & 0x0000000000200000UL) << 0) /* bit 21 -> 21 */
| ((val & 0x00000000001f0000UL) << 6) /* bit 16 -> 22 */
| ((val & 0x000000000000ff80UL) << 20) /* bit 7 -> 27 */
| ((val & 0x000000000000007fUL) << 13) /* bit 0 -> 13 */)
);
ia64_patch(insn_addr + 1, 0x1ffffffffffUL, val >> 22);
}
static inline void ia64_imm60b (void *insn, uint64_t val)
{
/* Ignore the slot number of the relocation; GCC and Intel
toolchains differed for some time on whether IMM64 relocs are
against slot 1 (Intel) or slot 2 (GCC). */
uint64_t insn_addr = (uint64_t) insn & ~3UL;
if (val + ((uint64_t) 1 << 59) >= (1UL << 60))
fprintf(stderr, "%s: value %ld out of IMM60 range\n",
__FUNCTION__, (int64_t) val);
ia64_patch_imm60(insn_addr + 2, val);
}
static inline void ia64_imm22 (void *insn, uint64_t val)
{
if (val + (1 << 21) >= (1 << 22))
fprintf(stderr, "%s: value %li out of IMM22 range\n",
__FUNCTION__, (int64_t)val);
ia64_patch((uint64_t) insn, 0x01fffcfe000UL,
( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */
| ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */
| ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */
| ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */));
}
/* Like ia64_imm22(), but also clear bits 20-21. For addl, this has
the effect of turning "addl rX=imm22,rY" into "addl
rX=imm22,r0". */
static inline void ia64_imm22_r0 (void *insn, uint64_t val)
{
if (val + (1 << 21) >= (1 << 22))
fprintf(stderr, "%s: value %li out of IMM22 range\n",
__FUNCTION__, (int64_t)val);
ia64_patch((uint64_t) insn, 0x01fffcfe000UL | (0x3UL << 20),
( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */
| ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */
| ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */
| ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */));
}
static inline void ia64_imm21b (void *insn, uint64_t val)
{
if (val + (1 << 20) >= (1 << 21))
fprintf(stderr, "%s: value %li out of IMM21b range\n",
__FUNCTION__, (int64_t)val);
ia64_patch((uint64_t) insn, 0x11ffffe000UL,
( ((val & 0x100000UL) << 16) /* bit 20 -> 36 */
| ((val & 0x0fffffUL) << 13) /* bit 0 -> 13 */));
}
static inline void ia64_nop_b (void *insn)
{
ia64_patch((uint64_t) insn, (1UL << 41) - 1, 2UL << 37);
}
static inline void ia64_ldxmov(void *insn, uint64_t val)
{
if (val + (1 << 21) < (1 << 22))
ia64_patch((uint64_t) insn, 0x1fff80fe000UL, 8UL << 37);
}
static inline int ia64_patch_ltoff(void *insn, uint64_t val,
int relaxable)
{
if (relaxable && (val + (1 << 21) < (1 << 22))) {
ia64_imm22_r0(insn, val);
return 0;
}
return 1;
}
struct ia64_fixup {
struct ia64_fixup *next;
void *addr; /* address that needs to be patched */
long value;
};
#define IA64_PLT(insn, plt_index) \
do { \
struct ia64_fixup *fixup = alloca(sizeof(*fixup)); \
fixup->next = plt_fixes; \
plt_fixes = fixup; \
fixup->addr = (insn); \
fixup->value = (plt_index); \
plt_offset[(plt_index)] = 1; \
} while (0)
#define IA64_LTOFF(insn, val, relaxable) \
do { \
if (ia64_patch_ltoff(insn, val, relaxable)) { \
struct ia64_fixup *fixup = alloca(sizeof(*fixup)); \
fixup->next = ltoff_fixes; \
ltoff_fixes = fixup; \
fixup->addr = (insn); \
fixup->value = (val); \
} \
} while (0)
static inline void ia64_apply_fixes (uint8_t **gen_code_pp,
struct ia64_fixup *ltoff_fixes,
uint64_t gp,
struct ia64_fixup *plt_fixes,
int num_plts,
unsigned long *plt_target,
unsigned int *plt_offset)
{
static const uint8_t plt_bundle[] = {
0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; movl r1=GP */
0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60,
0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; brl IP */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0
};
uint8_t *gen_code_ptr = *gen_code_pp, *plt_start, *got_start, *vp;
struct ia64_fixup *fixup;
unsigned int offset = 0;
struct fdesc {
long ip;
long gp;
} *fdesc;
int i;
if (plt_fixes) {
plt_start = gen_code_ptr;
for (i = 0; i < num_plts; ++i) {
if (plt_offset[i]) {
plt_offset[i] = offset;
offset += sizeof(plt_bundle);
fdesc = (struct fdesc *) plt_target[i];
memcpy(gen_code_ptr, plt_bundle, sizeof(plt_bundle));
ia64_imm64 (gen_code_ptr + 0x02, fdesc->gp);
ia64_imm60b(gen_code_ptr + 0x12,
(fdesc->ip - (long) (gen_code_ptr + 0x10)) >> 4);
gen_code_ptr += sizeof(plt_bundle);
}
}
for (fixup = plt_fixes; fixup; fixup = fixup->next)
ia64_imm21b(fixup->addr,
((long) plt_start + plt_offset[fixup->value]
- ((long) fixup->addr & ~0xf)) >> 4);
}
got_start = gen_code_ptr;
/* First, create the GOT: */
for (fixup = ltoff_fixes; fixup; fixup = fixup->next) {
/* first check if we already have this value in the GOT: */
for (vp = got_start; vp < gen_code_ptr; ++vp)
if (*(uint64_t *) vp == fixup->value)
break;
if (vp == gen_code_ptr) {
/* Nope, we need to put the value in the GOT: */
*(uint64_t *) vp = fixup->value;
gen_code_ptr += 8;
}
ia64_imm22(fixup->addr, (long) vp - gp);
}
*gen_code_pp = gen_code_ptr;
}
#endif
+101 -836
View File
File diff suppressed because it is too large. Load diff
-622
View File
@@ -1,622 +0,0 @@
/*
* internal execution defines for qemu
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* allow to see translation results - the slowdown should be negligible, so we leave it */
#define DEBUG_DISAS
#ifndef glue
#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)
#define stringify(s) tostring(s)
#define tostring(s) #s
#endif
#if __GNUC__ < 3
#define __builtin_expect(x, n) (x)
#endif
#ifdef __i386__
#define REGPARM(n) __attribute((regparm(n)))
#else
#define REGPARM(n)
#endif
/* is_jmp field values */
#define DISAS_NEXT 0 /* next instruction can be analyzed */
#define DISAS_JUMP 1 /* only pc was modified dynamically */
#define DISAS_UPDATE 2 /* cpu state was modified dynamically */
#define DISAS_TB_JUMP 3 /* only pc was modified statically */
struct TranslationBlock;
/* XXX: make safe guess about sizes */
#define MAX_OP_PER_INSTR 32
#define OPC_BUF_SIZE 512
#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR)
#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * 3)
extern uint16_t gen_opc_buf[OPC_BUF_SIZE];
extern uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
extern long gen_labels[OPC_BUF_SIZE];
extern int nb_gen_labels;
extern target_ulong gen_opc_pc[OPC_BUF_SIZE];
extern target_ulong gen_opc_npc[OPC_BUF_SIZE];
extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
extern target_ulong gen_opc_jump_pc[2];
typedef void (GenOpFunc)(void);
typedef void (GenOpFunc1)(long);
typedef void (GenOpFunc2)(long, long);
typedef void (GenOpFunc3)(long, long, long);
#if defined(TARGET_I386)
void optimize_flags_init(void);
#endif
extern FILE *logfile;
extern int loglevel;
int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb);
int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb);
void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf);
int cpu_gen_code(CPUState *env, struct TranslationBlock *tb,
int max_code_size, int *gen_code_size_ptr);
int cpu_restore_state(struct TranslationBlock *tb,
CPUState *env, unsigned long searched_pc,
void *puc);
int cpu_gen_code_copy(CPUState *env, struct TranslationBlock *tb,
int max_code_size, int *gen_code_size_ptr);
int cpu_restore_state_copy(struct TranslationBlock *tb,
CPUState *env, unsigned long searched_pc,
void *puc);
void cpu_resume_from_signal(CPUState *env1, void *puc);
void cpu_exec_init(void);
int page_unprotect(unsigned long address, unsigned long pc, void *puc);
void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
int is_cpu_write_access);
void tb_invalidate_page_range(target_ulong start, target_ulong end);
void tlb_flush_page(CPUState *env, target_ulong addr);
void tlb_flush(CPUState *env, int flush_global);
int tlb_set_page(CPUState *env, target_ulong vaddr,
target_phys_addr_t paddr, int prot,
int is_user, int is_softmmu);
#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)
#define CODE_GEN_PHYS_HASH_BITS 15
#define CODE_GEN_PHYS_HASH_SIZE (1 << CODE_GEN_PHYS_HASH_BITS)
/* maximum total translate dcode allocated */
/* NOTE: the translated code area cannot be too big because on some
archs the range of "fast" function calls is limited. Here is a
summary of the ranges:
i386 : signed 32 bits
arm : signed 26 bits
ppc : signed 24 bits
sparc : signed 32 bits
alpha : signed 23 bits
*/
#if defined(__alpha__)
#define CODE_GEN_BUFFER_SIZE (2 * 1024 * 1024)
#elif defined(__ia64)
#define CODE_GEN_BUFFER_SIZE (4 * 1024 * 1024) /* range of addl */
#elif defined(__powerpc__)
#define CODE_GEN_BUFFER_SIZE (6 * 1024 * 1024)
#else
#define CODE_GEN_BUFFER_SIZE (16 * 1024 * 1024)
#endif
//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
/* estimated block size for TB allocation */
/* XXX: use a per code average code fragment size and modulate it
according to the host CPU */
#if defined(CONFIG_SOFTMMU)
#define CODE_GEN_AVG_BLOCK_SIZE 128
#else
#define CODE_GEN_AVG_BLOCK_SIZE 64
#endif
#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / CODE_GEN_AVG_BLOCK_SIZE)
#if defined(__powerpc__)
#define USE_DIRECT_JUMP
#endif
#if defined(__i386__) && !defined(_WIN32)
#define USE_DIRECT_JUMP
#endif
typedef struct TranslationBlock {
target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */
target_ulong 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) */
uint16_t cflags; /* compile flags */
#define CF_CODE_COPY 0x0001 /* block was generated in code copy mode */
#define CF_TB_FP_USED 0x0002 /* fp ops are used in the TB */
#define CF_FP_USED 0x0004 /* fp ops are used in the TB or in a chained TB */
#define CF_SINGLE_INSN 0x0008 /* compile only a single instruction */
uint8_t *tc_ptr; /* pointer to the translated code */
struct TranslationBlock *hash_next; /* next matching tb for virtual address */
/* next matching tb for physical address. */
struct TranslationBlock *phys_hash_next;
/* first and second physical page containing code. The lower bit
of the pointer tells the index in page_next[] */
struct TranslationBlock *page_next[2];
target_ulong page_addr[2];
/* 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[4]; /* offset of jump instruction */
#else
uint32_t tb_next[2]; /* address of jump generated code */
#endif
/* list of TBs jumping to this one. This is a circular list using
the two least significant bits of the pointers to tell what is
the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 =
jmp_first */
struct TranslationBlock *jmp_next[2];
struct TranslationBlock *jmp_first;
} TranslationBlock;
static inline unsigned int tb_hash_func(target_ulong pc)
{
return pc & (CODE_GEN_HASH_SIZE - 1);
}
static inline unsigned int tb_phys_hash_func(unsigned long pc)
{
return pc & (CODE_GEN_PHYS_HASH_SIZE - 1);
}
TranslationBlock *tb_alloc(target_ulong pc);
void tb_flush(CPUState *env);
void tb_link(TranslationBlock *tb);
void tb_link_phys(TranslationBlock *tb,
target_ulong phys_pc, target_ulong phys_page2);
extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_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,
target_ulong pc,
target_ulong 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(USE_DIRECT_JUMP)
#if defined(__powerpc__)
static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
{
uint32_t val, *ptr;
/* patch the branch destination */
ptr = (uint32_t *)jmp_addr;
val = *ptr;
val = (val & ~0x03fffffc) | ((addr - jmp_addr) & 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");
}
#elif defined(__i386__)
static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
{
/* patch the branch destination */
*(uint32_t *)jmp_addr = addr - (jmp_addr + 4);
/* no need to flush icache explicitely */
}
#endif
static inline void tb_set_jmp_target(TranslationBlock *tb,
int n, unsigned long addr)
{
unsigned long offset;
offset = tb->tb_jmp_offset[n];
tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
offset = tb->tb_jmp_offset[n + 2];
if (offset != 0xffff)
tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
}
#else
/* set the jump target */
static inline void tb_set_jmp_target(TranslationBlock *tb,
int n, unsigned long addr)
{
tb->tb_next[n] = addr;
}
#endif
static inline void tb_add_jump(TranslationBlock *tb, int n,
TranslationBlock *tb_next)
{
/* NOTE: this test is only needed for thread safety */
if (!tb->jmp_next[n]) {
/* patch the native jump address */
tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr);
/* add in TB jmp circular list */
tb->jmp_next[n] = tb_next->jmp_first;
tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n));
}
}
TranslationBlock *tb_find_pc(unsigned long pc_ptr);
#ifndef offsetof
#define offsetof(type, field) ((size_t) &((type *)0)->field)
#endif
#if defined(_WIN32)
#define ASM_DATA_SECTION ".section \".data\"\n"
#define ASM_PREVIOUS_SECTION ".section .text\n"
#elif defined(__APPLE__)
#define ASM_DATA_SECTION ".data\n"
#define ASM_PREVIOUS_SECTION ".text\n"
#else
#define ASM_DATA_SECTION ".section \".data\"\n"
#define ASM_PREVIOUS_SECTION ".previous\n"
#endif
#if defined(__powerpc__)
/* we patch the jump instruction directly */
#define GOTO_TB(opname, tbparam, n)\
do {\
asm volatile (ASM_DATA_SECTION\
ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\
".long 1f\n"\
ASM_PREVIOUS_SECTION \
"b " ASM_NAME(__op_jmp) #n "\n"\
"1:\n");\
} while (0)
#elif defined(__i386__) && defined(USE_DIRECT_JUMP)
/* we patch the jump instruction directly */
#define GOTO_TB(opname, tbparam, n)\
do {\
asm volatile (".section .data\n"\
ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\
".long 1f\n"\
ASM_PREVIOUS_SECTION \
"jmp " ASM_NAME(__op_jmp) #n "\n"\
"1:\n");\
} while (0)
#else
/* jump to next block operations (more portable code, does not need
cache flushing, but slower because of indirect jump) */
#define GOTO_TB(opname, tbparam, n)\
do {\
static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\
static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
label ## n: ;\
dummy_label ## n: ;\
} while (0)
#endif
/* XXX: will be suppressed */
#define JUMP_TB(opname, tbparam, n, eip)\
do {\
GOTO_TB(opname, tbparam, n);\
T0 = (long)(tbparam) + (n);\
EIP = (int32_t)eip;\
EXIT_TB();\
} while (0)
extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
extern void *io_mem_opaque[IO_MEM_NB_ENTRIES];
#ifdef __powerpc__
static inline int testandset (int *p)
{
int ret;
__asm__ __volatile__ (
"0: lwarx %0,0,%1\n"
" xor. %0,%3,%0\n"
" bne 1f\n"
" stwcx. %2,0,%1\n"
" bne- 0b\n"
"1: "
: "=&r" (ret)
: "r" (p), "r" (1), "r" (0)
: "cr0", "memory");
return ret;
}
#endif
#ifdef __i386__
static inline int testandset (int *p)
{
long int readval = 0;
__asm__ __volatile__ ("lock; cmpxchgl %2, %0"
: "+m" (*p), "+a" (readval)
: "r" (1)
: "cc");
return readval;
}
#endif
#ifdef __x86_64__
static inline int testandset (int *p)
{
long int readval = 0;
__asm__ __volatile__ ("lock; cmpxchgl %2, %0"
: "+m" (*p), "+a" (readval)
: "r" (1)
: "cc");
return readval;
}
#endif
#ifdef __s390__
static inline int testandset (int *p)
{
int ret;
__asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
" jl 0b"
: "=&d" (ret)
: "r" (1), "a" (p), "0" (*p)
: "cc", "memory" );
return ret;
}
#endif
#ifdef __alpha__
static inline int testandset (int *p)
{
int ret;
unsigned long one;
__asm__ __volatile__ ("0: mov 1,%2\n"
" ldl_l %0,%1\n"
" stl_c %2,%1\n"
" beq %2,1f\n"
".subsection 2\n"
"1: br 0b\n"
".previous"
: "=r" (ret), "=m" (*p), "=r" (one)
: "m" (*p));
return ret;
}
#endif
#ifdef __sparc__
static inline int testandset (int *p)
{
int ret;
__asm__ __volatile__("ldstub [%1], %0"
: "=r" (ret)
: "r" (p)
: "memory");
return (ret ? 1 : 0);
}
#endif
#ifdef __arm__
static inline int testandset (int *spinlock)
{
register unsigned int ret;
__asm__ __volatile__("swp %0, %1, [%2]"
: "=r"(ret)
: "0"(1), "r"(spinlock));
return ret;
}
#endif
#ifdef __mc68000
static inline int testandset (int *p)
{
char ret;
__asm__ __volatile__("tas %1; sne %0"
: "=r" (ret)
: "m" (p)
: "cc","memory");
return ret;
}
#endif
#ifdef __ia64
#include <ia64intrin.h>
static inline int testandset (int *p)
{
return __sync_lock_test_and_set (p, 1);
}
#endif
typedef int spinlock_t;
#define SPIN_LOCK_UNLOCKED 0
#if defined(CONFIG_USER_ONLY)
static inline void spin_lock(spinlock_t *lock)
{
while (testandset(lock));
}
static inline void spin_unlock(spinlock_t *lock)
{
*lock = 0;
}
static inline int spin_trylock(spinlock_t *lock)
{
return !testandset(lock);
}
#else
static inline void spin_lock(spinlock_t *lock)
{
}
static inline void spin_unlock(spinlock_t *lock)
{
}
static inline int spin_trylock(spinlock_t *lock)
{
return 1;
}
#endif
extern spinlock_t tb_lock;
extern int tb_invalidated_flag;
#if !defined(CONFIG_USER_ONLY)
void tlb_fill(target_ulong addr, int is_write, int is_user,
void *retaddr);
#define ACCESS_TYPE 3
#define MEMSUFFIX _code
#define env cpu_single_env
#define DATA_SIZE 1
#include "softmmu_header.h"
#define DATA_SIZE 2
#include "softmmu_header.h"
#define DATA_SIZE 4
#include "softmmu_header.h"
#define DATA_SIZE 8
#include "softmmu_header.h"
#undef ACCESS_TYPE
#undef MEMSUFFIX
#undef env
#endif
#if defined(CONFIG_USER_ONLY)
static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
{
return addr;
}
#else
/* NOTE: this function can trigger an exception */
/* NOTE2: the returned address is not exactly the physical address: it
is the offset relative to phys_ram_base */
/* XXX: i386 target specific */
static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
{
int is_user, index, pd;
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
#if defined(TARGET_I386)
is_user = ((env->hflags & HF_CPL_MASK) == 3);
#elif defined (TARGET_PPC)
is_user = msr_pr;
#elif defined (TARGET_MIPS)
is_user = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM);
#elif defined (TARGET_SPARC)
is_user = (env->psrs == 0);
#else
#error "Unimplemented !"
#endif
if (__builtin_expect(env->tlb_read[is_user][index].address !=
(addr & TARGET_PAGE_MASK), 0)) {
ldub_code(addr);
}
pd = env->tlb_read[is_user][index].address & ~TARGET_PAGE_MASK;
if (pd > IO_MEM_ROM) {
cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x%08lx\n", addr);
}
return addr + env->tlb_read[is_user][index].addend - (unsigned long)phys_ram_base;
}
#endif
#ifdef USE_KQEMU
int kqemu_init(CPUState *env);
int kqemu_cpu_exec(CPUState *env);
void kqemu_flush_page(CPUState *env, target_ulong addr);
void kqemu_flush(CPUState *env, int global);
static inline int kqemu_is_ok(CPUState *env)
{
return(env->kqemu_enabled &&
(env->hflags & HF_CPL_MASK) == 3 &&
(env->eflags & IOPL_MASK) != IOPL_MASK &&
(env->cr[0] & CR0_PE_MASK) &&
(env->eflags & IF_MASK) &&
!(env->eflags & VM_MASK) &&
(env->ldt.limit == 0 || env->ldt.limit == 0x27));
}
#endif
-2432
View File
File diff suppressed because it is too large. Load diff
-720
View File
@@ -1,720 +0,0 @@
/*============================================================================
This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal notice) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*----------------------------------------------------------------------------
| Shifts `a' right by the number of bits given in `count'. If any nonzero
| bits are shifted off, they are ``jammed'' into the least significant bit of
| the result by setting the least significant bit to 1. The value of `count'
| can be arbitrarily large; in particular, if `count' is greater than 32, the
| result will be either 0 or 1, depending on whether `a' is zero or nonzero.
| The result is stored in the location pointed to by `zPtr'.
*----------------------------------------------------------------------------*/
INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr )
{
bits32 z;
if ( count == 0 ) {
z = a;
}
else if ( count < 32 ) {
z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 );
}
else {
z = ( a != 0 );
}
*zPtr = z;
}
/*----------------------------------------------------------------------------
| Shifts `a' right by the number of bits given in `count'. If any nonzero
| bits are shifted off, they are ``jammed'' into the least significant bit of
| the result by setting the least significant bit to 1. The value of `count'
| can be arbitrarily large; in particular, if `count' is greater than 64, the
| result will be either 0 or 1, depending on whether `a' is zero or nonzero.
| The result is stored in the location pointed to by `zPtr'.
*----------------------------------------------------------------------------*/
INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr )
{
bits64 z;
if ( count == 0 ) {
z = a;
}
else if ( count < 64 ) {
z = ( a>>count ) | ( ( a<<( ( - count ) & 63 ) ) != 0 );
}
else {
z = ( a != 0 );
}
*zPtr = z;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64
| _plus_ the number of bits given in `count'. The shifted result is at most
| 64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The
| bits shifted off form a second 64-bit result as follows: The _last_ bit
| shifted off is the most-significant bit of the extra result, and the other
| 63 bits of the extra result are all zero if and only if _all_but_the_last_
| bits shifted off were all zero. This extra result is stored in the location
| pointed to by `z1Ptr'. The value of `count' can be arbitrarily large.
| (This routine makes more sense if `a0' and `a1' are considered to form
| a fixed-point value with binary point between `a0' and `a1'. This fixed-
| point value is shifted right by the number of bits given in `count', and
| the integer part of the result is returned at the location pointed to by
| `z0Ptr'. The fractional part of the result may be slightly corrupted as
| described above, and is returned at the location pointed to by `z1Ptr'.)
*----------------------------------------------------------------------------*/
INLINE void
shift64ExtraRightJamming(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z0, z1;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z1 = a1;
z0 = a0;
}
else if ( count < 64 ) {
z1 = ( a0<<negCount ) | ( a1 != 0 );
z0 = a0>>count;
}
else {
if ( count == 64 ) {
z1 = a0 | ( a1 != 0 );
}
else {
z1 = ( ( a0 | a1 ) != 0 );
}
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
| number of bits given in `count'. Any bits shifted off are lost. The value
| of `count' can be arbitrarily large; in particular, if `count' is greater
| than 128, the result will be 0. The result is broken into two 64-bit pieces
| which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
shift128Right(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z0, z1;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z1 = a1;
z0 = a0;
}
else if ( count < 64 ) {
z1 = ( a0<<negCount ) | ( a1>>count );
z0 = a0>>count;
}
else {
z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0;
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
| number of bits given in `count'. If any nonzero bits are shifted off, they
| are ``jammed'' into the least significant bit of the result by setting the
| least significant bit to 1. The value of `count' can be arbitrarily large;
| in particular, if `count' is greater than 128, the result will be either
| 0 or 1, depending on whether the concatenation of `a0' and `a1' is zero or
| nonzero. The result is broken into two 64-bit pieces which are stored at
| the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
shift128RightJamming(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z0, z1;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z1 = a1;
z0 = a0;
}
else if ( count < 64 ) {
z1 = ( a0<<negCount ) | ( a1>>count ) | ( ( a1<<negCount ) != 0 );
z0 = a0>>count;
}
else {
if ( count == 64 ) {
z1 = a0 | ( a1 != 0 );
}
else if ( count < 128 ) {
z1 = ( a0>>( count & 63 ) ) | ( ( ( a0<<negCount ) | a1 ) != 0 );
}
else {
z1 = ( ( a0 | a1 ) != 0 );
}
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' right
| by 64 _plus_ the number of bits given in `count'. The shifted result is
| at most 128 nonzero bits; these are broken into two 64-bit pieces which are
| stored at the locations pointed to by `z0Ptr' and `z1Ptr'. The bits shifted
| off form a third 64-bit result as follows: The _last_ bit shifted off is
| the most-significant bit of the extra result, and the other 63 bits of the
| extra result are all zero if and only if _all_but_the_last_ bits shifted off
| were all zero. This extra result is stored in the location pointed to by
| `z2Ptr'. The value of `count' can be arbitrarily large.
| (This routine makes more sense if `a0', `a1', and `a2' are considered
| to form a fixed-point value with binary point between `a1' and `a2'. This
| fixed-point value is shifted right by the number of bits given in `count',
| and the integer part of the result is returned at the locations pointed to
| by `z0Ptr' and `z1Ptr'. The fractional part of the result may be slightly
| corrupted as described above, and is returned at the location pointed to by
| `z2Ptr'.)
*----------------------------------------------------------------------------*/
INLINE void
shift128ExtraRightJamming(
bits64 a0,
bits64 a1,
bits64 a2,
int16 count,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z2 = a2;
z1 = a1;
z0 = a0;
}
else {
if ( count < 64 ) {
z2 = a1<<negCount;
z1 = ( a0<<negCount ) | ( a1>>count );
z0 = a0>>count;
}
else {
if ( count == 64 ) {
z2 = a1;
z1 = a0;
}
else {
a2 |= a1;
if ( count < 128 ) {
z2 = a0<<negCount;
z1 = a0>>( count & 63 );
}
else {
z2 = ( count == 128 ) ? a0 : ( a0 != 0 );
z1 = 0;
}
}
z0 = 0;
}
z2 |= ( a2 != 0 );
}
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the
| number of bits given in `count'. Any bits shifted off are lost. The value
| of `count' must be less than 64. The result is broken into two 64-bit
| pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
shortShift128Left(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
*z1Ptr = a1<<count;
*z0Ptr =
( count == 0 ) ? a0 : ( a0<<count ) | ( a1>>( ( - count ) & 63 ) );
}
/*----------------------------------------------------------------------------
| Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left
| by the number of bits given in `count'. Any bits shifted off are lost.
| The value of `count' must be less than 64. The result is broken into three
| 64-bit pieces which are stored at the locations pointed to by `z0Ptr',
| `z1Ptr', and `z2Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
shortShift192Left(
bits64 a0,
bits64 a1,
bits64 a2,
int16 count,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 negCount;
z2 = a2<<count;
z1 = a1<<count;
z0 = a0<<count;
if ( 0 < count ) {
negCount = ( ( - count ) & 63 );
z1 |= a2>>negCount;
z0 |= a1>>negCount;
}
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit
| value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so
| any carry out is lost. The result is broken into two 64-bit pieces which
| are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
add128(
bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z1;
z1 = a1 + b1;
*z1Ptr = z1;
*z0Ptr = a0 + b0 + ( z1 < a1 );
}
/*----------------------------------------------------------------------------
| Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the
| 192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is
| modulo 2^192, so any carry out is lost. The result is broken into three
| 64-bit pieces which are stored at the locations pointed to by `z0Ptr',
| `z1Ptr', and `z2Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
add192(
bits64 a0,
bits64 a1,
bits64 a2,
bits64 b0,
bits64 b1,
bits64 b2,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 carry0, carry1;
z2 = a2 + b2;
carry1 = ( z2 < a2 );
z1 = a1 + b1;
carry0 = ( z1 < a1 );
z0 = a0 + b0;
z1 += carry1;
z0 += ( z1 < carry1 );
z0 += carry0;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the
| 128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo
| 2^128, so any borrow out (carry out) is lost. The result is broken into two
| 64-bit pieces which are stored at the locations pointed to by `z0Ptr' and
| `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
sub128(
bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr )
{
*z1Ptr = a1 - b1;
*z0Ptr = a0 - b0 - ( a1 < b1 );
}
/*----------------------------------------------------------------------------
| Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2'
| from the 192-bit value formed by concatenating `a0', `a1', and `a2'.
| Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The
| result is broken into three 64-bit pieces which are stored at the locations
| pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
sub192(
bits64 a0,
bits64 a1,
bits64 a2,
bits64 b0,
bits64 b1,
bits64 b2,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 borrow0, borrow1;
z2 = a2 - b2;
borrow1 = ( a2 < b2 );
z1 = a1 - b1;
borrow0 = ( a1 < b1 );
z0 = a0 - b0;
z0 -= ( z1 < borrow1 );
z1 -= borrow1;
z0 -= borrow0;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Multiplies `a' by `b' to obtain a 128-bit product. The product is broken
| into two 64-bit pieces which are stored at the locations pointed to by
| `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits32 aHigh, aLow, bHigh, bLow;
bits64 z0, zMiddleA, zMiddleB, z1;
aLow = a;
aHigh = a>>32;
bLow = b;
bHigh = b>>32;
z1 = ( (bits64) aLow ) * bLow;
zMiddleA = ( (bits64) aLow ) * bHigh;
zMiddleB = ( (bits64) aHigh ) * bLow;
z0 = ( (bits64) aHigh ) * bHigh;
zMiddleA += zMiddleB;
z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 );
zMiddleA <<= 32;
z1 += zMiddleA;
z0 += ( z1 < zMiddleA );
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Multiplies the 128-bit value formed by concatenating `a0' and `a1' by
| `b' to obtain a 192-bit product. The product is broken into three 64-bit
| pieces which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and
| `z2Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
mul128By64To192(
bits64 a0,
bits64 a1,
bits64 b,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2, more1;
mul64To128( a1, b, &z1, &z2 );
mul64To128( a0, b, &z0, &more1 );
add128( z0, more1, 0, z1, &z0, &z1 );
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the
| 128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit
| product. The product is broken into four 64-bit pieces which are stored at
| the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
mul128To256(
bits64 a0,
bits64 a1,
bits64 b0,
bits64 b1,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr,
bits64 *z3Ptr
)
{
bits64 z0, z1, z2, z3;
bits64 more1, more2;
mul64To128( a1, b1, &z2, &z3 );
mul64To128( a1, b0, &z1, &more2 );
add128( z1, more2, 0, z2, &z1, &z2 );
mul64To128( a0, b0, &z0, &more1 );
add128( z0, more1, 0, z1, &z0, &z1 );
mul64To128( a0, b1, &more1, &more2 );
add128( more1, more2, 0, z2, &more1, &z2 );
add128( z0, z1, 0, more1, &z0, &z1 );
*z3Ptr = z3;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Returns an approximation to the 64-bit integer quotient obtained by dividing
| `b' into the 128-bit value formed by concatenating `a0' and `a1'. The
| divisor `b' must be at least 2^63. If q is the exact quotient truncated
| toward zero, the approximation returned lies between q and q + 2 inclusive.
| If the exact quotient q is larger than 64 bits, the maximum positive 64-bit
| unsigned integer is returned.
*----------------------------------------------------------------------------*/
static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b )
{
bits64 b0, b1;
bits64 rem0, rem1, term0, term1;
bits64 z;
if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF );
b0 = b>>32;
z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32;
mul64To128( b, z, &term0, &term1 );
sub128( a0, a1, term0, term1, &rem0, &rem1 );
while ( ( (sbits64) rem0 ) < 0 ) {
z -= LIT64( 0x100000000 );
b1 = b<<32;
add128( rem0, rem1, b0, b1, &rem0, &rem1 );
}
rem0 = ( rem0<<32 ) | ( rem1>>32 );
z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0;
return z;
}
/*----------------------------------------------------------------------------
| Returns an approximation to the square root of the 32-bit significand given
| by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of
| `aExp' (the least significant bit) is 1, the integer returned approximates
| 2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp'
| is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either
| case, the approximation returned lies strictly within +/-2 of the exact
| value.
*----------------------------------------------------------------------------*/
static bits32 estimateSqrt32( int16 aExp, bits32 a )
{
static const bits16 sqrtOddAdjustments[] = {
0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0,
0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67
};
static const bits16 sqrtEvenAdjustments[] = {
0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E,
0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002
};
int8 index;
bits32 z;
index = ( a>>27 ) & 15;
if ( aExp & 1 ) {
z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ];
z = ( ( a / z )<<14 ) + ( z<<15 );
a >>= 1;
}
else {
z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ];
z = a / z + z;
z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 );
if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 );
}
return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 );
}
/*----------------------------------------------------------------------------
| Returns the number of leading 0 bits before the most-significant 1 bit of
| `a'. If `a' is zero, 32 is returned.
*----------------------------------------------------------------------------*/
static int8 countLeadingZeros32( bits32 a )
{
static const int8 countLeadingZerosHigh[] = {
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
int8 shiftCount;
shiftCount = 0;
if ( a < 0x10000 ) {
shiftCount += 16;
a <<= 16;
}
if ( a < 0x1000000 ) {
shiftCount += 8;
a <<= 8;
}
shiftCount += countLeadingZerosHigh[ a>>24 ];
return shiftCount;
}
/*----------------------------------------------------------------------------
| Returns the number of leading 0 bits before the most-significant 1 bit of
| `a'. If `a' is zero, 64 is returned.
*----------------------------------------------------------------------------*/
static int8 countLeadingZeros64( bits64 a )
{
int8 shiftCount;
shiftCount = 0;
if ( a < ( (bits64) 1 )<<32 ) {
shiftCount += 32;
}
else {
a >>= 32;
}
shiftCount += countLeadingZeros32( a );
return shiftCount;
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1'
| is equal to the 128-bit value formed by concatenating `b0' and `b1'.
| Otherwise, returns 0.
*----------------------------------------------------------------------------*/
INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 == b0 ) && ( a1 == b1 );
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
| than or equal to the 128-bit value formed by concatenating `b0' and `b1'.
| Otherwise, returns 0.
*----------------------------------------------------------------------------*/
INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) );
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
| than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise,
| returns 0.
*----------------------------------------------------------------------------*/
INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) );
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is
| not equal to the 128-bit value formed by concatenating `b0' and `b1'.
| Otherwise, returns 0.
*----------------------------------------------------------------------------*/
INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 != b0 ) || ( a1 != b1 );
}
-348
View File
@@ -1,348 +0,0 @@
/* Native implementation of soft float functions. Only a single status
context is supported */
#include "softfloat.h"
#include <math.h>
void set_float_rounding_mode(int val STATUS_PARAM)
{
STATUS(float_rounding_mode) = val;
#if defined(_BSD) && !defined(__APPLE__)
fpsetround(val);
#elif defined(__arm__)
/* nothing to do */
#else
fesetround(val);
#endif
}
#ifdef FLOATX80
void set_floatx80_rounding_precision(int val STATUS_PARAM)
{
STATUS(floatx80_rounding_precision) = val;
}
#endif
#if defined(_BSD)
#define lrint(d) ((int32_t)rint(d))
#define llrint(d) ((int64_t)rint(d))
#endif
#if defined(__powerpc__)
/* correct (but slow) PowerPC rint() (glibc version is incorrect) */
double qemu_rint(double x)
{
double y = 4503599627370496.0;
if (fabs(x) >= y)
return x;
if (x < 0)
y = -y;
y = (x + y) - y;
if (y == 0.0)
y = copysign(y, x);
return y;
}
#define rint qemu_rint
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE integer-to-floating-point conversion routines.
*----------------------------------------------------------------------------*/
float32 int32_to_float32(int v STATUS_PARAM)
{
return (float32)v;
}
float64 int32_to_float64(int v STATUS_PARAM)
{
return (float64)v;
}
#ifdef FLOATX80
floatx80 int32_to_floatx80(int v STATUS_PARAM)
{
return (floatx80)v;
}
#endif
float32 int64_to_float32( int64_t v STATUS_PARAM)
{
return (float32)v;
}
float64 int64_to_float64( int64_t v STATUS_PARAM)
{
return (float64)v;
}
#ifdef FLOATX80
floatx80 int64_to_floatx80( int64_t v STATUS_PARAM)
{
return (floatx80)v;
}
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision conversion routines.
*----------------------------------------------------------------------------*/
int float32_to_int32( float32 a STATUS_PARAM)
{
return lrintf(a);
}
int float32_to_int32_round_to_zero( float32 a STATUS_PARAM)
{
return (int)a;
}
int64_t float32_to_int64( float32 a STATUS_PARAM)
{
return llrintf(a);
}
int64_t float32_to_int64_round_to_zero( float32 a STATUS_PARAM)
{
return (int64_t)a;
}
float64 float32_to_float64( float32 a STATUS_PARAM)
{
return a;
}
#ifdef FLOATX80
floatx80 float32_to_floatx80( float32 a STATUS_PARAM)
{
return a;
}
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision operations.
*----------------------------------------------------------------------------*/
float32 float32_round_to_int( float32 a STATUS_PARAM)
{
return rintf(a);
}
float32 float32_rem( float32 a, float32 b STATUS_PARAM)
{
return remainderf(a, b);
}
float32 float32_sqrt( float32 a STATUS_PARAM)
{
return sqrtf(a);
}
char float32_compare( float32 a, float32 b STATUS_PARAM )
{
if (a < b) {
return -1;
} else if (a == b) {
return 0;
} else if (a > b) {
return 1;
} else {
return 2;
}
}
char float32_compare_quiet( float32 a, float32 b STATUS_PARAM )
{
if (isless(a, b)) {
return -1;
} else if (a == b) {
return 0;
} else if (isgreater(a, b)) {
return 1;
} else {
return 2;
}
}
char float32_is_signaling_nan( float32 a1)
{
float32u u;
uint32_t a;
u.f = a1;
a = u.i;
return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
}
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision conversion routines.
*----------------------------------------------------------------------------*/
int float64_to_int32( float64 a STATUS_PARAM)
{
return lrint(a);
}
int float64_to_int32_round_to_zero( float64 a STATUS_PARAM)
{
return (int)a;
}
int64_t float64_to_int64( float64 a STATUS_PARAM)
{
return llrint(a);
}
int64_t float64_to_int64_round_to_zero( float64 a STATUS_PARAM)
{
return (int64_t)a;
}
float32 float64_to_float32( float64 a STATUS_PARAM)
{
return a;
}
#ifdef FLOATX80
floatx80 float64_to_floatx80( float64 a STATUS_PARAM)
{
return a;
}
#endif
#ifdef FLOAT128
float128 float64_to_float128( float64 a STATUS_PARAM)
{
return a;
}
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision operations.
*----------------------------------------------------------------------------*/
float64 float64_round_to_int( float64 a STATUS_PARAM )
{
#if defined(__arm__)
switch(STATUS(float_rounding_mode)) {
default:
case float_round_nearest_even:
asm("rndd %0, %1" : "=f" (a) : "f"(a));
break;
case float_round_down:
asm("rnddm %0, %1" : "=f" (a) : "f"(a));
break;
case float_round_up:
asm("rnddp %0, %1" : "=f" (a) : "f"(a));
break;
case float_round_to_zero:
asm("rnddz %0, %1" : "=f" (a) : "f"(a));
break;
}
#else
return rint(a);
#endif
}
float64 float64_rem( float64 a, float64 b STATUS_PARAM)
{
return remainder(a, b);
}
float64 float64_sqrt( float64 a STATUS_PARAM)
{
return sqrt(a);
}
char float64_compare( float64 a, float64 b STATUS_PARAM )
{
if (a < b) {
return -1;
} else if (a == b) {
return 0;
} else if (a > b) {
return 1;
} else {
return 2;
}
}
char float64_compare_quiet( float64 a, float64 b STATUS_PARAM )
{
if (isless(a, b)) {
return -1;
} else if (a == b) {
return 0;
} else if (isgreater(a, b)) {
return 1;
} else {
return 2;
}
}
char float64_is_signaling_nan( float64 a1)
{
float64u u;
uint64_t a;
u.f = a1;
a = u.i;
return
( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
&& ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision conversion routines.
*----------------------------------------------------------------------------*/
int floatx80_to_int32( floatx80 a STATUS_PARAM)
{
return lrintl(a);
}
int floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM)
{
return (int)a;
}
int64_t floatx80_to_int64( floatx80 a STATUS_PARAM)
{
return llrintl(a);
}
int64_t floatx80_to_int64_round_to_zero( floatx80 a STATUS_PARAM)
{
return (int64_t)a;
}
float32 floatx80_to_float32( floatx80 a STATUS_PARAM)
{
return a;
}
float64 floatx80_to_float64( floatx80 a STATUS_PARAM)
{
return a;
}
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision operations.
*----------------------------------------------------------------------------*/
floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM)
{
return rintl(a);
}
floatx80 floatx80_rem( floatx80 a, floatx80 b STATUS_PARAM)
{
return remainderl(a, b);
}
floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM)
{
return sqrtl(a);
}
char floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM )
{
if (a < b) {
return -1;
} else if (a == b) {
return 0;
} else if (a > b) {
return 1;
} else {
return 2;
}
}
char floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
{
if (isless(a, b)) {
return -1;
} else if (a == b) {
return 0;
} else if (isgreater(a, b)) {
return 1;
} else {
return 2;
}
}
char floatx80_is_signaling_nan( floatx80 a1)
{
floatx80u u;
u.f = a1;
return ( ( u.i.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( u.i.low<<1 );
}
#endif
-332
View File
@@ -1,332 +0,0 @@
/* Native implementation of soft float functions */
#include <math.h>
#if defined(_BSD) && !defined(__APPLE__)
#include <ieeefp.h>
#else
#include <fenv.h>
#endif
typedef float float32;
typedef double float64;
#ifdef FLOATX80
typedef long double floatx80;
#endif
typedef union {
float32 f;
uint32_t i;
} float32u;
typedef union {
float64 f;
uint64_t i;
} float64u;
#ifdef FLOATX80
typedef union {
floatx80 f;
struct {
uint64_t low;
uint16_t high;
} i;
} floatx80u;
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point rounding mode.
*----------------------------------------------------------------------------*/
#if defined(_BSD) && !defined(__APPLE__)
enum {
float_round_nearest_even = FP_RN,
float_round_down = FE_RM,
float_round_up = FE_RP,
float_round_to_zero = FE_RZ
};
#elif defined(__arm__)
enum {
float_round_nearest_even = 0,
float_round_down = 1,
float_round_up = 2,
float_round_to_zero = 3
};
#else
enum {
float_round_nearest_even = FE_TONEAREST,
float_round_down = FE_DOWNWARD,
float_round_up = FE_UPWARD,
float_round_to_zero = FE_TOWARDZERO
};
#endif
typedef struct float_status {
signed char float_rounding_mode;
#ifdef FLOATX80
signed char floatx80_rounding_precision;
#endif
} float_status;
void set_float_rounding_mode(int val STATUS_PARAM);
#ifdef FLOATX80
void set_floatx80_rounding_precision(int val STATUS_PARAM);
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE integer-to-floating-point conversion routines.
*----------------------------------------------------------------------------*/
float32 int32_to_float32( int STATUS_PARAM);
float64 int32_to_float64( int STATUS_PARAM);
#ifdef FLOATX80
floatx80 int32_to_floatx80( int STATUS_PARAM);
#endif
#ifdef FLOAT128
float128 int32_to_float128( int STATUS_PARAM);
#endif
float32 int64_to_float32( int64_t STATUS_PARAM);
float64 int64_to_float64( int64_t STATUS_PARAM);
#ifdef FLOATX80
floatx80 int64_to_floatx80( int64_t STATUS_PARAM);
#endif
#ifdef FLOAT128
float128 int64_to_float128( int64_t STATUS_PARAM);
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision conversion routines.
*----------------------------------------------------------------------------*/
int float32_to_int32( float32 STATUS_PARAM);
int float32_to_int32_round_to_zero( float32 STATUS_PARAM);
int64_t float32_to_int64( float32 STATUS_PARAM);
int64_t float32_to_int64_round_to_zero( float32 STATUS_PARAM);
float64 float32_to_float64( float32 STATUS_PARAM);
#ifdef FLOATX80
floatx80 float32_to_floatx80( float32 STATUS_PARAM);
#endif
#ifdef FLOAT128
float128 float32_to_float128( float32 STATUS_PARAM);
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision operations.
*----------------------------------------------------------------------------*/
float32 float32_round_to_int( float32 STATUS_PARAM);
INLINE float32 float32_add( float32 a, float32 b STATUS_PARAM)
{
return a + b;
}
INLINE float32 float32_sub( float32 a, float32 b STATUS_PARAM)
{
return a - b;
}
INLINE float32 float32_mul( float32 a, float32 b STATUS_PARAM)
{
return a * b;
}
INLINE float32 float32_div( float32 a, float32 b STATUS_PARAM)
{
return a / b;
}
float32 float32_rem( float32, float32 STATUS_PARAM);
float32 float32_sqrt( float32 STATUS_PARAM);
INLINE char float32_eq( float32 a, float32 b STATUS_PARAM)
{
return a == b;
}
INLINE char float32_le( float32 a, float32 b STATUS_PARAM)
{
return a <= b;
}
INLINE char float32_lt( float32 a, float32 b STATUS_PARAM)
{
return a < b;
}
INLINE char float32_eq_signaling( float32 a, float32 b STATUS_PARAM)
{
return a <= b && a >= b;
}
INLINE char float32_le_quiet( float32 a, float32 b STATUS_PARAM)
{
return islessequal(a, b);
}
INLINE char float32_lt_quiet( float32 a, float32 b STATUS_PARAM)
{
return isless(a, b);
}
INLINE char float32_unordered( float32 a, float32 b STATUS_PARAM)
{
return isunordered(a, b);
}
char float32_compare( float32, float32 STATUS_PARAM );
char float32_compare_quiet( float32, float32 STATUS_PARAM );
char float32_is_signaling_nan( float32 );
INLINE float32 float32_abs(float32 a)
{
return fabsf(a);
}
INLINE float32 float32_chs(float32 a)
{
return -a;
}
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision conversion routines.
*----------------------------------------------------------------------------*/
int float64_to_int32( float64 STATUS_PARAM );
int float64_to_int32_round_to_zero( float64 STATUS_PARAM );
int64_t float64_to_int64( float64 STATUS_PARAM );
int64_t float64_to_int64_round_to_zero( float64 STATUS_PARAM );
float32 float64_to_float32( float64 STATUS_PARAM );
#ifdef FLOATX80
floatx80 float64_to_floatx80( float64 STATUS_PARAM );
#endif
#ifdef FLOAT128
float128 float64_to_float128( float64 STATUS_PARAM );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision operations.
*----------------------------------------------------------------------------*/
float64 float64_round_to_int( float64 STATUS_PARAM );
INLINE float64 float64_add( float64 a, float64 b STATUS_PARAM)
{
return a + b;
}
INLINE float64 float64_sub( float64 a, float64 b STATUS_PARAM)
{
return a - b;
}
INLINE float64 float64_mul( float64 a, float64 b STATUS_PARAM)
{
return a * b;
}
INLINE float64 float64_div( float64 a, float64 b STATUS_PARAM)
{
return a / b;
}
float64 float64_rem( float64, float64 STATUS_PARAM );
float64 float64_sqrt( float64 STATUS_PARAM );
INLINE char float64_eq( float64 a, float64 b STATUS_PARAM)
{
return a == b;
}
INLINE char float64_le( float64 a, float64 b STATUS_PARAM)
{
return a <= b;
}
INLINE char float64_lt( float64 a, float64 b STATUS_PARAM)
{
return a < b;
}
INLINE char float64_eq_signaling( float64 a, float64 b STATUS_PARAM)
{
return a <= b && a >= b;
}
INLINE char float64_le_quiet( float64 a, float64 b STATUS_PARAM)
{
return islessequal(a, b);
}
INLINE char float64_lt_quiet( float64 a, float64 b STATUS_PARAM)
{
return isless(a, b);
}
INLINE char float64_unordered( float64 a, float64 b STATUS_PARAM)
{
return isunordered(a, b);
}
char float64_compare( float64, float64 STATUS_PARAM );
char float64_compare_quiet( float64, float64 STATUS_PARAM );
char float64_is_signaling_nan( float64 );
INLINE float64 float64_abs(float64 a)
{
return fabs(a);
}
INLINE float64 float64_chs(float64 a)
{
return -a;
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision conversion routines.
*----------------------------------------------------------------------------*/
int floatx80_to_int32( floatx80 STATUS_PARAM );
int floatx80_to_int32_round_to_zero( floatx80 STATUS_PARAM );
int64_t floatx80_to_int64( floatx80 STATUS_PARAM);
int64_t floatx80_to_int64_round_to_zero( floatx80 STATUS_PARAM);
float32 floatx80_to_float32( floatx80 STATUS_PARAM );
float64 floatx80_to_float64( floatx80 STATUS_PARAM );
#ifdef FLOAT128
float128 floatx80_to_float128( floatx80 STATUS_PARAM );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision operations.
*----------------------------------------------------------------------------*/
floatx80 floatx80_round_to_int( floatx80 STATUS_PARAM );
INLINE floatx80 floatx80_add( floatx80 a, floatx80 b STATUS_PARAM)
{
return a + b;
}
INLINE floatx80 floatx80_sub( floatx80 a, floatx80 b STATUS_PARAM)
{
return a - b;
}
INLINE floatx80 floatx80_mul( floatx80 a, floatx80 b STATUS_PARAM)
{
return a * b;
}
INLINE floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM)
{
return a / b;
}
floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM );
floatx80 floatx80_sqrt( floatx80 STATUS_PARAM );
INLINE char floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM)
{
return a == b;
}
INLINE char floatx80_le( floatx80 a, floatx80 b STATUS_PARAM)
{
return a <= b;
}
INLINE char floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM)
{
return a < b;
}
INLINE char floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM)
{
return a <= b && a >= b;
}
INLINE char floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM)
{
return islessequal(a, b);
}
INLINE char floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM)
{
return isless(a, b);
}
INLINE char floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM)
{
return isunordered(a, b);
}
char floatx80_compare( floatx80, floatx80 STATUS_PARAM );
char floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM );
char floatx80_is_signaling_nan( floatx80 );
INLINE floatx80 floatx80_abs(floatx80 a)
{
return fabsl(a);
}
INLINE floatx80 floatx80_chs(floatx80 a)
{
return -a;
}
#endif
-464
View File
@@ -1,464 +0,0 @@
/*============================================================================
This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*----------------------------------------------------------------------------
| Underflow tininess-detection mode, statically initialized to default value.
| (The declaration in `softfloat.h' must match the `int8' type here.)
*----------------------------------------------------------------------------*/
int8 float_detect_tininess = float_tininess_after_rounding;
/*----------------------------------------------------------------------------
| Raises the exceptions specified by `flags'. Floating-point traps can be
| defined here if desired. It is currently not possible for such a trap
| to substitute a result value. If traps are not implemented, this routine
| should be simply `float_exception_flags |= flags;'.
*----------------------------------------------------------------------------*/
void float_raise( int8 flags STATUS_PARAM )
{
STATUS(float_exception_flags) |= flags;
}
/*----------------------------------------------------------------------------
| Internal canonical NaN format.
*----------------------------------------------------------------------------*/
typedef struct {
flag sign;
bits64 high, low;
} commonNaNT;
/*----------------------------------------------------------------------------
| The pattern for a default generated single-precision NaN.
*----------------------------------------------------------------------------*/
#define float32_default_nan 0xFFC00000
/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is a NaN;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float32_is_nan( float32 a )
{
return ( 0xFF000000 < (bits32) ( a<<1 ) );
}
/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is a signaling
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float32_is_signaling_nan( float32 a )
{
return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
}
/*----------------------------------------------------------------------------
| Returns the result of converting the single-precision floating-point NaN
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
| exception is raised.
*----------------------------------------------------------------------------*/
static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM )
{
commonNaNT z;
if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR );
z.sign = a>>31;
z.low = 0;
z.high = ( (bits64) a )<<41;
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the single-
| precision floating-point format.
*----------------------------------------------------------------------------*/
static float32 commonNaNToFloat32( commonNaNT a )
{
return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 );
}
/*----------------------------------------------------------------------------
| Takes two single-precision floating-point values `a' and `b', one of which
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
| signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = float32_is_nan( a );
aIsSignalingNaN = float32_is_signaling_nan( a );
bIsNaN = float32_is_nan( b );
bIsSignalingNaN = float32_is_signaling_nan( b );
a |= 0x00400000;
b |= 0x00400000;
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
if ( aIsSignalingNaN ) {
if ( bIsSignalingNaN ) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if ( aIsNaN ) {
if ( bIsSignalingNaN | ! bIsNaN ) return a;
returnLargerSignificand:
if ( (bits32) ( a<<1 ) < (bits32) ( b<<1 ) ) return b;
if ( (bits32) ( b<<1 ) < (bits32) ( a<<1 ) ) return a;
return ( a < b ) ? a : b;
}
else {
return b;
}
}
/*----------------------------------------------------------------------------
| The pattern for a default generated double-precision NaN.
*----------------------------------------------------------------------------*/
#define float64_default_nan LIT64( 0xFFF8000000000000 )
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is a NaN;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float64_is_nan( float64 a )
{
return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) );
}
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is a signaling
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float64_is_signaling_nan( float64 a )
{
return
( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
&& ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
}
/*----------------------------------------------------------------------------
| Returns the result of converting the double-precision floating-point NaN
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
| exception is raised.
*----------------------------------------------------------------------------*/
static commonNaNT float64ToCommonNaN( float64 a STATUS_PARAM)
{
commonNaNT z;
if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR);
z.sign = a>>63;
z.low = 0;
z.high = a<<12;
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the double-
| precision floating-point format.
*----------------------------------------------------------------------------*/
static float64 commonNaNToFloat64( commonNaNT a )
{
return
( ( (bits64) a.sign )<<63 )
| LIT64( 0x7FF8000000000000 )
| ( a.high>>12 );
}
/*----------------------------------------------------------------------------
| Takes two double-precision floating-point values `a' and `b', one of which
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
| signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = float64_is_nan( a );
aIsSignalingNaN = float64_is_signaling_nan( a );
bIsNaN = float64_is_nan( b );
bIsSignalingNaN = float64_is_signaling_nan( b );
a |= LIT64( 0x0008000000000000 );
b |= LIT64( 0x0008000000000000 );
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
if ( aIsSignalingNaN ) {
if ( bIsSignalingNaN ) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if ( aIsNaN ) {
if ( bIsSignalingNaN | ! bIsNaN ) return a;
returnLargerSignificand:
if ( (bits64) ( a<<1 ) < (bits64) ( b<<1 ) ) return b;
if ( (bits64) ( b<<1 ) < (bits64) ( a<<1 ) ) return a;
return ( a < b ) ? a : b;
}
else {
return b;
}
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| The pattern for a default generated extended double-precision NaN. The
| `high' and `low' values hold the most- and least-significant bits,
| respectively.
*----------------------------------------------------------------------------*/
#define floatx80_default_nan_high 0xFFFF
#define floatx80_default_nan_low LIT64( 0xC000000000000000 )
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is a
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag floatx80_is_nan( floatx80 a )
{
return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 );
}
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is a
| signaling NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag floatx80_is_signaling_nan( floatx80 a )
{
bits64 aLow;
aLow = a.low & ~ LIT64( 0x4000000000000000 );
return
( ( a.high & 0x7FFF ) == 0x7FFF )
&& (bits64) ( aLow<<1 )
&& ( a.low == aLow );
}
/*----------------------------------------------------------------------------
| Returns the result of converting the extended double-precision floating-
| point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the
| invalid exception is raised.
*----------------------------------------------------------------------------*/
static commonNaNT floatx80ToCommonNaN( floatx80 a STATUS_PARAM)
{
commonNaNT z;
if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR);
z.sign = a.high>>15;
z.low = 0;
z.high = a.low<<1;
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the extended
| double-precision floating-point format.
*----------------------------------------------------------------------------*/
static floatx80 commonNaNToFloatx80( commonNaNT a )
{
floatx80 z;
z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 );
z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF;
return z;
}
/*----------------------------------------------------------------------------
| Takes two extended double-precision floating-point values `a' and `b', one
| of which is a NaN, and returns the appropriate NaN result. If either `a' or
| `b' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = floatx80_is_nan( a );
aIsSignalingNaN = floatx80_is_signaling_nan( a );
bIsNaN = floatx80_is_nan( b );
bIsSignalingNaN = floatx80_is_signaling_nan( b );
a.low |= LIT64( 0xC000000000000000 );
b.low |= LIT64( 0xC000000000000000 );
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
if ( aIsSignalingNaN ) {
if ( bIsSignalingNaN ) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if ( aIsNaN ) {
if ( bIsSignalingNaN | ! bIsNaN ) return a;
returnLargerSignificand:
if ( a.low < b.low ) return b;
if ( b.low < a.low ) return a;
return ( a.high < b.high ) ? a : b;
}
else {
return b;
}
}
#endif
#ifdef FLOAT128
/*----------------------------------------------------------------------------
| The pattern for a default generated quadruple-precision NaN. The `high' and
| `low' values hold the most- and least-significant bits, respectively.
*----------------------------------------------------------------------------*/
#define float128_default_nan_high LIT64( 0xFFFF800000000000 )
#define float128_default_nan_low LIT64( 0x0000000000000000 )
/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point value `a' is a NaN;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float128_is_nan( float128 a )
{
return
( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
&& ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
}
/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point value `a' is a
| signaling NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float128_is_signaling_nan( float128 a )
{
return
( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
&& ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
}
/*----------------------------------------------------------------------------
| Returns the result of converting the quadruple-precision floating-point NaN
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
| exception is raised.
*----------------------------------------------------------------------------*/
static commonNaNT float128ToCommonNaN( float128 a STATUS_PARAM)
{
commonNaNT z;
if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR);
z.sign = a.high>>63;
shortShift128Left( a.high, a.low, 16, &z.high, &z.low );
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the quadruple-
| precision floating-point format.
*----------------------------------------------------------------------------*/
static float128 commonNaNToFloat128( commonNaNT a )
{
float128 z;
shift128Right( a.high, a.low, 16, &z.high, &z.low );
z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 );
return z;
}
/*----------------------------------------------------------------------------
| Takes two quadruple-precision floating-point values `a' and `b', one of
| which is a NaN, and returns the appropriate NaN result. If either `a' or
| `b' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = float128_is_nan( a );
aIsSignalingNaN = float128_is_signaling_nan( a );
bIsNaN = float128_is_nan( b );
bIsSignalingNaN = float128_is_signaling_nan( b );
a.high |= LIT64( 0x0000800000000000 );
b.high |= LIT64( 0x0000800000000000 );
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
if ( aIsSignalingNaN ) {
if ( bIsSignalingNaN ) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if ( aIsNaN ) {
if ( bIsSignalingNaN | ! bIsNaN ) return a;
returnLargerSignificand:
if ( lt128( a.high<<1, a.low, b.high<<1, b.low ) ) return b;
if ( lt128( b.high<<1, b.low, a.high<<1, a.low ) ) return a;
return ( a.high < b.high ) ? a : b;
}
else {
return b;
}
}
#endif
-5320
View File
File diff suppressed because it is too large. Load diff
-398
View File
@@ -1,398 +0,0 @@
/*============================================================================
This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
#ifndef SOFTFLOAT_H
#define SOFTFLOAT_H
#include <inttypes.h>
#include "config.h"
/*----------------------------------------------------------------------------
| Each of the following `typedef's defines the most convenient type that holds
| integers of at least as many bits as specified. For example, `uint8' should
| be the most convenient type that can hold unsigned integers of as many as
| 8 bits. The `flag' type must be able to hold either a 0 or 1. For most
| implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed
| to the same as `int'.
*----------------------------------------------------------------------------*/
typedef char flag;
typedef uint8_t uint8;
typedef int8_t int8;
typedef int uint16;
typedef int int16;
typedef unsigned int uint32;
typedef signed int int32;
typedef uint64_t uint64;
typedef int64_t int64;
/*----------------------------------------------------------------------------
| Each of the following `typedef's defines a type that holds integers
| of _exactly_ the number of bits specified. For instance, for most
| implementation of C, `bits16' and `sbits16' should be `typedef'ed to
| `unsigned short int' and `signed short int' (or `short int'), respectively.
*----------------------------------------------------------------------------*/
typedef uint8_t bits8;
typedef int8_t sbits8;
typedef uint16_t bits16;
typedef int16_t sbits16;
typedef uint32_t bits32;
typedef int32_t sbits32;
typedef uint64_t bits64;
typedef int64_t sbits64;
#define LIT64( a ) a##LL
#define INLINE static inline
/*----------------------------------------------------------------------------
| The macro `FLOATX80' must be defined to enable the extended double-precision
| floating-point format `floatx80'. If this macro is not defined, the
| `floatx80' type will not be defined, and none of the functions that either
| input or output the `floatx80' type will be defined. The same applies to
| the `FLOAT128' macro and the quadruple-precision format `float128'.
*----------------------------------------------------------------------------*/
#ifdef CONFIG_SOFTFLOAT
/* bit exact soft float support */
#define FLOATX80
#define FLOAT128
#else
/* native float support */
#if (defined(__i386__) || defined(__x86_64__)) && !defined(_BSD)
#define FLOATX80
#endif
#endif /* !CONFIG_SOFTFLOAT */
#define STATUS_PARAM , float_status *status
#define STATUS(field) status->field
#define STATUS_VAR , status
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point ordering relations
*----------------------------------------------------------------------------*/
enum {
float_relation_less = -1,
float_relation_equal = 0,
float_relation_greater = 1,
float_relation_unordered = 2
};
#ifdef CONFIG_SOFTFLOAT
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point types.
*----------------------------------------------------------------------------*/
typedef uint32_t float32;
typedef uint64_t float64;
#ifdef FLOATX80
typedef struct {
uint64_t low;
uint16_t high;
} floatx80;
#endif
#ifdef FLOAT128
typedef struct {
#ifdef WORDS_BIGENDIAN
uint64_t high, low;
#else
uint64_t low, high;
#endif
} float128;
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point underflow tininess-detection mode.
*----------------------------------------------------------------------------*/
enum {
float_tininess_after_rounding = 0,
float_tininess_before_rounding = 1
};
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point rounding mode.
*----------------------------------------------------------------------------*/
enum {
float_round_nearest_even = 0,
float_round_down = 1,
float_round_up = 2,
float_round_to_zero = 3
};
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point exception flags.
*----------------------------------------------------------------------------*/
enum {
float_flag_invalid = 1,
float_flag_divbyzero = 4,
float_flag_overflow = 8,
float_flag_underflow = 16,
float_flag_inexact = 32
};
typedef struct float_status {
signed char float_detect_tininess;
signed char float_rounding_mode;
signed char float_exception_flags;
#ifdef FLOATX80
signed char floatx80_rounding_precision;
#endif
} float_status;
void set_float_rounding_mode(int val STATUS_PARAM);
void set_float_exception_flags(int val STATUS_PARAM);
INLINE int get_float_exception_flags(float_status *status)
{
return STATUS(float_exception_flags);
}
#ifdef FLOATX80
void set_floatx80_rounding_precision(int val STATUS_PARAM);
#endif
/*----------------------------------------------------------------------------
| Routine to raise any or all of the software IEC/IEEE floating-point
| exception flags.
*----------------------------------------------------------------------------*/
void float_raise( signed char STATUS_PARAM);
/*----------------------------------------------------------------------------
| Software IEC/IEEE integer-to-floating-point conversion routines.
*----------------------------------------------------------------------------*/
float32 int32_to_float32( int STATUS_PARAM );
float64 int32_to_float64( int STATUS_PARAM );
float32 uint32_to_float32( unsigned int STATUS_PARAM );
float64 uint32_to_float64( unsigned int STATUS_PARAM );
#ifdef FLOATX80
floatx80 int32_to_floatx80( int STATUS_PARAM );
#endif
#ifdef FLOAT128
float128 int32_to_float128( int STATUS_PARAM );
#endif
float32 int64_to_float32( int64_t STATUS_PARAM );
float64 int64_to_float64( int64_t STATUS_PARAM );
#ifdef FLOATX80
floatx80 int64_to_floatx80( int64_t STATUS_PARAM );
#endif
#ifdef FLOAT128
float128 int64_to_float128( int64_t STATUS_PARAM );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision conversion routines.
*----------------------------------------------------------------------------*/
int float32_to_int32( float32 STATUS_PARAM );
int float32_to_int32_round_to_zero( float32 STATUS_PARAM );
unsigned int float32_to_uint32( float32 STATUS_PARAM );
unsigned int float32_to_uint32_round_to_zero( float32 STATUS_PARAM );
int64_t float32_to_int64( float32 STATUS_PARAM );
int64_t float32_to_int64_round_to_zero( float32 STATUS_PARAM );
float64 float32_to_float64( float32 STATUS_PARAM );
#ifdef FLOATX80
floatx80 float32_to_floatx80( float32 STATUS_PARAM );
#endif
#ifdef FLOAT128
float128 float32_to_float128( float32 STATUS_PARAM );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision operations.
*----------------------------------------------------------------------------*/
float32 float32_round_to_int( float32 STATUS_PARAM );
float32 float32_add( float32, float32 STATUS_PARAM );
float32 float32_sub( float32, float32 STATUS_PARAM );
float32 float32_mul( float32, float32 STATUS_PARAM );
float32 float32_div( float32, float32 STATUS_PARAM );
float32 float32_rem( float32, float32 STATUS_PARAM );
float32 float32_sqrt( float32 STATUS_PARAM );
char float32_eq( float32, float32 STATUS_PARAM );
char float32_le( float32, float32 STATUS_PARAM );
char float32_lt( float32, float32 STATUS_PARAM );
char float32_eq_signaling( float32, float32 STATUS_PARAM );
char float32_le_quiet( float32, float32 STATUS_PARAM );
char float32_lt_quiet( float32, float32 STATUS_PARAM );
char float32_compare( float32, float32 STATUS_PARAM );
char float32_compare_quiet( float32, float32 STATUS_PARAM );
char float32_is_signaling_nan( float32 );
INLINE float32 float32_abs(float32 a)
{
return a & 0x7fffffff;
}
INLINE float32 float32_chs(float32 a)
{
return a ^ 0x80000000;
}
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision conversion routines.
*----------------------------------------------------------------------------*/
int float64_to_int32( float64 STATUS_PARAM );
int float64_to_int32_round_to_zero( float64 STATUS_PARAM );
unsigned int float64_to_uint32( float64 STATUS_PARAM );
unsigned int float64_to_uint32_round_to_zero( float64 STATUS_PARAM );
int64_t float64_to_int64( float64 STATUS_PARAM );
int64_t float64_to_int64_round_to_zero( float64 STATUS_PARAM );
float32 float64_to_float32( float64 STATUS_PARAM );
#ifdef FLOATX80
floatx80 float64_to_floatx80( float64 STATUS_PARAM );
#endif
#ifdef FLOAT128
float128 float64_to_float128( float64 STATUS_PARAM );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision operations.
*----------------------------------------------------------------------------*/
float64 float64_round_to_int( float64 STATUS_PARAM );
float64 float64_add( float64, float64 STATUS_PARAM );
float64 float64_sub( float64, float64 STATUS_PARAM );
float64 float64_mul( float64, float64 STATUS_PARAM );
float64 float64_div( float64, float64 STATUS_PARAM );
float64 float64_rem( float64, float64 STATUS_PARAM );
float64 float64_sqrt( float64 STATUS_PARAM );
char float64_eq( float64, float64 STATUS_PARAM );
char float64_le( float64, float64 STATUS_PARAM );
char float64_lt( float64, float64 STATUS_PARAM );
char float64_eq_signaling( float64, float64 STATUS_PARAM );
char float64_le_quiet( float64, float64 STATUS_PARAM );
char float64_lt_quiet( float64, float64 STATUS_PARAM );
char float64_compare( float64, float64 STATUS_PARAM );
char float64_compare_quiet( float64, float64 STATUS_PARAM );
char float64_is_signaling_nan( float64 );
INLINE float64 float64_abs(float64 a)
{
return a & 0x7fffffffffffffffLL;
}
INLINE float64 float64_chs(float64 a)
{
return a ^ 0x8000000000000000LL;
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision conversion routines.
*----------------------------------------------------------------------------*/
int floatx80_to_int32( floatx80 STATUS_PARAM );
int floatx80_to_int32_round_to_zero( floatx80 STATUS_PARAM );
int64_t floatx80_to_int64( floatx80 STATUS_PARAM );
int64_t floatx80_to_int64_round_to_zero( floatx80 STATUS_PARAM );
float32 floatx80_to_float32( floatx80 STATUS_PARAM );
float64 floatx80_to_float64( floatx80 STATUS_PARAM );
#ifdef FLOAT128
float128 floatx80_to_float128( floatx80 STATUS_PARAM );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision operations.
*----------------------------------------------------------------------------*/
floatx80 floatx80_round_to_int( floatx80 STATUS_PARAM );
floatx80 floatx80_add( floatx80, floatx80 STATUS_PARAM );
floatx80 floatx80_sub( floatx80, floatx80 STATUS_PARAM );
floatx80 floatx80_mul( floatx80, floatx80 STATUS_PARAM );
floatx80 floatx80_div( floatx80, floatx80 STATUS_PARAM );
floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM );
floatx80 floatx80_sqrt( floatx80 STATUS_PARAM );
char floatx80_eq( floatx80, floatx80 STATUS_PARAM );
char floatx80_le( floatx80, floatx80 STATUS_PARAM );
char floatx80_lt( floatx80, floatx80 STATUS_PARAM );
char floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM );
char floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM );
char floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM );
char floatx80_is_signaling_nan( floatx80 );
INLINE floatx80 floatx80_abs(floatx80 a)
{
a.high &= 0x7fff;
return a;
}
INLINE floatx80 floatx80_chs(floatx80 a)
{
a.high ^= 0x8000;
return a;
}
#endif
#ifdef FLOAT128
/*----------------------------------------------------------------------------
| Software IEC/IEEE quadruple-precision conversion routines.
*----------------------------------------------------------------------------*/
int float128_to_int32( float128 STATUS_PARAM );
int float128_to_int32_round_to_zero( float128 STATUS_PARAM );
int64_t float128_to_int64( float128 STATUS_PARAM );
int64_t float128_to_int64_round_to_zero( float128 STATUS_PARAM );
float32 float128_to_float32( float128 STATUS_PARAM );
float64 float128_to_float64( float128 STATUS_PARAM );
#ifdef FLOATX80
floatx80 float128_to_floatx80( float128 STATUS_PARAM );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE quadruple-precision operations.
*----------------------------------------------------------------------------*/
float128 float128_round_to_int( float128 STATUS_PARAM );
float128 float128_add( float128, float128 STATUS_PARAM );
float128 float128_sub( float128, float128 STATUS_PARAM );
float128 float128_mul( float128, float128 STATUS_PARAM );
float128 float128_div( float128, float128 STATUS_PARAM );
float128 float128_rem( float128, float128 STATUS_PARAM );
float128 float128_sqrt( float128 STATUS_PARAM );
char float128_eq( float128, float128 STATUS_PARAM );
char float128_le( float128, float128 STATUS_PARAM );
char float128_lt( float128, float128 STATUS_PARAM );
char float128_eq_signaling( float128, float128 STATUS_PARAM );
char float128_le_quiet( float128, float128 STATUS_PARAM );
char float128_lt_quiet( float128, float128 STATUS_PARAM );
char float128_is_signaling_nan( float128 );
INLINE float128 float128_abs(float128 a)
{
a.high &= 0x7fffffffffffffffLL;
return a;
}
INLINE float128 float128_chs(float128 a)
{
a.high ^= 0x8000000000000000LL;
return a;
}
#endif
#else /* CONFIG_SOFTFLOAT */
#include "softfloat-native.h"
#endif /* !CONFIG_SOFTFLOAT */
#endif /* !SOFTFLOAT_H */
-823
View File
@@ -1,823 +0,0 @@
/*
* gdb server stub
*
* Copyright (c) 2003-2005 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef CONFIG_USER_ONLY
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "qemu.h"
#else
#include "vl.h"
#endif
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <signal.h>
//#define DEBUG_GDB
enum RSState {
RS_IDLE,
RS_GETLINE,
RS_CHKSUM1,
RS_CHKSUM2,
};
/* XXX: This is not thread safe. Do we care? */
static int gdbserver_fd = -1;
typedef struct GDBState {
enum RSState state; /* parsing state */
int fd;
char line_buf[4096];
int line_buf_index;
int line_csum;
#ifdef CONFIG_USER_ONLY
int running_state;
#endif
} GDBState;
#ifdef CONFIG_USER_ONLY
/* XXX: remove this hack. */
static GDBState gdbserver_state;
#endif
static int get_char(GDBState *s)
{
uint8_t ch;
int ret;
for(;;) {
ret = read(s->fd, &ch, 1);
if (ret < 0) {
if (errno != EINTR && errno != EAGAIN)
return -1;
} else if (ret == 0) {
return -1;
} else {
break;
}
}
return ch;
}
static void put_buffer(GDBState *s, const uint8_t *buf, int len)
{
int ret;
while (len > 0) {
ret = write(s->fd, buf, len);
if (ret < 0) {
if (errno != EINTR && errno != EAGAIN)
return;
} else {
buf += ret;
len -= ret;
}
}
}
static inline int fromhex(int v)
{
if (v >= '0' && v <= '9')
return v - '0';
else if (v >= 'A' && v <= 'F')
return v - 'A' + 10;
else if (v >= 'a' && v <= 'f')
return v - 'a' + 10;
else
return 0;
}
static inline int tohex(int v)
{
if (v < 10)
return v + '0';
else
return v - 10 + 'a';
}
static void memtohex(char *buf, const uint8_t *mem, int len)
{
int i, c;
char *q;
q = buf;
for(i = 0; i < len; i++) {
c = mem[i];
*q++ = tohex(c >> 4);
*q++ = tohex(c & 0xf);
}
*q = '\0';
}
static void hextomem(uint8_t *mem, const char *buf, int len)
{
int i;
for(i = 0; i < len; i++) {
mem[i] = (fromhex(buf[0]) << 4) | fromhex(buf[1]);
buf += 2;
}
}
/* return -1 if error, 0 if OK */
static int put_packet(GDBState *s, char *buf)
{
char buf1[3];
int len, csum, ch, i;
#ifdef DEBUG_GDB
printf("reply='%s'\n", buf);
#endif
for(;;) {
buf1[0] = '$';
put_buffer(s, buf1, 1);
len = strlen(buf);
put_buffer(s, buf, len);
csum = 0;
for(i = 0; i < len; i++) {
csum += buf[i];
}
buf1[0] = '#';
buf1[1] = tohex((csum >> 4) & 0xf);
buf1[2] = tohex((csum) & 0xf);
put_buffer(s, buf1, 3);
ch = get_char(s);
if (ch < 0)
return -1;
if (ch == '+')
break;
}
return 0;
}
#if defined(TARGET_I386)
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
uint32_t *registers = (uint32_t *)mem_buf;
int i, fpus;
for(i = 0; i < 8; i++) {
registers[i] = env->regs[i];
}
registers[8] = env->eip;
registers[9] = env->eflags;
registers[10] = env->segs[R_CS].selector;
registers[11] = env->segs[R_SS].selector;
registers[12] = env->segs[R_DS].selector;
registers[13] = env->segs[R_ES].selector;
registers[14] = env->segs[R_FS].selector;
registers[15] = env->segs[R_GS].selector;
/* XXX: convert floats */
for(i = 0; i < 8; i++) {
memcpy(mem_buf + 16 * 4 + i * 10, &env->fpregs[i], 10);
}
registers[36] = env->fpuc;
fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
registers[37] = fpus;
registers[38] = 0; /* XXX: convert tags */
registers[39] = 0; /* fiseg */
registers[40] = 0; /* fioff */
registers[41] = 0; /* foseg */
registers[42] = 0; /* fooff */
registers[43] = 0; /* fop */
for(i = 0; i < 16; i++)
tswapls(&registers[i]);
for(i = 36; i < 44; i++)
tswapls(&registers[i]);
return 44 * 4;
}
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
{
uint32_t *registers = (uint32_t *)mem_buf;
int i;
for(i = 0; i < 8; i++) {
env->regs[i] = tswapl(registers[i]);
}
env->eip = tswapl(registers[8]);
env->eflags = tswapl(registers[9]);
#if defined(CONFIG_USER_ONLY)
#define LOAD_SEG(index, sreg)\
if (tswapl(registers[index]) != env->segs[sreg].selector)\
cpu_x86_load_seg(env, sreg, tswapl(registers[index]));
LOAD_SEG(10, R_CS);
LOAD_SEG(11, R_SS);
LOAD_SEG(12, R_DS);
LOAD_SEG(13, R_ES);
LOAD_SEG(14, R_FS);
LOAD_SEG(15, R_GS);
#endif
}
#elif defined (TARGET_PPC)
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
uint32_t *registers = (uint32_t *)mem_buf, tmp;
int i;
/* fill in gprs */
for(i = 0; i < 32; i++) {
registers[i] = tswapl(env->gpr[i]);
}
/* fill in fprs */
for (i = 0; i < 32; i++) {
registers[(i * 2) + 32] = tswapl(*((uint32_t *)&env->fpr[i]));
registers[(i * 2) + 33] = tswapl(*((uint32_t *)&env->fpr[i] + 1));
}
/* nip, msr, ccr, lnk, ctr, xer, mq */
registers[96] = tswapl(env->nip);
registers[97] = tswapl(do_load_msr(env));
tmp = 0;
for (i = 0; i < 8; i++)
tmp |= env->crf[i] << (32 - ((i + 1) * 4));
registers[98] = tswapl(tmp);
registers[99] = tswapl(env->lr);
registers[100] = tswapl(env->ctr);
registers[101] = tswapl(do_load_xer(env));
registers[102] = 0;
return 103 * 4;
}
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
{
uint32_t *registers = (uint32_t *)mem_buf;
int i;
/* fill in gprs */
for (i = 0; i < 32; i++) {
env->gpr[i] = tswapl(registers[i]);
}
/* fill in fprs */
for (i = 0; i < 32; i++) {
*((uint32_t *)&env->fpr[i]) = tswapl(registers[(i * 2) + 32]);
*((uint32_t *)&env->fpr[i] + 1) = tswapl(registers[(i * 2) + 33]);
}
/* nip, msr, ccr, lnk, ctr, xer, mq */
env->nip = tswapl(registers[96]);
do_store_msr(env, tswapl(registers[97]));
registers[98] = tswapl(registers[98]);
for (i = 0; i < 8; i++)
env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF;
env->lr = tswapl(registers[99]);
env->ctr = tswapl(registers[100]);
do_store_xer(env, tswapl(registers[101]));
}
#elif defined (TARGET_SPARC)
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
target_ulong *registers = (target_ulong *)mem_buf;
int i;
/* fill in g0..g7 */
for(i = 0; i < 7; i++) {
registers[i] = tswapl(env->gregs[i]);
}
/* fill in register window */
for(i = 0; i < 24; i++) {
registers[i + 8] = tswapl(env->regwptr[i]);
}
/* fill in fprs */
for (i = 0; i < 32; i++) {
registers[i + 32] = tswapl(*((uint32_t *)&env->fpr[i]));
}
#ifndef TARGET_SPARC64
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
registers[64] = tswapl(env->y);
{
target_ulong tmp;
tmp = GET_PSR(env);
registers[65] = tswapl(tmp);
}
registers[66] = tswapl(env->wim);
registers[67] = tswapl(env->tbr);
registers[68] = tswapl(env->pc);
registers[69] = tswapl(env->npc);
registers[70] = tswapl(env->fsr);
registers[71] = 0; /* csr */
registers[72] = 0;
return 73 * sizeof(target_ulong);
#else
for (i = 0; i < 32; i += 2) {
registers[i/2 + 64] = tswapl(*((uint64_t *)&env->fpr[i]));
}
registers[81] = tswapl(env->pc);
registers[82] = tswapl(env->npc);
registers[83] = tswapl(env->tstate[env->tl]);
registers[84] = tswapl(env->fsr);
registers[85] = tswapl(env->fprs);
registers[86] = tswapl(env->y);
return 87 * sizeof(target_ulong);
#endif
}
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
{
target_ulong *registers = (target_ulong *)mem_buf;
int i;
/* fill in g0..g7 */
for(i = 0; i < 7; i++) {
env->gregs[i] = tswapl(registers[i]);
}
/* fill in register window */
for(i = 0; i < 24; i++) {
env->regwptr[i] = tswapl(registers[i + 8]);
}
/* fill in fprs */
for (i = 0; i < 32; i++) {
*((uint32_t *)&env->fpr[i]) = tswapl(registers[i + 32]);
}
#ifndef TARGET_SPARC64
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
env->y = tswapl(registers[64]);
PUT_PSR(env, tswapl(registers[65]));
env->wim = tswapl(registers[66]);
env->tbr = tswapl(registers[67]);
env->pc = tswapl(registers[68]);
env->npc = tswapl(registers[69]);
env->fsr = tswapl(registers[70]);
#else
for (i = 0; i < 32; i += 2) {
uint64_t tmp;
tmp = tswapl(registers[i/2 + 64]) << 32;
tmp |= tswapl(registers[i/2 + 64 + 1]);
*((uint64_t *)&env->fpr[i]) = tmp;
}
env->pc = tswapl(registers[81]);
env->npc = tswapl(registers[82]);
env->tstate[env->tl] = tswapl(registers[83]);
env->fsr = tswapl(registers[84]);
env->fprs = tswapl(registers[85]);
env->y = tswapl(registers[86]);
#endif
}
#elif defined (TARGET_ARM)
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
int i;
uint8_t *ptr;
ptr = mem_buf;
/* 16 core integer registers (4 bytes each). */
for (i = 0; i < 16; i++)
{
*(uint32_t *)ptr = tswapl(env->regs[i]);
ptr += 4;
}
/* 8 FPA registers (12 bytes each), FPS (4 bytes).
Not yet implemented. */
memset (ptr, 0, 8 * 12 + 4);
ptr += 8 * 12 + 4;
/* CPSR (4 bytes). */
*(uint32_t *)ptr = tswapl (env->cpsr);
ptr += 4;
return ptr - mem_buf;
}
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
{
int i;
uint8_t *ptr;
ptr = mem_buf;
/* Core integer registers. */
for (i = 0; i < 16; i++)
{
env->regs[i] = tswapl(*(uint32_t *)ptr);
ptr += 4;
}
/* Ignore FPA regs and scr. */
ptr += 8 * 12 + 4;
env->cpsr = tswapl(*(uint32_t *)ptr);
}
#else
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
return 0;
}
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
{
}
#endif
static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
{
const char *p;
int ch, reg_size, type;
char buf[4096];
uint8_t mem_buf[2000];
uint32_t *registers;
uint32_t addr, len;
#ifdef DEBUG_GDB
printf("command='%s'\n", line_buf);
#endif
p = line_buf;
ch = *p++;
switch(ch) {
case '?':
/* TODO: Make this return the correct value for user-mode. */
snprintf(buf, sizeof(buf), "S%02x", SIGTRAP);
put_packet(s, buf);
break;
case 'c':
if (*p != '\0') {
addr = strtoul(p, (char **)&p, 16);
#if defined(TARGET_I386)
env->eip = addr;
#elif defined (TARGET_PPC)
env->nip = addr;
#elif defined (TARGET_SPARC)
env->pc = addr;
env->npc = addr + 4;
#endif
}
#ifdef CONFIG_USER_ONLY
s->running_state = 1;
#else
vm_start();
#endif
return RS_IDLE;
case 's':
if (*p != '\0') {
addr = strtoul(p, (char **)&p, 16);
#if defined(TARGET_I386)
env->eip = addr;
#elif defined (TARGET_PPC)
env->nip = addr;
#elif defined (TARGET_SPARC)
env->pc = addr;
env->npc = addr + 4;
#endif
}
cpu_single_step(env, 1);
#ifdef CONFIG_USER_ONLY
s->running_state = 1;
#else
vm_start();
#endif
return RS_IDLE;
case 'g':
reg_size = cpu_gdb_read_registers(env, mem_buf);
memtohex(buf, mem_buf, reg_size);
put_packet(s, buf);
break;
case 'G':
registers = (void *)mem_buf;
len = strlen(p) / 2;
hextomem((uint8_t *)registers, p, len);
cpu_gdb_write_registers(env, mem_buf, len);
put_packet(s, "OK");
break;
case 'm':
addr = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoul(p, NULL, 16);
if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0)
memset(mem_buf, 0, len);
memtohex(buf, mem_buf, len);
put_packet(s, buf);
break;
case 'M':
addr = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoul(p, (char **)&p, 16);
if (*p == ':')
p++;
hextomem(mem_buf, p, len);
if (cpu_memory_rw_debug(env, addr, mem_buf, len, 1) != 0)
put_packet(s, "E14");
else
put_packet(s, "OK");
break;
case 'Z':
type = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
addr = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoul(p, (char **)&p, 16);
if (type == 0 || type == 1) {
if (cpu_breakpoint_insert(env, addr) < 0)
goto breakpoint_error;
put_packet(s, "OK");
} else {
breakpoint_error:
put_packet(s, "E22");
}
break;
case 'z':
type = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
addr = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoul(p, (char **)&p, 16);
if (type == 0 || type == 1) {
cpu_breakpoint_remove(env, addr);
put_packet(s, "OK");
} else {
goto breakpoint_error;
}
break;
default:
// unknown_command:
/* put empty packet */
buf[0] = '\0';
put_packet(s, buf);
break;
}
return RS_IDLE;
}
extern void tb_flush(CPUState *env);
#ifndef CONFIG_USER_ONLY
static void gdb_vm_stopped(void *opaque, int reason)
{
GDBState *s = opaque;
char buf[256];
int ret;
/* disable single step if it was enable */
cpu_single_step(cpu_single_env, 0);
if (reason == EXCP_DEBUG) {
tb_flush(cpu_single_env);
ret = SIGTRAP;
}
else
ret = 0;
snprintf(buf, sizeof(buf), "S%02x", ret);
put_packet(s, buf);
}
#endif
static void gdb_read_byte(GDBState *s, CPUState *env, int ch)
{
int i, csum;
char reply[1];
#ifndef CONFIG_USER_ONLY
if (vm_running) {
/* when the CPU is running, we cannot do anything except stop
it when receiving a char */
vm_stop(EXCP_INTERRUPT);
} else
#endif
{
switch(s->state) {
case RS_IDLE:
if (ch == '$') {
s->line_buf_index = 0;
s->state = RS_GETLINE;
}
break;
case RS_GETLINE:
if (ch == '#') {
s->state = RS_CHKSUM1;
} else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
s->state = RS_IDLE;
} else {
s->line_buf[s->line_buf_index++] = ch;
}
break;
case RS_CHKSUM1:
s->line_buf[s->line_buf_index] = '\0';
s->line_csum = fromhex(ch) << 4;
s->state = RS_CHKSUM2;
break;
case RS_CHKSUM2:
s->line_csum |= fromhex(ch);
csum = 0;
for(i = 0; i < s->line_buf_index; i++) {
csum += s->line_buf[i];
}
if (s->line_csum != (csum & 0xff)) {
reply[0] = '-';
put_buffer(s, reply, 1);
s->state = RS_IDLE;
} else {
reply[0] = '+';
put_buffer(s, reply, 1);
s->state = gdb_handle_packet(s, env, s->line_buf);
}
break;
}
}
}
#ifdef CONFIG_USER_ONLY
int
gdb_handlesig (CPUState *env, int sig)
{
GDBState *s;
char buf[256];
int n;
if (gdbserver_fd < 0)
return sig;
s = &gdbserver_state;
/* disable single step if it was enabled */
cpu_single_step(env, 0);
tb_flush(env);
if (sig != 0)
{
snprintf(buf, sizeof(buf), "S%02x", sig);
put_packet(s, buf);
}
sig = 0;
s->state = RS_IDLE;
s->running_state = 0;
while (s->running_state == 0) {
n = read (s->fd, buf, 256);
if (n > 0)
{
int i;
for (i = 0; i < n; i++)
gdb_read_byte (s, env, buf[i]);
}
else if (n == 0 || errno != EAGAIN)
{
/* XXX: Connection closed. Should probably wait for annother
connection before continuing. */
return sig;
}
}
return sig;
}
/* Tell the remote gdb that the process has exited. */
void gdb_exit(CPUState *env, int code)
{
GDBState *s;
char buf[4];
if (gdbserver_fd < 0)
return;
s = &gdbserver_state;
snprintf(buf, sizeof(buf), "W%02x", code);
put_packet(s, buf);
}
#else
static int gdb_can_read(void *opaque)
{
return 256;
}
static void gdb_read(void *opaque, const uint8_t *buf, int size)
{
GDBState *s = opaque;
int i;
if (size == 0) {
/* end of connection */
qemu_del_vm_stop_handler(gdb_vm_stopped, s);
qemu_del_fd_read_handler(s->fd);
qemu_free(s);
vm_start();
} else {
for(i = 0; i < size; i++)
gdb_read_byte(s, cpu_single_env, buf[i]);
}
}
#endif
static void gdb_accept(void *opaque, const uint8_t *buf, int size)
{
GDBState *s;
struct sockaddr_in sockaddr;
socklen_t len;
int val, fd;
for(;;) {
len = sizeof(sockaddr);
fd = accept(gdbserver_fd, (struct sockaddr *)&sockaddr, &len);
if (fd < 0 && errno != EINTR) {
perror("accept");
return;
} else if (fd >= 0) {
break;
}
}
/* set short latency */
val = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
#ifdef CONFIG_USER_ONLY
s = &gdbserver_state;
memset (s, 0, sizeof (GDBState));
#else
s = qemu_mallocz(sizeof(GDBState));
if (!s) {
close(fd);
return;
}
#endif
s->fd = fd;
fcntl(fd, F_SETFL, O_NONBLOCK);
#ifndef CONFIG_USER_ONLY
/* stop the VM */
vm_stop(EXCP_INTERRUPT);
/* start handling I/O */
qemu_add_fd_read_handler(s->fd, gdb_can_read, gdb_read, s);
/* when the VM is stopped, the following callback is called */
qemu_add_vm_stop_handler(gdb_vm_stopped, s);
#endif
}
static int gdbserver_open(int port)
{
struct sockaddr_in sockaddr;
int fd, val, ret;
fd = socket(PF_INET, SOCK_STREAM, 0);
if (fd < 0) {
perror("socket");
return -1;
}
/* allow fast reuse */
val = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(port);
sockaddr.sin_addr.s_addr = 0;
ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
if (ret < 0) {
perror("bind");
return -1;
}
ret = listen(fd, 0);
if (ret < 0) {
perror("listen");
return -1;
}
#ifndef CONFIG_USER_ONLY
fcntl(fd, F_SETFL, O_NONBLOCK);
#endif
return fd;
}
int gdbserver_start(int port)
{
gdbserver_fd = gdbserver_open(port);
if (gdbserver_fd < 0)
return -1;
/* accept connections */
#ifdef CONFIG_USER_ONLY
gdb_accept (NULL, NULL, 0);
#else
qemu_add_fd_read_handler(gdbserver_fd, NULL, gdb_accept, NULL);
#endif
return 0;
}
-12
View File
@@ -1,12 +0,0 @@
#ifndef GDBSTUB_H
#define GDBSTUB_H
#define DEFAULT_GDBSTUB_PORT 1234
#ifdef CONFIG_USER_ONLY
int gdb_handlesig (CPUState *, int);
void gdb_exit(CPUState *, int);
#endif
int gdbserver_start(int);
#endif
-410
View File
@@ -1,410 +0,0 @@
/*
* QEMU ADB support
*
* Copyright (c) 2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
/* ADB commands */
#define ADB_BUSRESET 0x00
#define ADB_FLUSH 0x01
#define ADB_WRITEREG 0x08
#define ADB_READREG 0x0c
/* ADB device commands */
#define ADB_CMD_SELF_TEST 0xff
#define ADB_CMD_CHANGE_ID 0xfe
#define ADB_CMD_CHANGE_ID_AND_ACT 0xfd
#define ADB_CMD_CHANGE_ID_AND_ENABLE 0x00
/* ADB default device IDs (upper 4 bits of ADB command byte) */
#define ADB_DONGLE 1
#define ADB_KEYBOARD 2
#define ADB_MOUSE 3
#define ADB_TABLET 4
#define ADB_MODEM 5
#define ADB_MISC 7
/* error codes */
#define ADB_RET_NOTPRESENT (-2)
int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len)
{
ADBDevice *d;
int devaddr, cmd, i;
cmd = buf[0] & 0xf;
if (cmd == ADB_BUSRESET) {
for(i = 0; i < s->nb_devices; i++) {
d = &s->devices[i];
if (d->devreset) {
d->devreset(d);
}
}
return 0;
}
devaddr = buf[0] >> 4;
for(i = 0; i < s->nb_devices; i++) {
d = &s->devices[i];
if (d->devaddr == devaddr) {
return d->devreq(d, obuf, buf, len);
}
}
return ADB_RET_NOTPRESENT;
}
/* XXX: move that to cuda ? */
int adb_poll(ADBBusState *s, uint8_t *obuf)
{
ADBDevice *d;
int olen, i;
uint8_t buf[1];
olen = 0;
for(i = 0; i < s->nb_devices; i++) {
if (s->poll_index >= s->nb_devices)
s->poll_index = 0;
d = &s->devices[s->poll_index];
buf[0] = ADB_READREG | (d->devaddr << 4);
olen = adb_request(s, obuf + 1, buf, 1);
/* if there is data, we poll again the same device */
if (olen > 0) {
obuf[0] = buf[0];
olen++;
break;
}
s->poll_index++;
}
return olen;
}
ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
ADBDeviceRequest *devreq,
ADBDeviceReset *devreset,
void *opaque)
{
ADBDevice *d;
if (s->nb_devices >= MAX_ADB_DEVICES)
return NULL;
d = &s->devices[s->nb_devices++];
d->bus = s;
d->devaddr = devaddr;
d->devreq = devreq;
d->devreset = devreset;
d->opaque = opaque;
return d;
}
/***************************************************************/
/* Keyboard ADB device */
typedef struct KBDState {
uint8_t data[128];
int rptr, wptr, count;
} KBDState;
static const uint8_t pc_to_adb_keycode[256] = {
0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54, 0, 1,
2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9,
11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
84, 85, 82, 65, 0, 0, 10,103,111, 0, 0,110, 81, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 94, 0, 93, 0, 0, 0, 0, 0, 0,104,102, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76,125, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 75, 0, 0,124, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,115, 62,116, 0, 59, 0, 60, 0,119,
61,121,114,117, 0, 0, 0, 0, 0, 0, 0, 55,126, 0,127, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
static void adb_kbd_put_keycode(void *opaque, int keycode)
{
ADBDevice *d = opaque;
KBDState *s = d->opaque;
if (s->count < sizeof(s->data)) {
s->data[s->wptr] = keycode;
if (++s->wptr == sizeof(s->data))
s->wptr = 0;
s->count++;
}
}
static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf)
{
static int ext_keycode;
KBDState *s = d->opaque;
int adb_keycode, keycode;
int olen;
olen = 0;
for(;;) {
if (s->count == 0)
break;
keycode = s->data[s->rptr];
if (++s->rptr == sizeof(s->data))
s->rptr = 0;
s->count--;
if (keycode == 0xe0) {
ext_keycode = 1;
} else {
if (ext_keycode)
adb_keycode = pc_to_adb_keycode[keycode | 0x80];
else
adb_keycode = pc_to_adb_keycode[keycode & 0x7f];
obuf[0] = adb_keycode | (keycode & 0x80);
/* NOTE: could put a second keycode if needed */
obuf[1] = 0xff;
olen = 2;
ext_keycode = 0;
break;
}
}
return olen;
}
static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
const uint8_t *buf, int len)
{
KBDState *s = d->opaque;
int cmd, reg, olen;
if ((buf[0] & 0x0f) == ADB_FLUSH) {
/* flush keyboard fifo */
s->wptr = s->rptr = s->count = 0;
return 0;
}
cmd = buf[0] & 0xc;
reg = buf[0] & 0x3;
olen = 0;
switch(cmd) {
case ADB_WRITEREG:
switch(reg) {
case 2:
/* LED status */
break;
case 3:
switch(buf[2]) {
case ADB_CMD_SELF_TEST:
break;
case ADB_CMD_CHANGE_ID:
case ADB_CMD_CHANGE_ID_AND_ACT:
case ADB_CMD_CHANGE_ID_AND_ENABLE:
d->devaddr = buf[1] & 0xf;
break;
default:
/* XXX: check this */
d->devaddr = buf[1] & 0xf;
d->handler = buf[2];
break;
}
}
break;
case ADB_READREG:
switch(reg) {
case 0:
olen = adb_kbd_poll(d, obuf);
break;
case 1:
break;
case 2:
obuf[0] = 0x00; /* XXX: check this */
obuf[1] = 0x07; /* led status */
olen = 2;
break;
case 3:
obuf[0] = d->handler;
obuf[1] = d->devaddr;
olen = 2;
break;
}
break;
}
return olen;
}
static int adb_kbd_reset(ADBDevice *d)
{
KBDState *s = d->opaque;
d->handler = 1;
d->devaddr = ADB_KEYBOARD;
memset(s, 0, sizeof(KBDState));
return 0;
}
void adb_kbd_init(ADBBusState *bus)
{
ADBDevice *d;
KBDState *s;
s = qemu_mallocz(sizeof(KBDState));
d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request,
adb_kbd_reset, s);
adb_kbd_reset(d);
qemu_add_kbd_event_handler(adb_kbd_put_keycode, d);
}
/***************************************************************/
/* Mouse ADB device */
typedef struct MouseState {
int buttons_state, last_buttons_state;
int dx, dy, dz;
} MouseState;
static void adb_mouse_event(void *opaque,
int dx1, int dy1, int dz1, int buttons_state)
{
ADBDevice *d = opaque;
MouseState *s = d->opaque;
s->dx += dx1;
s->dy += dy1;
s->dz += dz1;
s->buttons_state = buttons_state;
}
static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
{
MouseState *s = d->opaque;
int dx, dy;
if (s->last_buttons_state == s->buttons_state &&
s->dx == 0 && s->dy == 0)
return 0;
dx = s->dx;
if (dx < -63)
dx = -63;
else if (dx > 63)
dx = 63;
dy = s->dy;
if (dy < -63)
dy = -63;
else if (dy > 63)
dy = 63;
s->dx -= dx;
s->dy -= dy;
s->last_buttons_state = s->buttons_state;
dx &= 0x7f;
dy &= 0x7f;
if (!(s->buttons_state & MOUSE_EVENT_LBUTTON))
dy |= 0x80;
if (!(s->buttons_state & MOUSE_EVENT_RBUTTON))
dx |= 0x80;
obuf[0] = dy;
obuf[1] = dx;
return 2;
}
static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
const uint8_t *buf, int len)
{
MouseState *s = d->opaque;
int cmd, reg, olen;
if ((buf[0] & 0x0f) == ADB_FLUSH) {
/* flush mouse fifo */
s->buttons_state = s->last_buttons_state;
s->dx = 0;
s->dy = 0;
s->dz = 0;
return 0;
}
cmd = buf[0] & 0xc;
reg = buf[0] & 0x3;
olen = 0;
switch(cmd) {
case ADB_WRITEREG:
switch(reg) {
case 2:
break;
case 3:
switch(buf[2]) {
case ADB_CMD_SELF_TEST:
break;
case ADB_CMD_CHANGE_ID:
case ADB_CMD_CHANGE_ID_AND_ACT:
case ADB_CMD_CHANGE_ID_AND_ENABLE:
d->devaddr = buf[1] & 0xf;
break;
default:
/* XXX: check this */
d->devaddr = buf[1] & 0xf;
break;
}
}
break;
case ADB_READREG:
switch(reg) {
case 0:
olen = adb_mouse_poll(d, obuf);
break;
case 1:
break;
case 3:
obuf[0] = d->handler;
obuf[1] = d->devaddr;
olen = 2;
break;
}
break;
}
return olen;
}
static int adb_mouse_reset(ADBDevice *d)
{
MouseState *s = d->opaque;
d->handler = 2;
d->devaddr = ADB_MOUSE;
memset(s, 0, sizeof(MouseState));
return 0;
}
void adb_mouse_init(ADBBusState *bus)
{
ADBDevice *d;
MouseState *s;
s = qemu_mallocz(sizeof(MouseState));
d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request,
adb_mouse_reset, s);
adb_mouse_reset(d);
qemu_add_mouse_event_handler(adb_mouse_event, d);
}
-313
View File
@@ -1,313 +0,0 @@
/*
* QEMU Adlib emulation
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#define dolog(...) AUD_log ("adlib", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
#ifdef USE_YMF262
#define HAS_YMF262 1
#include "ymf262.h"
void YMF262UpdateOneQEMU(int which, INT16 *dst, int length);
#define SHIFT 2
#else
#include "fmopl.h"
#define SHIFT 1
#endif
#ifdef _WIN32
#include <windows.h>
#define small_delay() Sleep (1)
#else
#define small_delay() usleep (1)
#endif
#define IO_READ_PROTO(name) \
uint32_t name (void *opaque, uint32_t nport)
#define IO_WRITE_PROTO(name) \
void name (void *opaque, uint32_t nport, uint32_t val)
static struct {
int port;
int freq;
} conf = {0x220, 44100};
typedef struct {
int enabled;
int active;
int cparam;
int64_t ticks;
int bufpos;
int16_t *mixbuf;
double interval;
QEMUTimer *ts, *opl_ts;
SWVoice *voice;
int left, pos, samples, bytes_per_second, old_free;
int refcount;
#ifndef USE_YMF262
FM_OPL *opl;
#endif
} AdlibState;
static AdlibState adlib;
static IO_WRITE_PROTO(adlib_write)
{
AdlibState *s = opaque;
int a = nport & 3;
int status;
s->ticks = qemu_get_clock (vm_clock);
s->active = 1;
AUD_enable (s->voice, 1);
#ifdef USE_YMF262
status = YMF262Write (0, a, val);
#else
status = OPLWrite (s->opl, a, val);
#endif
}
static IO_READ_PROTO(adlib_read)
{
AdlibState *s = opaque;
uint8_t data;
int a = nport & 3;
#ifdef USE_YMF262
(void) s;
data = YMF262Read (0, a);
#else
data = OPLRead (s->opl, a);
#endif
return data;
}
static void OPL_timer (void *opaque)
{
AdlibState *s = opaque;
#ifdef USE_YMF262
YMF262TimerOver (s->cparam >> 1, s->cparam & 1);
#else
OPLTimerOver (s->opl, s->cparam);
#endif
qemu_mod_timer (s->opl_ts, qemu_get_clock (vm_clock) + s->interval);
}
static void YMF262TimerHandler (int c, double interval_Sec)
{
AdlibState *s = &adlib;
if (interval_Sec == 0.0) {
qemu_del_timer (s->opl_ts);
return;
}
s->cparam = c;
s->interval = ticks_per_sec * interval_Sec;
qemu_mod_timer (s->opl_ts, qemu_get_clock (vm_clock) + s->interval);
small_delay ();
}
static int write_audio (AdlibState *s, int samples)
{
int net = 0;
int ss = samples;
while (samples) {
int nbytes = samples << SHIFT;
int wbytes = AUD_write (s->voice,
s->mixbuf + (s->pos << (SHIFT - 1)),
nbytes);
int wsampl = wbytes >> SHIFT;
samples -= wsampl;
s->pos = (s->pos + wsampl) % s->samples;
net += wsampl;
if (!wbytes)
break;
}
if (net > ss) {
dolog ("WARNING: net > ss\n");
}
return net;
}
static void timer (void *opaque)
{
AdlibState *s = opaque;
int elapsed, samples, net = 0;
if (s->refcount)
dolog ("refcount=%d\n", s->refcount);
s->refcount += 1;
if (!(s->active && s->enabled))
goto reset;
AUD_run ();
while (s->left) {
int written = write_audio (s, s->left);
net += written;
if (!written)
goto reset2;
s->left -= written;
}
s->pos = 0;
elapsed = AUD_calc_elapsed (s->voice);
if (!elapsed)
goto reset2;
/* elapsed = AUD_get_free (s->voice); */
samples = elapsed >> SHIFT;
if (!samples)
goto reset2;
samples = audio_MIN (samples, s->samples - s->pos);
if (s->left)
dolog ("left=%d samples=%d elapsed=%d free=%d\n",
s->left, samples, elapsed, AUD_get_free (s->voice));
if (!samples)
goto reset2;
#ifdef USE_YMF262
YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples);
#else
YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
#endif
while (samples) {
int written = write_audio (s, samples);
net += written;
if (!written)
break;
samples -= written;
}
if (!samples)
s->pos = 0;
s->left = samples;
reset2:
AUD_adjust (s->voice, net << SHIFT);
reset:
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + ticks_per_sec / 1024);
s->refcount -= 1;
}
static void Adlib_fini (AdlibState *s)
{
#ifdef USE_YMF262
YMF262Shutdown ();
#else
if (s->opl) {
OPLDestroy (s->opl);
s->opl = NULL;
}
#endif
if (s->opl_ts)
qemu_free_timer (s->opl_ts);
if (s->ts)
qemu_free_timer (s->ts);
#define maybe_free(p) if (p) qemu_free (p)
maybe_free (s->mixbuf);
#undef maybe_free
s->active = 0;
s->enabled = 0;
}
void Adlib_init (void)
{
AdlibState *s = &adlib;
memset (s, 0, sizeof (*s));
#ifdef USE_YMF262
if (YMF262Init (1, 14318180, conf.freq)) {
dolog ("YMF262Init %d failed\n", conf.freq);
return;
}
else {
YMF262SetTimerHandler (0, YMF262TimerHandler, 0);
s->enabled = 1;
}
#else
s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, conf.freq);
if (!s->opl) {
dolog ("OPLCreate %d failed\n", conf.freq);
return;
}
else {
OPLSetTimerHandler (s->opl, YMF262TimerHandler, 0);
s->enabled = 1;
}
#endif
s->opl_ts = qemu_new_timer (vm_clock, OPL_timer, s);
if (!s->opl_ts) {
dolog ("Can not get timer for adlib emulation\n");
Adlib_fini (s);
return;
}
s->ts = qemu_new_timer (vm_clock, timer, s);
if (!s->opl_ts) {
dolog ("Can not get timer for adlib emulation\n");
Adlib_fini (s);
return;
}
s->voice = AUD_open (s->voice, "adlib", conf.freq, SHIFT, AUD_FMT_S16);
if (!s->voice) {
Adlib_fini (s);
return;
}
s->bytes_per_second = conf.freq << SHIFT;
s->samples = AUD_get_buffer_size (s->voice) >> SHIFT;
s->mixbuf = qemu_mallocz (s->samples << SHIFT);
if (!s->mixbuf) {
dolog ("not enough memory for adlib mixing buffer (%d)\n",
s->samples << SHIFT);
Adlib_fini (s);
return;
}
register_ioport_read (0x388, 4, 1, adlib_read, s);
register_ioport_write (0x388, 4, 1, adlib_write, s);
register_ioport_read (conf.port, 4, 1, adlib_read, s);
register_ioport_write (conf.port, 4, 1, adlib_write, s);
register_ioport_read (conf.port + 8, 2, 1, adlib_read, s);
register_ioport_write (conf.port + 8, 2, 1, adlib_write, s);
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1);
}
-956
View File
@@ -1,956 +0,0 @@
/*
* APIC support
*
* Copyright (c) 2004-2005 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 "vl.h"
//#define DEBUG_APIC
//#define DEBUG_IOAPIC
/* APIC Local Vector Table */
#define APIC_LVT_TIMER 0
#define APIC_LVT_THERMAL 1
#define APIC_LVT_PERFORM 2
#define APIC_LVT_LINT0 3
#define APIC_LVT_LINT1 4
#define APIC_LVT_ERROR 5
#define APIC_LVT_NB 6
/* APIC delivery modes */
#define APIC_DM_FIXED 0
#define APIC_DM_LOWPRI 1
#define APIC_DM_SMI 2
#define APIC_DM_NMI 4
#define APIC_DM_INIT 5
#define APIC_DM_SIPI 6
#define APIC_DM_EXTINT 7
/* APIC destination mode */
#define APIC_DESTMODE_FLAT 0xf
#define APIC_DESTMODE_CLUSTER 1
#define APIC_TRIGGER_EDGE 0
#define APIC_TRIGGER_LEVEL 1
#define APIC_LVT_TIMER_PERIODIC (1<<17)
#define APIC_LVT_MASKED (1<<16)
#define APIC_LVT_LEVEL_TRIGGER (1<<15)
#define APIC_LVT_REMOTE_IRR (1<<14)
#define APIC_INPUT_POLARITY (1<<13)
#define APIC_SEND_PENDING (1<<12)
#define IOAPIC_NUM_PINS 0x18
#define ESR_ILLEGAL_ADDRESS (1 << 7)
#define APIC_SV_ENABLE (1 << 8)
typedef struct APICState {
CPUState *cpu_env;
uint32_t apicbase;
uint8_t id;
uint8_t arb_id;
uint8_t tpr;
uint32_t spurious_vec;
uint8_t log_dest;
uint8_t dest_mode;
uint32_t isr[8]; /* in service register */
uint32_t tmr[8]; /* trigger mode register */
uint32_t irr[8]; /* interrupt request register */
uint32_t lvt[APIC_LVT_NB];
uint32_t esr; /* error register */
uint32_t icr[2];
uint32_t divide_conf;
int count_shift;
uint32_t initial_count;
int64_t initial_count_load_time, next_time;
QEMUTimer *timer;
struct APICState *next_apic;
} APICState;
struct IOAPICState {
uint8_t id;
uint8_t ioregsel;
uint32_t irr;
uint64_t ioredtbl[IOAPIC_NUM_PINS];
};
static int apic_io_memory;
static APICState *first_local_apic = NULL;
static int last_apic_id = 0;
static void apic_init_ipi(APICState *s);
static void apic_set_irq(APICState *s, int vector_num, int trigger_mode);
static void apic_update_irq(APICState *s);
static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode,
uint8_t vector_num, uint8_t polarity,
uint8_t trigger_mode)
{
APICState *apic_iter;
switch (delivery_mode) {
case APIC_DM_LOWPRI:
case APIC_DM_FIXED:
/* XXX: arbitration */
break;
case APIC_DM_SMI:
case APIC_DM_NMI:
break;
case APIC_DM_INIT:
/* normal INIT IPI sent to processors */
for (apic_iter = first_local_apic; apic_iter != NULL;
apic_iter = apic_iter->next_apic) {
apic_init_ipi(apic_iter);
}
return;
case APIC_DM_EXTINT:
/* handled in I/O APIC code */
break;
default:
return;
}
for (apic_iter = first_local_apic; apic_iter != NULL;
apic_iter = apic_iter->next_apic) {
if (deliver_bitmask & (1 << apic_iter->id))
apic_set_irq(apic_iter, vector_num, trigger_mode);
}
}
void cpu_set_apic_base(CPUState *env, uint64_t val)
{
APICState *s = env->apic_state;
#ifdef DEBUG_APIC
printf("cpu_set_apic_base: %016llx\n", val);
#endif
s->apicbase = (val & 0xfffff000) |
(s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
/* if disabled, cannot be enabled again */
if (!(val & MSR_IA32_APICBASE_ENABLE)) {
s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
env->cpuid_features &= ~CPUID_APIC;
s->spurious_vec &= ~APIC_SV_ENABLE;
}
}
uint64_t cpu_get_apic_base(CPUState *env)
{
APICState *s = env->apic_state;
#ifdef DEBUG_APIC
printf("cpu_get_apic_base: %016llx\n", (uint64_t)s->apicbase);
#endif
return s->apicbase;
}
void cpu_set_apic_tpr(CPUX86State *env, uint8_t val)
{
APICState *s = env->apic_state;
s->tpr = (val & 0x0f) << 4;
apic_update_irq(s);
}
uint8_t cpu_get_apic_tpr(CPUX86State *env)
{
APICState *s = env->apic_state;
return s->tpr >> 4;
}
static int fls_bit(int value)
{
unsigned int ret = 0;
#ifdef HOST_I386
__asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value));
return ret;
#else
if (value > 0xffff)
value >>= 16, ret = 16;
if (value > 0xff)
value >>= 8, ret += 8;
if (value > 0xf)
value >>= 4, ret += 4;
if (value > 0x3)
value >>= 2, ret += 2;
return ret + (value >> 1);
#endif
}
static inline void set_bit(uint32_t *tab, int index)
{
int i, mask;
i = index >> 5;
mask = 1 << (index & 0x1f);
tab[i] |= mask;
}
static inline void reset_bit(uint32_t *tab, int index)
{
int i, mask;
i = index >> 5;
mask = 1 << (index & 0x1f);
tab[i] &= ~mask;
}
/* return -1 if no bit is set */
static int get_highest_priority_int(uint32_t *tab)
{
int i;
for(i = 7; i >= 0; i--) {
if (tab[i] != 0) {
return i * 32 + fls_bit(tab[i]);
}
}
return -1;
}
static int apic_get_ppr(APICState *s)
{
int tpr, isrv, ppr;
tpr = (s->tpr >> 4);
isrv = get_highest_priority_int(s->isr);
if (isrv < 0)
isrv = 0;
isrv >>= 4;
if (tpr >= isrv)
ppr = s->tpr;
else
ppr = isrv << 4;
return ppr;
}
static int apic_get_arb_pri(APICState *s)
{
/* XXX: arbitration */
return 0;
}
/* signal the CPU if an irq is pending */
static void apic_update_irq(APICState *s)
{
int irrv, ppr;
if (!(s->spurious_vec & APIC_SV_ENABLE))
return;
irrv = get_highest_priority_int(s->irr);
if (irrv < 0)
return;
ppr = apic_get_ppr(s);
if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
return;
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
}
static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
{
set_bit(s->irr, vector_num);
if (trigger_mode)
set_bit(s->tmr, vector_num);
else
reset_bit(s->tmr, vector_num);
apic_update_irq(s);
}
static void apic_eoi(APICState *s)
{
int isrv;
isrv = get_highest_priority_int(s->isr);
if (isrv < 0)
return;
reset_bit(s->isr, isrv);
/* XXX: send the EOI packet to the APIC bus to allow the I/O APIC to
set the remote IRR bit for level triggered interrupts. */
apic_update_irq(s);
}
static uint32_t apic_get_delivery_bitmask(uint8_t dest, uint8_t dest_mode)
{
uint32_t mask = 0;
APICState *apic_iter;
if (dest_mode == 0) {
if (dest == 0xff)
mask = 0xff;
else
mask = 1 << dest;
} else {
/* XXX: cluster mode */
for (apic_iter = first_local_apic; apic_iter != NULL;
apic_iter = apic_iter->next_apic) {
if (dest & apic_iter->log_dest)
mask |= (1 << apic_iter->id);
}
}
return mask;
}
static void apic_init_ipi(APICState *s)
{
int i;
for(i = 0; i < APIC_LVT_NB; i++)
s->lvt[i] = 1 << 16; /* mask LVT */
s->tpr = 0;
s->spurious_vec = 0xff;
s->log_dest = 0;
s->dest_mode = 0;
memset(s->isr, 0, sizeof(s->isr));
memset(s->tmr, 0, sizeof(s->tmr));
memset(s->irr, 0, sizeof(s->irr));
memset(s->lvt, 0, sizeof(s->lvt));
s->esr = 0;
memset(s->icr, 0, sizeof(s->icr));
s->divide_conf = 0;
s->count_shift = 0;
s->initial_count = 0;
s->initial_count_load_time = 0;
s->next_time = 0;
}
static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode,
uint8_t delivery_mode, uint8_t vector_num,
uint8_t polarity, uint8_t trigger_mode)
{
uint32_t deliver_bitmask = 0;
int dest_shorthand = (s->icr[0] >> 18) & 3;
APICState *apic_iter;
switch (delivery_mode) {
case APIC_DM_LOWPRI:
/* XXX: serch for focus processor, arbitration */
dest = s->id;
case APIC_DM_INIT:
{
int trig_mode = (s->icr[0] >> 15) & 1;
int level = (s->icr[0] >> 14) & 1;
if (level == 0 && trig_mode == 1) {
for (apic_iter = first_local_apic; apic_iter != NULL;
apic_iter = apic_iter->next_apic) {
if (deliver_bitmask & (1 << apic_iter->id)) {
apic_iter->arb_id = apic_iter->id;
}
}
return;
}
}
break;
case APIC_DM_SIPI:
for (apic_iter = first_local_apic; apic_iter != NULL;
apic_iter = apic_iter->next_apic) {
if (deliver_bitmask & (1 << apic_iter->id)) {
/* XXX: SMP support */
/* apic_startup(apic_iter); */
}
}
return;
}
switch (dest_shorthand) {
case 0:
deliver_bitmask = apic_get_delivery_bitmask(dest, dest_mode);
break;
case 1:
deliver_bitmask = (1 << s->id);
break;
case 2:
deliver_bitmask = 0xffffffff;
break;
case 3:
deliver_bitmask = 0xffffffff & ~(1 << s->id);
break;
}
apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
trigger_mode);
}
int apic_get_interrupt(CPUState *env)
{
APICState *s = env->apic_state;
int intno;
/* if the APIC is installed or enabled, we let the 8259 handle the
IRQs */
if (!s)
return -1;
if (!(s->spurious_vec & APIC_SV_ENABLE))
return -1;
/* XXX: spurious IRQ handling */
intno = get_highest_priority_int(s->irr);
if (intno < 0)
return -1;
reset_bit(s->irr, intno);
if (s->tpr && intno <= s->tpr)
return s->spurious_vec & 0xff;
set_bit(s->isr, intno);
apic_update_irq(s);
return intno;
}
static uint32_t apic_get_current_count(APICState *s)
{
int64_t d;
uint32_t val;
d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >>
s->count_shift;
if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
/* periodic */
val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
} else {
if (d >= s->initial_count)
val = 0;
else
val = s->initial_count - d;
}
return val;
}
static void apic_timer_update(APICState *s, int64_t current_time)
{
int64_t next_time, d;
if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
d = (current_time - s->initial_count_load_time) >>
s->count_shift;
if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1);
} else {
if (d >= s->initial_count)
goto no_timer;
d = (uint64_t)s->initial_count + 1;
}
next_time = s->initial_count_load_time + (d << s->count_shift);
qemu_mod_timer(s->timer, next_time);
s->next_time = next_time;
} else {
no_timer:
qemu_del_timer(s->timer);
}
}
static void apic_timer(void *opaque)
{
APICState *s = opaque;
if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
apic_set_irq(s, s->lvt[APIC_LVT_TIMER] & 0xff, APIC_TRIGGER_EDGE);
}
apic_timer_update(s, s->next_time);
}
static uint32_t apic_mem_readb(void *opaque, target_phys_addr_t addr)
{
return 0;
}
static uint32_t apic_mem_readw(void *opaque, target_phys_addr_t addr)
{
return 0;
}
static void apic_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
}
static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
{
}
static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
{
CPUState *env;
APICState *s;
uint32_t val;
int index;
env = cpu_single_env;
if (!env)
return 0;
s = env->apic_state;
index = (addr >> 4) & 0xff;
switch(index) {
case 0x02: /* id */
val = s->id << 24;
break;
case 0x03: /* version */
val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */
break;
case 0x08:
val = s->tpr;
break;
case 0x09:
val = apic_get_arb_pri(s);
break;
case 0x0a:
/* ppr */
val = apic_get_ppr(s);
break;
case 0x0d:
val = s->log_dest << 24;
break;
case 0x0e:
val = s->dest_mode << 28;
break;
case 0x0f:
val = s->spurious_vec;
break;
case 0x10 ... 0x17:
val = s->isr[index & 7];
break;
case 0x18 ... 0x1f:
val = s->tmr[index & 7];
break;
case 0x20 ... 0x27:
val = s->irr[index & 7];
break;
case 0x28:
val = s->esr;
break;
case 0x32 ... 0x37:
val = s->lvt[index - 0x32];
break;
case 0x30:
case 0x31:
val = s->icr[index & 1];
break;
case 0x38:
val = s->initial_count;
break;
case 0x39:
val = apic_get_current_count(s);
break;
case 0x3e:
val = s->divide_conf;
break;
default:
s->esr |= ESR_ILLEGAL_ADDRESS;
val = 0;
break;
}
#ifdef DEBUG_APIC
printf("APIC read: %08x = %08x\n", (uint32_t)addr, val);
#endif
return val;
}
static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
CPUState *env;
APICState *s;
int index;
env = cpu_single_env;
if (!env)
return;
s = env->apic_state;
#ifdef DEBUG_APIC
printf("APIC write: %08x = %08x\n", (uint32_t)addr, val);
#endif
index = (addr >> 4) & 0xff;
switch(index) {
case 0x02:
s->id = (val >> 24);
break;
case 0x08:
s->tpr = val;
apic_update_irq(s);
break;
case 0x0b: /* EOI */
apic_eoi(s);
break;
case 0x0d:
s->log_dest = val >> 24;
break;
case 0x0e:
s->dest_mode = val >> 28;
break;
case 0x0f:
s->spurious_vec = val & 0x1ff;
apic_update_irq(s);
break;
case 0x30:
s->icr[0] = val;
apic_deliver(s, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
(s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
(s->icr[0] >> 14) & 1, (s->icr[0] >> 15) & 1);
break;
case 0x31:
s->icr[1] = val;
break;
case 0x32 ... 0x37:
{
int n = index - 0x32;
s->lvt[n] = val;
if (n == APIC_LVT_TIMER)
apic_timer_update(s, qemu_get_clock(vm_clock));
}
break;
case 0x38:
s->initial_count = val;
s->initial_count_load_time = qemu_get_clock(vm_clock);
apic_timer_update(s, s->initial_count_load_time);
break;
case 0x3e:
{
int v;
s->divide_conf = val & 0xb;
v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
s->count_shift = (v + 1) & 7;
}
break;
default:
s->esr |= ESR_ILLEGAL_ADDRESS;
break;
}
}
static void apic_save(QEMUFile *f, void *opaque)
{
APICState *s = opaque;
int i;
qemu_put_be32s(f, &s->apicbase);
qemu_put_8s(f, &s->id);
qemu_put_8s(f, &s->arb_id);
qemu_put_8s(f, &s->tpr);
qemu_put_be32s(f, &s->spurious_vec);
qemu_put_8s(f, &s->log_dest);
qemu_put_8s(f, &s->dest_mode);
for (i = 0; i < 8; i++) {
qemu_put_be32s(f, &s->isr[i]);
qemu_put_be32s(f, &s->tmr[i]);
qemu_put_be32s(f, &s->irr[i]);
}
for (i = 0; i < APIC_LVT_NB; i++) {
qemu_put_be32s(f, &s->lvt[i]);
}
qemu_put_be32s(f, &s->esr);
qemu_put_be32s(f, &s->icr[0]);
qemu_put_be32s(f, &s->icr[1]);
qemu_put_be32s(f, &s->divide_conf);
qemu_put_be32s(f, &s->count_shift);
qemu_put_be32s(f, &s->initial_count);
qemu_put_be64s(f, &s->initial_count_load_time);
qemu_put_be64s(f, &s->next_time);
}
static int apic_load(QEMUFile *f, void *opaque, int version_id)
{
APICState *s = opaque;
int i;
if (version_id != 1)
return -EINVAL;
/* XXX: what if the base changes? (registered memory regions) */
qemu_get_be32s(f, &s->apicbase);
qemu_get_8s(f, &s->id);
qemu_get_8s(f, &s->arb_id);
qemu_get_8s(f, &s->tpr);
qemu_get_be32s(f, &s->spurious_vec);
qemu_get_8s(f, &s->log_dest);
qemu_get_8s(f, &s->dest_mode);
for (i = 0; i < 8; i++) {
qemu_get_be32s(f, &s->isr[i]);
qemu_get_be32s(f, &s->tmr[i]);
qemu_get_be32s(f, &s->irr[i]);
}
for (i = 0; i < APIC_LVT_NB; i++) {
qemu_get_be32s(f, &s->lvt[i]);
}
qemu_get_be32s(f, &s->esr);
qemu_get_be32s(f, &s->icr[0]);
qemu_get_be32s(f, &s->icr[1]);
qemu_get_be32s(f, &s->divide_conf);
qemu_get_be32s(f, &s->count_shift);
qemu_get_be32s(f, &s->initial_count);
qemu_get_be64s(f, &s->initial_count_load_time);
qemu_get_be64s(f, &s->next_time);
return 0;
}
static void apic_reset(void *opaque)
{
APICState *s = opaque;
apic_init_ipi(s);
}
static CPUReadMemoryFunc *apic_mem_read[3] = {
apic_mem_readb,
apic_mem_readw,
apic_mem_readl,
};
static CPUWriteMemoryFunc *apic_mem_write[3] = {
apic_mem_writeb,
apic_mem_writew,
apic_mem_writel,
};
int apic_init(CPUState *env)
{
APICState *s;
s = qemu_mallocz(sizeof(APICState));
if (!s)
return -1;
env->apic_state = s;
apic_init_ipi(s);
s->id = last_apic_id++;
s->cpu_env = env;
s->apicbase = 0xfee00000 |
(s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE;
/* XXX: mapping more APICs at the same memory location */
if (apic_io_memory == 0) {
/* NOTE: the APIC is directly connected to the CPU - it is not
on the global memory bus. */
apic_io_memory = cpu_register_io_memory(0, apic_mem_read,
apic_mem_write, NULL);
cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000,
apic_io_memory);
}
s->timer = qemu_new_timer(vm_clock, apic_timer, s);
register_savevm("apic", 0, 1, apic_save, apic_load, s);
qemu_register_reset(apic_reset, s);
s->next_apic = first_local_apic;
first_local_apic = s;
return 0;
}
static void ioapic_service(IOAPICState *s)
{
uint8_t i;
uint8_t trig_mode;
uint8_t vector;
uint8_t delivery_mode;
uint32_t mask;
uint64_t entry;
uint8_t dest;
uint8_t dest_mode;
uint8_t polarity;
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
mask = 1 << i;
if (s->irr & mask) {
entry = s->ioredtbl[i];
if (!(entry & APIC_LVT_MASKED)) {
trig_mode = ((entry >> 15) & 1);
dest = entry >> 56;
dest_mode = (entry >> 11) & 1;
delivery_mode = (entry >> 8) & 7;
polarity = (entry >> 13) & 1;
if (trig_mode == APIC_TRIGGER_EDGE)
s->irr &= ~mask;
if (delivery_mode == APIC_DM_EXTINT)
vector = pic_read_irq(isa_pic);
else
vector = entry & 0xff;
apic_bus_deliver(apic_get_delivery_bitmask(dest, dest_mode),
delivery_mode, vector, polarity, trig_mode);
}
}
}
}
void ioapic_set_irq(void *opaque, int vector, int level)
{
IOAPICState *s = opaque;
if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
uint32_t mask = 1 << vector;
uint64_t entry = s->ioredtbl[vector];
if ((entry >> 15) & 1) {
/* level triggered */
if (level) {
s->irr |= mask;
ioapic_service(s);
} else {
s->irr &= ~mask;
}
} else {
/* edge triggered */
if (level) {
s->irr |= mask;
ioapic_service(s);
}
}
}
}
static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr)
{
IOAPICState *s = opaque;
int index;
uint32_t val = 0;
addr &= 0xff;
if (addr == 0x00) {
val = s->ioregsel;
} else if (addr == 0x10) {
switch (s->ioregsel) {
case 0x00:
val = s->id << 24;
break;
case 0x01:
val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */
break;
case 0x02:
val = 0;
break;
default:
index = (s->ioregsel - 0x10) >> 1;
if (index >= 0 && index < IOAPIC_NUM_PINS) {
if (s->ioregsel & 1)
val = s->ioredtbl[index] >> 32;
else
val = s->ioredtbl[index] & 0xffffffff;
}
}
#ifdef DEBUG_IOAPIC
printf("I/O APIC read: %08x = %08x\n", s->ioregsel, val);
#endif
}
return val;
}
static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
IOAPICState *s = opaque;
int index;
addr &= 0xff;
if (addr == 0x00) {
s->ioregsel = val;
return;
} else if (addr == 0x10) {
#ifdef DEBUG_IOAPIC
printf("I/O APIC write: %08x = %08x\n", s->ioregsel, val);
#endif
switch (s->ioregsel) {
case 0x00:
s->id = (val >> 24) & 0xff;
return;
case 0x01:
case 0x02:
return;
default:
index = (s->ioregsel - 0x10) >> 1;
if (index >= 0 && index < IOAPIC_NUM_PINS) {
if (s->ioregsel & 1) {
s->ioredtbl[index] &= 0xffffffff;
s->ioredtbl[index] |= (uint64_t)val << 32;
} else {
s->ioredtbl[index] &= ~0xffffffffULL;
s->ioredtbl[index] |= val;
}
ioapic_service(s);
}
}
}
}
static void ioapic_save(QEMUFile *f, void *opaque)
{
IOAPICState *s = opaque;
int i;
qemu_put_8s(f, &s->id);
qemu_put_8s(f, &s->ioregsel);
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
qemu_put_be64s(f, &s->ioredtbl[i]);
}
}
static int ioapic_load(QEMUFile *f, void *opaque, int version_id)
{
IOAPICState *s = opaque;
int i;
if (version_id != 1)
return -EINVAL;
qemu_get_8s(f, &s->id);
qemu_get_8s(f, &s->ioregsel);
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
qemu_get_be64s(f, &s->ioredtbl[i]);
}
return 0;
}
static void ioapic_reset(void *opaque)
{
IOAPICState *s = opaque;
int i;
memset(s, 0, sizeof(*s));
for(i = 0; i < IOAPIC_NUM_PINS; i++)
s->ioredtbl[i] = 1 << 16; /* mask LVT */
}
static CPUReadMemoryFunc *ioapic_mem_read[3] = {
ioapic_mem_readl,
ioapic_mem_readl,
ioapic_mem_readl,
};
static CPUWriteMemoryFunc *ioapic_mem_write[3] = {
ioapic_mem_writel,
ioapic_mem_writel,
ioapic_mem_writel,
};
IOAPICState *ioapic_init(void)
{
IOAPICState *s;
int io_memory;
s = qemu_mallocz(sizeof(IOAPICState));
if (!s)
return NULL;
ioapic_reset(s);
s->id = last_apic_id++;
io_memory = cpu_register_io_memory(0, ioapic_mem_read,
ioapic_mem_write, s);
cpu_register_physical_memory(0xfec00000, 0x1000, io_memory);
register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s);
qemu_register_reset(ioapic_reset, s);
return s;
}
-3118
View File
File diff suppressed because it is too large. Load diff
-78
View File
@@ -1,78 +0,0 @@
/*
* QEMU Cirrus CLGD 54xx VGA Emulator.
*
* Copyright (c) 2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
static void
glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
uint8_t *dst,const uint8_t *src,
int dstpitch,int srcpitch,
int bltwidth,int bltheight)
{
int x,y;
dstpitch -= bltwidth;
srcpitch -= bltwidth;
for (y = 0; y < bltheight; y++) {
for (x = 0; x < bltwidth; x++) {
ROP_OP(*dst, *src);
dst++;
src++;
}
dst += dstpitch;
src += srcpitch;
}
}
static void
glue(cirrus_bitblt_rop_bkwd_, ROP_NAME)(CirrusVGAState *s,
uint8_t *dst,const uint8_t *src,
int dstpitch,int srcpitch,
int bltwidth,int bltheight)
{
int x,y;
dstpitch += bltwidth;
srcpitch += bltwidth;
for (y = 0; y < bltheight; y++) {
for (x = 0; x < bltwidth; x++) {
ROP_OP(*dst, *src);
dst--;
src--;
}
dst += dstpitch;
src += srcpitch;
}
}
#define DEPTH 8
#include "cirrus_vga_rop2.h"
#define DEPTH 16
#include "cirrus_vga_rop2.h"
#define DEPTH 24
#include "cirrus_vga_rop2.h"
#define DEPTH 32
#include "cirrus_vga_rop2.h"
#undef ROP_NAME
#undef ROP_OP
-281
View File
@@ -1,281 +0,0 @@
/*
* QEMU Cirrus CLGD 54xx VGA Emulator.
*
* Copyright (c) 2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#if DEPTH == 8
#define PUTPIXEL() ROP_OP(d[0], col)
#elif DEPTH == 16
#define PUTPIXEL() ROP_OP(((uint16_t *)d)[0], col);
#elif DEPTH == 24
#define PUTPIXEL() ROP_OP(d[0], col); \
ROP_OP(d[1], (col >> 8)); \
ROP_OP(d[2], (col >> 16))
#elif DEPTH == 32
#define PUTPIXEL() ROP_OP(((uint32_t *)d)[0], col)
#else
#error unsupported DEPTH
#endif
static void
glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH)
(CirrusVGAState * s, uint8_t * dst,
const uint8_t * src,
int dstpitch, int srcpitch,
int bltwidth, int bltheight)
{
uint8_t *d;
int x, y, pattern_y, pattern_pitch, pattern_x;
unsigned int col;
const uint8_t *src1;
#if DEPTH == 24
int skipleft = s->gr[0x2f] & 0x1f;
#else
int skipleft = (s->gr[0x2f] & 0x07) * (DEPTH / 8);
#endif
#if DEPTH == 8
pattern_pitch = 8;
#elif DEPTH == 16
pattern_pitch = 16;
#else
pattern_pitch = 32;
#endif
pattern_y = s->cirrus_blt_srcaddr & 7;
for(y = 0; y < bltheight; y++) {
pattern_x = skipleft;
d = dst + skipleft;
src1 = src + pattern_y * pattern_pitch;
for (x = skipleft; x < bltwidth; x += (DEPTH / 8)) {
#if DEPTH == 8
col = src1[pattern_x];
pattern_x = (pattern_x + 1) & 7;
#elif DEPTH == 16
col = ((uint16_t *)(src1 + pattern_x))[0];
pattern_x = (pattern_x + 2) & 15;
#elif DEPTH == 24
{
const uint8_t *src2 = src1 + pattern_x * 3;
col = src2[0] | (src2[1] << 8) | (src2[2] << 16);
pattern_x = (pattern_x + 1) & 7;
}
#else
col = ((uint32_t *)(src1 + pattern_x))[0];
pattern_x = (pattern_x + 4) & 31;
#endif
PUTPIXEL();
d += (DEPTH / 8);
}
pattern_y = (pattern_y + 1) & 7;
dst += dstpitch;
}
}
/* NOTE: srcpitch is ignored */
static void
glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH)
(CirrusVGAState * s, uint8_t * dst,
const uint8_t * src,
int dstpitch, int srcpitch,
int bltwidth, int bltheight)
{
uint8_t *d;
int x, y;
unsigned bits, bits_xor;
unsigned int col;
unsigned bitmask;
unsigned index;
#if DEPTH == 24
int dstskipleft = s->gr[0x2f] & 0x1f;
int srcskipleft = dstskipleft / 3;
#else
int srcskipleft = s->gr[0x2f] & 0x07;
int dstskipleft = srcskipleft * (DEPTH / 8);
#endif
if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
bits_xor = 0xff;
col = s->cirrus_blt_bgcol;
} else {
bits_xor = 0x00;
col = s->cirrus_blt_fgcol;
}
for(y = 0; y < bltheight; y++) {
bitmask = 0x80 >> srcskipleft;
bits = *src++ ^ bits_xor;
d = dst + dstskipleft;
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
if ((bitmask & 0xff) == 0) {
bitmask = 0x80;
bits = *src++ ^ bits_xor;
}
index = (bits & bitmask);
if (index) {
PUTPIXEL();
}
d += (DEPTH / 8);
bitmask >>= 1;
}
dst += dstpitch;
}
}
static void
glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH)
(CirrusVGAState * s, uint8_t * dst,
const uint8_t * src,
int dstpitch, int srcpitch,
int bltwidth, int bltheight)
{
uint32_t colors[2];
uint8_t *d;
int x, y;
unsigned bits;
unsigned int col;
unsigned bitmask;
int srcskipleft = s->gr[0x2f] & 0x07;
int dstskipleft = srcskipleft * (DEPTH / 8);
colors[0] = s->cirrus_blt_bgcol;
colors[1] = s->cirrus_blt_fgcol;
for(y = 0; y < bltheight; y++) {
bitmask = 0x80 >> srcskipleft;
bits = *src++;
d = dst + dstskipleft;
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
if ((bitmask & 0xff) == 0) {
bitmask = 0x80;
bits = *src++;
}
col = colors[!!(bits & bitmask)];
PUTPIXEL();
d += (DEPTH / 8);
bitmask >>= 1;
}
dst += dstpitch;
}
}
static void
glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH)
(CirrusVGAState * s, uint8_t * dst,
const uint8_t * src,
int dstpitch, int srcpitch,
int bltwidth, int bltheight)
{
uint8_t *d;
int x, y, bitpos, pattern_y;
unsigned int bits, bits_xor;
unsigned int col;
#if DEPTH == 24
int dstskipleft = s->gr[0x2f] & 0x1f;
int srcskipleft = dstskipleft / 3;
#else
int srcskipleft = s->gr[0x2f] & 0x07;
int dstskipleft = srcskipleft * (DEPTH / 8);
#endif
if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
bits_xor = 0xff;
col = s->cirrus_blt_bgcol;
} else {
bits_xor = 0x00;
col = s->cirrus_blt_fgcol;
}
pattern_y = s->cirrus_blt_srcaddr & 7;
for(y = 0; y < bltheight; y++) {
bits = src[pattern_y] ^ bits_xor;
bitpos = 7 - srcskipleft;
d = dst + dstskipleft;
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
if ((bits >> bitpos) & 1) {
PUTPIXEL();
}
d += (DEPTH / 8);
bitpos = (bitpos - 1) & 7;
}
pattern_y = (pattern_y + 1) & 7;
dst += dstpitch;
}
}
static void
glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH)
(CirrusVGAState * s, uint8_t * dst,
const uint8_t * src,
int dstpitch, int srcpitch,
int bltwidth, int bltheight)
{
uint32_t colors[2];
uint8_t *d;
int x, y, bitpos, pattern_y;
unsigned int bits;
unsigned int col;
int srcskipleft = s->gr[0x2f] & 0x07;
int dstskipleft = srcskipleft * (DEPTH / 8);
colors[0] = s->cirrus_blt_bgcol;
colors[1] = s->cirrus_blt_fgcol;
pattern_y = s->cirrus_blt_srcaddr & 7;
for(y = 0; y < bltheight; y++) {
bits = src[pattern_y];
bitpos = 7 - srcskipleft;
d = dst + dstskipleft;
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
col = colors[(bits >> bitpos) & 1];
PUTPIXEL();
d += (DEPTH / 8);
bitpos = (bitpos - 1) & 7;
}
pattern_y = (pattern_y + 1) & 7;
dst += dstpitch;
}
}
static void
glue(glue(glue(cirrus_fill_, ROP_NAME), _),DEPTH)
(CirrusVGAState *s,
uint8_t *dst, int dst_pitch,
int width, int height)
{
uint8_t *d, *d1;
uint32_t col;
int x, y;
col = s->cirrus_blt_fgcol;
d1 = dst;
for(y = 0; y < height; y++) {
d = d1;
for(x = 0; x < width; x += (DEPTH / 8)) {
PUTPIXEL();
d += (DEPTH / 8);
}
d1 += dst_pitch;
}
}
#undef DEPTH
#undef PUTPIXEL
-656
View File
@@ -1,656 +0,0 @@
/*
* QEMU CUDA support
*
* Copyright (c) 2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
/* XXX: implement all timer modes */
//#define DEBUG_CUDA
//#define DEBUG_CUDA_PACKET
/* Bits in B data register: all active low */
#define TREQ 0x08 /* Transfer request (input) */
#define TACK 0x10 /* Transfer acknowledge (output) */
#define TIP 0x20 /* Transfer in progress (output) */
/* Bits in ACR */
#define SR_CTRL 0x1c /* Shift register control bits */
#define SR_EXT 0x0c /* Shift on external clock */
#define SR_OUT 0x10 /* Shift out if 1 */
/* Bits in IFR and IER */
#define IER_SET 0x80 /* set bits in IER */
#define IER_CLR 0 /* clear bits in IER */
#define SR_INT 0x04 /* Shift register full/empty */
#define T1_INT 0x40 /* Timer 1 interrupt */
#define T2_INT 0x20 /* Timer 2 interrupt */
/* Bits in ACR */
#define T1MODE 0xc0 /* Timer 1 mode */
#define T1MODE_CONT 0x40 /* continuous interrupts */
/* commands (1st byte) */
#define ADB_PACKET 0
#define CUDA_PACKET 1
#define ERROR_PACKET 2
#define TIMER_PACKET 3
#define POWER_PACKET 4
#define MACIIC_PACKET 5
#define PMU_PACKET 6
/* CUDA commands (2nd byte) */
#define CUDA_WARM_START 0x0
#define CUDA_AUTOPOLL 0x1
#define CUDA_GET_6805_ADDR 0x2
#define CUDA_GET_TIME 0x3
#define CUDA_GET_PRAM 0x7
#define CUDA_SET_6805_ADDR 0x8
#define CUDA_SET_TIME 0x9
#define CUDA_POWERDOWN 0xa
#define CUDA_POWERUP_TIME 0xb
#define CUDA_SET_PRAM 0xc
#define CUDA_MS_RESET 0xd
#define CUDA_SEND_DFAC 0xe
#define CUDA_BATTERY_SWAP_SENSE 0x10
#define CUDA_RESET_SYSTEM 0x11
#define CUDA_SET_IPL 0x12
#define CUDA_FILE_SERVER_FLAG 0x13
#define CUDA_SET_AUTO_RATE 0x14
#define CUDA_GET_AUTO_RATE 0x16
#define CUDA_SET_DEVICE_LIST 0x19
#define CUDA_GET_DEVICE_LIST 0x1a
#define CUDA_SET_ONE_SECOND_MODE 0x1b
#define CUDA_SET_POWER_MESSAGES 0x21
#define CUDA_GET_SET_IIC 0x22
#define CUDA_WAKEUP 0x23
#define CUDA_TIMER_TICKLE 0x24
#define CUDA_COMBINED_FORMAT_IIC 0x25
#define CUDA_TIMER_FREQ (4700000 / 6)
#define CUDA_ADB_POLL_FREQ 50
/* CUDA returns time_t's offset from Jan 1, 1904, not 1970 */
#define RTC_OFFSET 2082844800
typedef struct CUDATimer {
int index;
uint16_t latch;
uint16_t counter_value; /* counter value at load time */
int64_t load_time;
int64_t next_irq_time;
QEMUTimer *timer;
} CUDATimer;
typedef struct CUDAState {
/* cuda registers */
uint8_t b; /* B-side data */
uint8_t a; /* A-side data */
uint8_t dirb; /* B-side direction (1=output) */
uint8_t dira; /* A-side direction (1=output) */
uint8_t sr; /* Shift register */
uint8_t acr; /* Auxiliary control register */
uint8_t pcr; /* Peripheral control register */
uint8_t ifr; /* Interrupt flag register */
uint8_t ier; /* Interrupt enable register */
uint8_t anh; /* A-side data, no handshake */
CUDATimer timers[2];
uint8_t last_b; /* last value of B register */
uint8_t last_acr; /* last value of B register */
int data_in_size;
int data_in_index;
int data_out_index;
SetIRQFunc *set_irq;
int irq;
void *irq_opaque;
uint8_t autopoll;
uint8_t data_in[128];
uint8_t data_out[16];
QEMUTimer *adb_poll_timer;
} CUDAState;
static CUDAState cuda_state;
ADBBusState adb_bus;
static void cuda_update(CUDAState *s);
static void cuda_receive_packet_from_host(CUDAState *s,
const uint8_t *data, int len);
static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
int64_t current_time);
static void cuda_update_irq(CUDAState *s)
{
if (s->ifr & s->ier & (SR_INT | T1_INT)) {
s->set_irq(s->irq_opaque, s->irq, 1);
} else {
s->set_irq(s->irq_opaque, s->irq, 0);
}
}
static unsigned int get_counter(CUDATimer *s)
{
int64_t d;
unsigned int counter;
d = muldiv64(qemu_get_clock(vm_clock) - s->load_time,
CUDA_TIMER_FREQ, ticks_per_sec);
if (s->index == 0) {
/* the timer goes down from latch to -1 (period of latch + 2) */
if (d <= (s->counter_value + 1)) {
counter = (s->counter_value - d) & 0xffff;
} else {
counter = (d - (s->counter_value + 1)) % (s->latch + 2);
counter = (s->latch - counter) & 0xffff;
}
} else {
counter = (s->counter_value - d) & 0xffff;
}
return counter;
}
static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val)
{
#ifdef DEBUG_CUDA
printf("cuda: T%d.counter=%d\n",
1 + (ti->timer == NULL), val);
#endif
ti->load_time = qemu_get_clock(vm_clock);
ti->counter_value = val;
cuda_timer_update(s, ti, ti->load_time);
}
static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time)
{
int64_t d, next_time;
unsigned int counter;
/* current counter value */
d = muldiv64(current_time - s->load_time,
CUDA_TIMER_FREQ, ticks_per_sec);
/* the timer goes down from latch to -1 (period of latch + 2) */
if (d <= (s->counter_value + 1)) {
counter = (s->counter_value - d) & 0xffff;
} else {
counter = (d - (s->counter_value + 1)) % (s->latch + 2);
counter = (s->latch - counter) & 0xffff;
}
/* Note: we consider the irq is raised on 0 */
if (counter == 0xffff) {
next_time = d + s->latch + 1;
} else if (counter == 0) {
next_time = d + s->latch + 2;
} else {
next_time = d + counter;
}
#if 0
#ifdef DEBUG_CUDA
printf("latch=%d counter=%lld delta_next=%lld\n",
s->latch, d, next_time - d);
#endif
#endif
next_time = muldiv64(next_time, ticks_per_sec, CUDA_TIMER_FREQ) +
s->load_time;
if (next_time <= current_time)
next_time = current_time + 1;
return next_time;
}
static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
int64_t current_time)
{
if (!ti->timer)
return;
if ((s->acr & T1MODE) != T1MODE_CONT) {
qemu_del_timer(ti->timer);
} else {
ti->next_irq_time = get_next_irq_time(ti, current_time);
qemu_mod_timer(ti->timer, ti->next_irq_time);
}
}
static void cuda_timer1(void *opaque)
{
CUDAState *s = opaque;
CUDATimer *ti = &s->timers[0];
cuda_timer_update(s, ti, ti->next_irq_time);
s->ifr |= T1_INT;
cuda_update_irq(s);
}
static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr)
{
CUDAState *s = opaque;
uint32_t val;
addr = (addr >> 9) & 0xf;
switch(addr) {
case 0:
val = s->b;
break;
case 1:
val = s->a;
break;
case 2:
val = s->dirb;
break;
case 3:
val = s->dira;
break;
case 4:
val = get_counter(&s->timers[0]) & 0xff;
s->ifr &= ~T1_INT;
cuda_update_irq(s);
break;
case 5:
val = get_counter(&s->timers[0]) >> 8;
cuda_update_irq(s);
break;
case 6:
val = s->timers[0].latch & 0xff;
break;
case 7:
/* XXX: check this */
val = (s->timers[0].latch >> 8) & 0xff;
break;
case 8:
val = get_counter(&s->timers[1]) & 0xff;
s->ifr &= ~T2_INT;
break;
case 9:
val = get_counter(&s->timers[1]) >> 8;
break;
case 10:
val = s->sr;
s->ifr &= ~SR_INT;
cuda_update_irq(s);
break;
case 11:
val = s->acr;
break;
case 12:
val = s->pcr;
break;
case 13:
val = s->ifr;
if (s->ifr & s->ier)
val |= 0x80;
break;
case 14:
val = s->ier | 0x80;
break;
default:
case 15:
val = s->anh;
break;
}
#ifdef DEBUG_CUDA
if (addr != 13 || val != 0)
printf("cuda: read: reg=0x%x val=%02x\n", addr, val);
#endif
return val;
}
static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
CUDAState *s = opaque;
addr = (addr >> 9) & 0xf;
#ifdef DEBUG_CUDA
printf("cuda: write: reg=0x%x val=%02x\n", addr, val);
#endif
switch(addr) {
case 0:
s->b = val;
cuda_update(s);
break;
case 1:
s->a = val;
break;
case 2:
s->dirb = val;
break;
case 3:
s->dira = val;
break;
case 4:
s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
break;
case 5:
s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
s->ifr &= ~T1_INT;
set_counter(s, &s->timers[0], s->timers[0].latch);
break;
case 6:
s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
break;
case 7:
s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
s->ifr &= ~T1_INT;
cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
break;
case 8:
s->timers[1].latch = val;
set_counter(s, &s->timers[1], val);
break;
case 9:
set_counter(s, &s->timers[1], (val << 8) | s->timers[1].latch);
break;
case 10:
s->sr = val;
break;
case 11:
s->acr = val;
cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
cuda_update(s);
break;
case 12:
s->pcr = val;
break;
case 13:
/* reset bits */
s->ifr &= ~val;
cuda_update_irq(s);
break;
case 14:
if (val & IER_SET) {
/* set bits */
s->ier |= val & 0x7f;
} else {
/* reset bits */
s->ier &= ~val;
}
cuda_update_irq(s);
break;
default:
case 15:
s->anh = val;
break;
}
}
/* NOTE: TIP and TREQ are negated */
static void cuda_update(CUDAState *s)
{
int packet_received, len;
packet_received = 0;
if (!(s->b & TIP)) {
/* transfer requested from host */
if (s->acr & SR_OUT) {
/* data output */
if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
if (s->data_out_index < sizeof(s->data_out)) {
#ifdef DEBUG_CUDA
printf("cuda: send: %02x\n", s->sr);
#endif
s->data_out[s->data_out_index++] = s->sr;
s->ifr |= SR_INT;
cuda_update_irq(s);
}
}
} else {
if (s->data_in_index < s->data_in_size) {
/* data input */
if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
s->sr = s->data_in[s->data_in_index++];
#ifdef DEBUG_CUDA
printf("cuda: recv: %02x\n", s->sr);
#endif
/* indicate end of transfer */
if (s->data_in_index >= s->data_in_size) {
s->b = (s->b | TREQ);
}
s->ifr |= SR_INT;
cuda_update_irq(s);
}
}
}
} else {
/* no transfer requested: handle sync case */
if ((s->last_b & TIP) && (s->b & TACK) != (s->last_b & TACK)) {
/* update TREQ state each time TACK change state */
if (s->b & TACK)
s->b = (s->b | TREQ);
else
s->b = (s->b & ~TREQ);
s->ifr |= SR_INT;
cuda_update_irq(s);
} else {
if (!(s->last_b & TIP)) {
/* handle end of host to cuda transfert */
packet_received = (s->data_out_index > 0);
/* always an IRQ at the end of transfert */
s->ifr |= SR_INT;
cuda_update_irq(s);
}
/* signal if there is data to read */
if (s->data_in_index < s->data_in_size) {
s->b = (s->b & ~TREQ);
}
}
}
s->last_acr = s->acr;
s->last_b = s->b;
/* NOTE: cuda_receive_packet_from_host() can call cuda_update()
recursively */
if (packet_received) {
len = s->data_out_index;
s->data_out_index = 0;
cuda_receive_packet_from_host(s, s->data_out, len);
}
}
static void cuda_send_packet_to_host(CUDAState *s,
const uint8_t *data, int len)
{
#ifdef DEBUG_CUDA_PACKET
{
int i;
printf("cuda_send_packet_to_host:\n");
for(i = 0; i < len; i++)
printf(" %02x", data[i]);
printf("\n");
}
#endif
memcpy(s->data_in, data, len);
s->data_in_size = len;
s->data_in_index = 0;
cuda_update(s);
s->ifr |= SR_INT;
cuda_update_irq(s);
}
static void cuda_adb_poll(void *opaque)
{
CUDAState *s = opaque;
uint8_t obuf[ADB_MAX_OUT_LEN + 2];
int olen;
olen = adb_poll(&adb_bus, obuf + 2);
if (olen > 0) {
obuf[0] = ADB_PACKET;
obuf[1] = 0x40; /* polled data */
cuda_send_packet_to_host(s, obuf, olen + 2);
}
qemu_mod_timer(s->adb_poll_timer,
qemu_get_clock(vm_clock) +
(ticks_per_sec / CUDA_ADB_POLL_FREQ));
}
static void cuda_receive_packet(CUDAState *s,
const uint8_t *data, int len)
{
uint8_t obuf[16];
int ti, autopoll;
switch(data[0]) {
case CUDA_AUTOPOLL:
autopoll = (data[1] != 0);
if (autopoll != s->autopoll) {
s->autopoll = autopoll;
if (autopoll) {
qemu_mod_timer(s->adb_poll_timer,
qemu_get_clock(vm_clock) +
(ticks_per_sec / CUDA_ADB_POLL_FREQ));
} else {
qemu_del_timer(s->adb_poll_timer);
}
}
obuf[0] = CUDA_PACKET;
obuf[1] = data[1];
cuda_send_packet_to_host(s, obuf, 2);
break;
case CUDA_GET_TIME:
case CUDA_SET_TIME:
/* XXX: add time support ? */
ti = time(NULL) + RTC_OFFSET;
obuf[0] = CUDA_PACKET;
obuf[1] = 0;
obuf[2] = 0;
obuf[3] = ti >> 24;
obuf[4] = ti >> 16;
obuf[5] = ti >> 8;
obuf[6] = ti;
cuda_send_packet_to_host(s, obuf, 7);
break;
case CUDA_FILE_SERVER_FLAG:
case CUDA_SET_DEVICE_LIST:
case CUDA_SET_AUTO_RATE:
case CUDA_SET_POWER_MESSAGES:
obuf[0] = CUDA_PACKET;
obuf[1] = 0;
cuda_send_packet_to_host(s, obuf, 2);
break;
case CUDA_POWERDOWN:
obuf[0] = CUDA_PACKET;
obuf[1] = 0;
cuda_send_packet_to_host(s, obuf, 2);
qemu_system_shutdown_request();
break;
default:
break;
}
}
static void cuda_receive_packet_from_host(CUDAState *s,
const uint8_t *data, int len)
{
#ifdef DEBUG_CUDA_PACKET
{
int i;
printf("cuda_receive_packet_from_host:\n");
for(i = 0; i < len; i++)
printf(" %02x", data[i]);
printf("\n");
}
#endif
switch(data[0]) {
case ADB_PACKET:
{
uint8_t obuf[ADB_MAX_OUT_LEN + 2];
int olen;
olen = adb_request(&adb_bus, obuf + 2, data + 1, len - 1);
if (olen > 0) {
obuf[0] = ADB_PACKET;
obuf[1] = 0x00;
} else {
/* error */
obuf[0] = ADB_PACKET;
obuf[1] = -olen;
olen = 0;
}
cuda_send_packet_to_host(s, obuf, olen + 2);
}
break;
case CUDA_PACKET:
cuda_receive_packet(s, data + 1, len - 1);
break;
}
}
static void cuda_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
{
}
static void cuda_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
}
static uint32_t cuda_readw (void *opaque, target_phys_addr_t addr)
{
return 0;
}
static uint32_t cuda_readl (void *opaque, target_phys_addr_t addr)
{
return 0;
}
static CPUWriteMemoryFunc *cuda_write[] = {
&cuda_writeb,
&cuda_writew,
&cuda_writel,
};
static CPUReadMemoryFunc *cuda_read[] = {
&cuda_readb,
&cuda_readw,
&cuda_readl,
};
int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq)
{
CUDAState *s = &cuda_state;
int cuda_mem_index;
s->set_irq = set_irq;
s->irq_opaque = irq_opaque;
s->irq = irq;
s->timers[0].index = 0;
s->timers[0].timer = qemu_new_timer(vm_clock, cuda_timer1, s);
s->timers[0].latch = 0xffff;
set_counter(s, &s->timers[0], 0xffff);
s->timers[1].index = 1;
s->timers[1].latch = 0;
// s->ier = T1_INT | SR_INT;
s->ier = 0;
set_counter(s, &s->timers[1], 0xffff);
s->adb_poll_timer = qemu_new_timer(vm_clock, cuda_adb_poll, s);
cuda_mem_index = cpu_register_io_memory(0, cuda_read, cuda_write, s);
return cuda_mem_index;
}
-535
View File
@@ -1,535 +0,0 @@
/*
* QEMU DMA emulation
*
* Copyright (c) 2003-2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
/* #define DEBUG_DMA */
#define dolog(...) fprintf (stderr, "dma: " __VA_ARGS__)
#ifdef DEBUG_DMA
#define lwarn(...) fprintf (stderr, "dma: " __VA_ARGS__)
#define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
#define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__)
#else
#define lwarn(...)
#define linfo(...)
#define ldebug(...)
#endif
#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0])))
struct dma_regs {
int now[2];
uint16_t base[2];
uint8_t mode;
uint8_t page;
uint8_t pageh;
uint8_t dack;
uint8_t eop;
DMA_transfer_handler transfer_handler;
void *opaque;
};
#define ADDR 0
#define COUNT 1
static struct dma_cont {
uint8_t status;
uint8_t command;
uint8_t mask;
uint8_t flip_flop;
int dshift;
struct dma_regs regs[4];
} dma_controllers[2];
enum {
CMD_MEMORY_TO_MEMORY = 0x01,
CMD_FIXED_ADDRESS = 0x02,
CMD_BLOCK_CONTROLLER = 0x04,
CMD_COMPRESSED_TIME = 0x08,
CMD_CYCLIC_PRIORITY = 0x10,
CMD_EXTENDED_WRITE = 0x20,
CMD_LOW_DREQ = 0x40,
CMD_LOW_DACK = 0x80,
CMD_NOT_SUPPORTED = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS
| CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE
| CMD_LOW_DREQ | CMD_LOW_DACK
};
static int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
static void write_page (void *opaque, uint32_t nport, uint32_t data)
{
struct dma_cont *d = opaque;
int ichan;
ichan = channels[nport & 7];
if (-1 == ichan) {
dolog ("invalid channel %#x %#x\n", nport, data);
return;
}
d->regs[ichan].page = data;
}
static void write_pageh (void *opaque, uint32_t nport, uint32_t data)
{
struct dma_cont *d = opaque;
int ichan;
ichan = channels[nport & 7];
if (-1 == ichan) {
dolog ("invalid channel %#x %#x\n", nport, data);
return;
}
d->regs[ichan].pageh = data;
}
static uint32_t read_page (void *opaque, uint32_t nport)
{
struct dma_cont *d = opaque;
int ichan;
ichan = channels[nport & 7];
if (-1 == ichan) {
dolog ("invalid channel read %#x\n", nport);
return 0;
}
return d->regs[ichan].page;
}
static uint32_t read_pageh (void *opaque, uint32_t nport)
{
struct dma_cont *d = opaque;
int ichan;
ichan = channels[nport & 7];
if (-1 == ichan) {
dolog ("invalid channel read %#x\n", nport);
return 0;
}
return d->regs[ichan].pageh;
}
static inline void init_chan (struct dma_cont *d, int ichan)
{
struct dma_regs *r;
r = d->regs + ichan;
r->now[ADDR] = r->base[ADDR] << d->dshift;
r->now[COUNT] = 0;
}
static inline int getff (struct dma_cont *d)
{
int ff;
ff = d->flip_flop;
d->flip_flop = !ff;
return ff;
}
static uint32_t read_chan (void *opaque, uint32_t nport)
{
struct dma_cont *d = opaque;
int ichan, nreg, iport, ff, val, dir;
struct dma_regs *r;
iport = (nport >> d->dshift) & 0x0f;
ichan = iport >> 1;
nreg = iport & 1;
r = d->regs + ichan;
dir = ((r->mode >> 5) & 1) ? -1 : 1;
ff = getff (d);
if (nreg)
val = (r->base[COUNT] << d->dshift) - r->now[COUNT];
else
val = r->now[ADDR] + r->now[COUNT] * dir;
ldebug ("read_chan %#x -> %d\n", iport, val);
return (val >> (d->dshift + (ff << 3))) & 0xff;
}
static void write_chan (void *opaque, uint32_t nport, uint32_t data)
{
struct dma_cont *d = opaque;
int iport, ichan, nreg;
struct dma_regs *r;
iport = (nport >> d->dshift) & 0x0f;
ichan = iport >> 1;
nreg = iport & 1;
r = d->regs + ichan;
if (getff (d)) {
r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00);
init_chan (d, ichan);
} else {
r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff);
}
}
static void write_cont (void *opaque, uint32_t nport, uint32_t data)
{
struct dma_cont *d = opaque;
int iport, ichan = 0;
iport = (nport >> d->dshift) & 0x0f;
switch (iport) {
case 0x08: /* command */
if ((data != 0) && (data & CMD_NOT_SUPPORTED)) {
dolog ("command %#x not supported\n", data);
return;
}
d->command = data;
break;
case 0x09:
ichan = data & 3;
if (data & 4) {
d->status |= 1 << (ichan + 4);
}
else {
d->status &= ~(1 << (ichan + 4));
}
d->status &= ~(1 << ichan);
break;
case 0x0a: /* single mask */
if (data & 4)
d->mask |= 1 << (data & 3);
else
d->mask &= ~(1 << (data & 3));
break;
case 0x0b: /* mode */
{
ichan = data & 3;
#ifdef DEBUG_DMA
{
int op, ai, dir, opmode;
op = (data >> 2) & 3;
ai = (data >> 4) & 1;
dir = (data >> 5) & 1;
opmode = (data >> 6) & 3;
linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
ichan, op, ai, dir, opmode);
}
#endif
d->regs[ichan].mode = data;
break;
}
case 0x0c: /* clear flip flop */
d->flip_flop = 0;
break;
case 0x0d: /* reset */
d->flip_flop = 0;
d->mask = ~0;
d->status = 0;
d->command = 0;
break;
case 0x0e: /* clear mask for all channels */
d->mask = 0;
break;
case 0x0f: /* write mask for all channels */
d->mask = data;
break;
default:
dolog ("unknown iport %#x\n", iport);
break;
}
#ifdef DEBUG_DMA
if (0xc != iport) {
linfo ("write_cont: nport %#06x, ichan % 2d, val %#06x\n",
nport, ichan, data);
}
#endif
}
static uint32_t read_cont (void *opaque, uint32_t nport)
{
struct dma_cont *d = opaque;
int iport, val;
iport = (nport >> d->dshift) & 0x0f;
switch (iport) {
case 0x08: /* status */
val = d->status;
d->status &= 0xf0;
break;
case 0x0f: /* mask */
val = d->mask;
break;
default:
val = 0;
break;
}
ldebug ("read_cont: nport %#06x, iport %#04x val %#x\n", nport, iport, val);
return val;
}
int DMA_get_channel_mode (int nchan)
{
return dma_controllers[nchan > 3].regs[nchan & 3].mode;
}
void DMA_hold_DREQ (int nchan)
{
int ncont, ichan;
ncont = nchan > 3;
ichan = nchan & 3;
linfo ("held cont=%d chan=%d\n", ncont, ichan);
dma_controllers[ncont].status |= 1 << (ichan + 4);
}
void DMA_release_DREQ (int nchan)
{
int ncont, ichan;
ncont = nchan > 3;
ichan = nchan & 3;
linfo ("released cont=%d chan=%d\n", ncont, ichan);
dma_controllers[ncont].status &= ~(1 << (ichan + 4));
}
static void channel_run (int ncont, int ichan)
{
int n;
struct dma_regs *r = &dma_controllers[ncont].regs[ichan];
#ifdef DEBUG_DMA
int dir, opmode;
dir = (r->mode >> 5) & 1;
opmode = (r->mode >> 6) & 3;
if (dir) {
dolog ("DMA in address decrement mode\n");
}
if (opmode != 1) {
dolog ("DMA not in single mode select %#x\n", opmode);
}
#endif
r = dma_controllers[ncont].regs + ichan;
n = r->transfer_handler (r->opaque, ichan + (ncont << 2),
r->now[COUNT], (r->base[COUNT] + 1) << ncont);
r->now[COUNT] = n;
ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont);
}
void DMA_run (void)
{
struct dma_cont *d;
int icont, ichan;
d = dma_controllers;
for (icont = 0; icont < 2; icont++, d++) {
for (ichan = 0; ichan < 4; ichan++) {
int mask;
mask = 1 << ichan;
if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4))))
channel_run (icont, ichan);
}
}
}
void DMA_register_channel (int nchan,
DMA_transfer_handler transfer_handler,
void *opaque)
{
struct dma_regs *r;
int ichan, ncont;
ncont = nchan > 3;
ichan = nchan & 3;
r = dma_controllers[ncont].regs + ichan;
r->transfer_handler = transfer_handler;
r->opaque = opaque;
}
int DMA_read_memory (int nchan, void *buf, int pos, int len)
{
struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
target_ulong addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
if (r->mode & 0x20) {
int i;
uint8_t *p = buf;
cpu_physical_memory_read (addr - pos - len, buf, len);
/* What about 16bit transfers? */
for (i = 0; i < len >> 1; i++) {
uint8_t b = p[len - i - 1];
p[i] = b;
}
}
else
cpu_physical_memory_read (addr + pos, buf, len);
return len;
}
int DMA_write_memory (int nchan, void *buf, int pos, int len)
{
struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
target_ulong addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
if (r->mode & 0x20) {
int i;
uint8_t *p = buf;
cpu_physical_memory_write (addr - pos - len, buf, len);
/* What about 16bit transfers? */
for (i = 0; i < len; i++) {
uint8_t b = p[len - i - 1];
p[i] = b;
}
}
else
cpu_physical_memory_write (addr + pos, buf, len);
return len;
}
/* request the emulator to transfer a new DMA memory block ASAP */
void DMA_schedule(int nchan)
{
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
}
static void dma_reset(void *opaque)
{
struct dma_cont *d = opaque;
write_cont (d, (0x0d << d->dshift), 0);
}
/* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */
static void dma_init2(struct dma_cont *d, int base, int dshift,
int page_base, int pageh_base)
{
const static int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 };
int i;
d->dshift = dshift;
for (i = 0; i < 8; i++) {
register_ioport_write (base + (i << dshift), 1, 1, write_chan, d);
register_ioport_read (base + (i << dshift), 1, 1, read_chan, d);
}
for (i = 0; i < LENOFA (page_port_list); i++) {
register_ioport_write (page_base + page_port_list[i], 1, 1,
write_page, d);
register_ioport_read (page_base + page_port_list[i], 1, 1,
read_page, d);
if (pageh_base >= 0) {
register_ioport_write (pageh_base + page_port_list[i], 1, 1,
write_pageh, d);
register_ioport_read (pageh_base + page_port_list[i], 1, 1,
read_pageh, d);
}
}
for (i = 0; i < 8; i++) {
register_ioport_write (base + ((i + 8) << dshift), 1, 1,
write_cont, d);
register_ioport_read (base + ((i + 8) << dshift), 1, 1,
read_cont, d);
}
qemu_register_reset(dma_reset, d);
dma_reset(d);
}
static void dma_save (QEMUFile *f, void *opaque)
{
struct dma_cont *d = opaque;
int i;
/* qemu_put_8s (f, &d->status); */
qemu_put_8s (f, &d->command);
qemu_put_8s (f, &d->mask);
qemu_put_8s (f, &d->flip_flop);
qemu_put_be32s (f, &d->dshift);
for (i = 0; i < 4; ++i) {
struct dma_regs *r = &d->regs[i];
qemu_put_be32s (f, &r->now[0]);
qemu_put_be32s (f, &r->now[1]);
qemu_put_be16s (f, &r->base[0]);
qemu_put_be16s (f, &r->base[1]);
qemu_put_8s (f, &r->mode);
qemu_put_8s (f, &r->page);
qemu_put_8s (f, &r->pageh);
qemu_put_8s (f, &r->dack);
qemu_put_8s (f, &r->eop);
}
}
static int dma_load (QEMUFile *f, void *opaque, int version_id)
{
struct dma_cont *d = opaque;
int i;
if (version_id != 1)
return -EINVAL;
/* qemu_get_8s (f, &d->status); */
qemu_get_8s (f, &d->command);
qemu_get_8s (f, &d->mask);
qemu_get_8s (f, &d->flip_flop);
qemu_get_be32s (f, &d->dshift);
for (i = 0; i < 4; ++i) {
struct dma_regs *r = &d->regs[i];
qemu_get_be32s (f, &r->now[0]);
qemu_get_be32s (f, &r->now[1]);
qemu_get_be16s (f, &r->base[0]);
qemu_get_be16s (f, &r->base[1]);
qemu_get_8s (f, &r->mode);
qemu_get_8s (f, &r->page);
qemu_get_8s (f, &r->pageh);
qemu_get_8s (f, &r->dack);
qemu_get_8s (f, &r->eop);
}
return 0;
}
void DMA_init (int high_page_enable)
{
dma_init2(&dma_controllers[0], 0x00, 0, 0x80,
high_page_enable ? 0x480 : -1);
dma_init2(&dma_controllers[1], 0xc0, 1, 0x88,
high_page_enable ? 0x488 : -1);
register_savevm ("dma", 0, 1, dma_save, dma_load, &dma_controllers[0]);
register_savevm ("dma", 1, 1, dma_save, dma_load, &dma_controllers[1]);
}
-218
View File
@@ -1,218 +0,0 @@
#ifdef BSWAP_NEEDED
static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr)
{
bswap16s(&ehdr->e_type); /* Object file type */
bswap16s(&ehdr->e_machine); /* Architecture */
bswap32s(&ehdr->e_version); /* Object file version */
bswapSZs(&ehdr->e_entry); /* Entry point virtual address */
bswapSZs(&ehdr->e_phoff); /* Program header table file offset */
bswapSZs(&ehdr->e_shoff); /* Section header table file offset */
bswap32s(&ehdr->e_flags); /* Processor-specific flags */
bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */
bswap16s(&ehdr->e_phentsize); /* Program header table entry size */
bswap16s(&ehdr->e_phnum); /* Program header table entry count */
bswap16s(&ehdr->e_shentsize); /* Section header table entry size */
bswap16s(&ehdr->e_shnum); /* Section header table entry count */
bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
}
static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr)
{
bswap32s(&phdr->p_type); /* Segment type */
bswapSZs(&phdr->p_offset); /* Segment file offset */
bswapSZs(&phdr->p_vaddr); /* Segment virtual address */
bswapSZs(&phdr->p_paddr); /* Segment physical address */
bswapSZs(&phdr->p_filesz); /* Segment size in file */
bswapSZs(&phdr->p_memsz); /* Segment size in memory */
bswap32s(&phdr->p_flags); /* Segment flags */
bswapSZs(&phdr->p_align); /* Segment alignment */
}
static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr)
{
bswap32s(&shdr->sh_name);
bswap32s(&shdr->sh_type);
bswapSZs(&shdr->sh_flags);
bswapSZs(&shdr->sh_addr);
bswapSZs(&shdr->sh_offset);
bswapSZs(&shdr->sh_size);
bswap32s(&shdr->sh_link);
bswap32s(&shdr->sh_info);
bswapSZs(&shdr->sh_addralign);
bswapSZs(&shdr->sh_entsize);
}
static void glue(bswap_sym, SZ)(struct elf_sym *sym)
{
bswap32s(&sym->st_name);
bswapSZs(&sym->st_value);
bswapSZs(&sym->st_size);
bswap16s(&sym->st_shndx);
}
#endif
static int glue(find_phdr, SZ)(struct elfhdr *ehdr, int fd, struct elf_phdr *phdr, elf_word type)
{
int i, retval;
retval = lseek(fd, ehdr->e_phoff, SEEK_SET);
if (retval < 0)
return -1;
for (i = 0; i < ehdr->e_phnum; i++) {
retval = read(fd, phdr, sizeof(*phdr));
if (retval < 0)
return -1;
glue(bswap_phdr, SZ)(phdr);
if (phdr->p_type == type)
return 0;
}
return -1;
}
static void * glue(find_shdr, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, elf_word type)
{
int i, retval;
retval = lseek(fd, ehdr->e_shoff, SEEK_SET);
if (retval < 0)
return NULL;
for (i = 0; i < ehdr->e_shnum; i++) {
retval = read(fd, shdr, sizeof(*shdr));
if (retval < 0)
return NULL;
glue(bswap_shdr, SZ)(shdr);
if (shdr->sh_type == type)
return qemu_malloc(shdr->sh_size);
}
return NULL;
}
static void * glue(find_strtab, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
{
int retval;
retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET);
if (retval < 0)
return NULL;
retval = read(fd, shdr, sizeof(*shdr));
if (retval < 0)
return NULL;
glue(bswap_shdr, SZ)(shdr);
if (shdr->sh_type == SHT_STRTAB)
return qemu_malloc(shdr->sh_size);;
return NULL;
}
static int glue(read_program, SZ)(int fd, struct elf_phdr *phdr, void *dst, elf_word entry)
{
int retval;
retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET);
if (retval < 0)
return -1;
return read(fd, dst, phdr->p_filesz);
}
static int glue(read_section, SZ)(int fd, struct elf_shdr *s, void *dst)
{
int retval;
retval = lseek(fd, s->sh_offset, SEEK_SET);
if (retval < 0)
return -1;
retval = read(fd, dst, s->sh_size);
if (retval < 0)
return -1;
return 0;
}
static void * glue(process_section, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, elf_word type)
{
void *dst;
dst = glue(find_shdr, SZ)(ehdr, fd, shdr, type);
if (!dst)
goto error;
if (glue(read_section, SZ)(fd, shdr, dst))
goto error;
return dst;
error:
qemu_free(dst);
return NULL;
}
static void * glue(process_strtab, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
{
void *dst;
dst = glue(find_strtab, SZ)(ehdr, fd, shdr, symtab);
if (!dst)
goto error;
if (glue(read_section, SZ)(fd, shdr, dst))
goto error;
return dst;
error:
qemu_free(dst);
return NULL;
}
static void glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd)
{
struct elf_shdr symtab, strtab;
struct elf_sym *syms;
#if (SZ == 64)
struct elf32_sym *syms32;
#endif
struct syminfo *s;
int nsyms, i;
char *str;
/* Symbol table */
syms = glue(process_section, SZ)(ehdr, fd, &symtab, SHT_SYMTAB);
if (!syms)
return;
nsyms = symtab.sh_size / sizeof(struct elf_sym);
#if (SZ == 64)
syms32 = qemu_mallocz(nsyms * sizeof(struct elf32_sym));
#endif
for (i = 0; i < nsyms; i++) {
glue(bswap_sym, SZ)(&syms[i]);
#if (SZ == 64)
syms32[i].st_name = syms[i].st_name;
syms32[i].st_info = syms[i].st_info;
syms32[i].st_other = syms[i].st_other;
syms32[i].st_shndx = syms[i].st_shndx;
syms32[i].st_value = syms[i].st_value & 0xffffffff;
syms32[i].st_size = syms[i].st_size & 0xffffffff;
#endif
}
/* String table */
str = glue(process_strtab, SZ)(ehdr, fd, &strtab, &symtab);
if (!str)
goto error_freesyms;
/* Commit */
s = qemu_mallocz(sizeof(*s));
#if (SZ == 64)
s->disas_symtab = syms32;
qemu_free(syms);
#else
s->disas_symtab = syms;
#endif
s->disas_num_syms = nsyms;
s->disas_strtab = str;
s->next = syminfos;
syminfos = s;
return;
error_freesyms:
#if (SZ == 64)
qemu_free(syms32);
#endif
qemu_free(syms);
return;
}
-398
View File
@@ -1,398 +0,0 @@
/*
* QEMU ESP emulation
*
* Copyright (c) 2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
/* debug ESP card */
//#define DEBUG_ESP
#ifdef DEBUG_ESP
#define DPRINTF(fmt, args...) \
do { printf("ESP: " fmt , ##args); } while (0)
#else
#define DPRINTF(fmt, args...)
#endif
#define ESPDMA_REGS 4
#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
#define ESP_MAXREG 0x3f
typedef struct ESPState {
BlockDriverState **bd;
uint8_t rregs[ESP_MAXREG];
uint8_t wregs[ESP_MAXREG];
int irq;
uint32_t espdmaregs[ESPDMA_REGS];
uint32_t ti_size;
int ti_dir;
uint8_t ti_buf[65536];
} ESPState;
#define STAT_DO 0x00
#define STAT_DI 0x01
#define STAT_CD 0x02
#define STAT_ST 0x03
#define STAT_MI 0x06
#define STAT_MO 0x07
#define STAT_TC 0x10
#define STAT_IN 0x80
#define INTR_FC 0x08
#define INTR_BS 0x10
#define INTR_DC 0x20
#define SEQ_0 0x0
#define SEQ_CD 0x4
static void handle_satn(ESPState *s)
{
uint8_t buf[32];
uint32_t dmaptr, dmalen;
unsigned int i;
int64_t nb_sectors;
int target;
dmaptr = iommu_translate(s->espdmaregs[1]);
dmalen = s->wregs[0] | (s->wregs[1] << 8);
DPRINTF("Select with ATN at %8.8x len %d\n", dmaptr, dmalen);
DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
cpu_physical_memory_read(dmaptr, buf, dmalen);
for (i = 0; i < dmalen; i++) {
DPRINTF("Command %2.2x\n", buf[i]);
}
s->ti_dir = 0;
s->ti_size = 0;
target = s->wregs[4] & 7;
if (target > 4 || !s->bd[target]) { // No such drive
s->rregs[4] = STAT_IN;
s->rregs[5] = INTR_DC;
s->rregs[6] = SEQ_0;
s->espdmaregs[0] |= 1;
pic_set_irq(s->irq, 1);
return;
}
switch (buf[1]) {
case 0x0:
DPRINTF("Test Unit Ready (len %d)\n", buf[5]);
break;
case 0x12:
DPRINTF("Inquiry (len %d)\n", buf[5]);
memset(s->ti_buf, 0, 36);
if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
s->ti_buf[0] = 5;
memcpy(&s->ti_buf[16], "QEMU CDROM ", 16);
} else {
s->ti_buf[0] = 0;
memcpy(&s->ti_buf[16], "QEMU HARDDISK ", 16);
}
memcpy(&s->ti_buf[8], "QEMU ", 8);
s->ti_buf[2] = 1;
s->ti_buf[3] = 2;
s->ti_dir = 1;
s->ti_size = 36;
break;
case 0x1a:
DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf[3], buf[5]);
break;
case 0x25:
DPRINTF("Read Capacity (len %d)\n", buf[5]);
memset(s->ti_buf, 0, 8);
bdrv_get_geometry(s->bd[target], &nb_sectors);
s->ti_buf[0] = (nb_sectors >> 24) & 0xff;
s->ti_buf[1] = (nb_sectors >> 16) & 0xff;
s->ti_buf[2] = (nb_sectors >> 8) & 0xff;
s->ti_buf[3] = nb_sectors & 0xff;
s->ti_buf[4] = 0;
s->ti_buf[5] = 0;
s->ti_buf[6] = 2;
s->ti_buf[7] = 0;
s->ti_dir = 1;
s->ti_size = 8;
break;
case 0x28:
{
int64_t offset, len;
offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
len = (buf[8] << 8) | buf[9];
DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len);
bdrv_read(s->bd[target], offset, s->ti_buf, len);
s->ti_dir = 1;
s->ti_size = len * 512;
break;
}
case 0x2a:
{
int64_t offset, len;
offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
len = (buf[8] << 8) | buf[9];
DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len);
bdrv_write(s->bd[target], offset, s->ti_buf, len);
s->ti_dir = 0;
s->ti_size = len * 512;
break;
}
default:
DPRINTF("Unknown command (%2.2x)\n", buf[1]);
break;
}
s->rregs[4] = STAT_IN | STAT_TC | STAT_DI;
s->rregs[5] = INTR_BS | INTR_FC;
s->rregs[6] = SEQ_CD;
s->espdmaregs[0] |= 1;
pic_set_irq(s->irq, 1);
}
static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len)
{
uint32_t dmaptr, dmalen;
dmaptr = iommu_translate(s->espdmaregs[1]);
dmalen = s->wregs[0] | (s->wregs[1] << 8);
DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
cpu_physical_memory_write(dmaptr, buf, len);
s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
s->rregs[5] = INTR_BS | INTR_FC;
s->rregs[6] = SEQ_CD;
s->espdmaregs[0] |= 1;
pic_set_irq(s->irq, 1);
}
static const uint8_t okbuf[] = {0, 0};
static void handle_ti(ESPState *s)
{
uint32_t dmaptr, dmalen;
unsigned int i;
dmaptr = iommu_translate(s->espdmaregs[1]);
dmalen = s->wregs[0] | (s->wregs[1] << 8);
DPRINTF("Transfer Information at %8.8x len %d\n", dmaptr, dmalen);
DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
for (i = 0; i < s->ti_size; i++) {
dmaptr = iommu_translate(s->espdmaregs[1] + i);
if (s->ti_dir)
cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1);
else
cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1);
}
s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
s->rregs[5] = INTR_BS;
s->rregs[6] = 0;
s->espdmaregs[0] |= 1;
pic_set_irq(s->irq, 1);
}
static void esp_reset(void *opaque)
{
ESPState *s = opaque;
memset(s->rregs, 0, ESP_MAXREG);
s->rregs[0x0e] = 0x4; // Indicate fas100a
memset(s->espdmaregs, 0, ESPDMA_REGS * 4);
}
static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
{
ESPState *s = opaque;
uint32_t saddr;
saddr = (addr & ESP_MAXREG) >> 2;
switch (saddr) {
default:
break;
}
DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
return s->rregs[saddr];
}
static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
ESPState *s = opaque;
uint32_t saddr;
saddr = (addr & ESP_MAXREG) >> 2;
DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val);
switch (saddr) {
case 3:
// Command
switch(val & 0x7f) {
case 0:
DPRINTF("NOP (%2.2x)\n", val);
break;
case 1:
DPRINTF("Flush FIFO (%2.2x)\n", val);
s->rregs[6] = 0;
s->rregs[5] = INTR_FC;
break;
case 2:
DPRINTF("Chip reset (%2.2x)\n", val);
esp_reset(s);
break;
case 3:
DPRINTF("Bus reset (%2.2x)\n", val);
break;
case 0x10:
handle_ti(s);
break;
case 0x11:
DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
dma_write(s, okbuf, 2);
break;
case 0x12:
DPRINTF("Message Accepted (%2.2x)\n", val);
dma_write(s, okbuf, 2);
s->rregs[5] = INTR_DC;
s->rregs[6] = 0;
break;
case 0x1a:
DPRINTF("Set ATN (%2.2x)\n", val);
break;
case 0x42:
handle_satn(s);
break;
case 0x43:
DPRINTF("Set ATN & stop (%2.2x)\n", val);
handle_satn(s);
break;
default:
DPRINTF("Unhandled command (%2.2x)\n", val);
break;
}
break;
case 4 ... 7:
case 9 ... 0xf:
break;
default:
break;
}
s->wregs[saddr] = val;
}
static CPUReadMemoryFunc *esp_mem_read[3] = {
esp_mem_readb,
esp_mem_readb,
esp_mem_readb,
};
static CPUWriteMemoryFunc *esp_mem_write[3] = {
esp_mem_writeb,
esp_mem_writeb,
esp_mem_writeb,
};
static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
{
ESPState *s = opaque;
uint32_t saddr;
saddr = (addr & ESPDMA_MAXADDR) >> 2;
DPRINTF("read dmareg[%d]: 0x%2.2x\n", saddr, s->espdmaregs[saddr]);
return s->espdmaregs[saddr];
}
static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
ESPState *s = opaque;
uint32_t saddr;
saddr = (addr & ESPDMA_MAXADDR) >> 2;
DPRINTF("write dmareg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->espdmaregs[saddr], val);
switch (saddr) {
case 0:
if (!(val & 0x10))
pic_set_irq(s->irq, 0);
break;
default:
break;
}
s->espdmaregs[saddr] = val;
}
static CPUReadMemoryFunc *espdma_mem_read[3] = {
espdma_mem_readl,
espdma_mem_readl,
espdma_mem_readl,
};
static CPUWriteMemoryFunc *espdma_mem_write[3] = {
espdma_mem_writel,
espdma_mem_writel,
espdma_mem_writel,
};
static void esp_save(QEMUFile *f, void *opaque)
{
ESPState *s = opaque;
unsigned int i;
qemu_put_buffer(f, s->rregs, ESP_MAXREG);
qemu_put_buffer(f, s->wregs, ESP_MAXREG);
qemu_put_be32s(f, &s->irq);
for (i = 0; i < ESPDMA_REGS; i++)
qemu_put_be32s(f, &s->espdmaregs[i]);
}
static int esp_load(QEMUFile *f, void *opaque, int version_id)
{
ESPState *s = opaque;
unsigned int i;
if (version_id != 1)
return -EINVAL;
qemu_get_buffer(f, s->rregs, ESP_MAXREG);
qemu_get_buffer(f, s->wregs, ESP_MAXREG);
qemu_get_be32s(f, &s->irq);
for (i = 0; i < ESPDMA_REGS; i++)
qemu_get_be32s(f, &s->espdmaregs[i]);
return 0;
}
void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr)
{
ESPState *s;
int esp_io_memory, espdma_io_memory;
s = qemu_mallocz(sizeof(ESPState));
if (!s)
return;
s->bd = bd;
s->irq = irq;
esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);
espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s);
cpu_register_physical_memory(espdaddr, 16, espdma_io_memory);
esp_reset(s);
register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
qemu_register_reset(esp_reset, s);
}
-1757
View File
File diff suppressed because it is too large. Load diff
-1390
View File
File diff suppressed because it is too large. Load diff
-174
View File
@@ -1,174 +0,0 @@
#ifndef __FMOPL_H_
#define __FMOPL_H_
/* --- select emulation chips --- */
#define BUILD_YM3812 (HAS_YM3812)
//#define BUILD_YM3526 (HAS_YM3526)
//#define BUILD_Y8950 (HAS_Y8950)
/* --- system optimize --- */
/* select bit size of output : 8 or 16 */
#define OPL_OUTPUT_BIT 16
/* compiler dependence */
#ifndef OSD_CPU_H
#define OSD_CPU_H
typedef unsigned char UINT8; /* unsigned 8bit */
typedef unsigned short UINT16; /* unsigned 16bit */
typedef unsigned int UINT32; /* unsigned 32bit */
typedef signed char INT8; /* signed 8bit */
typedef signed short INT16; /* signed 16bit */
typedef signed int INT32; /* signed 32bit */
#endif
#if (OPL_OUTPUT_BIT==16)
typedef INT16 OPLSAMPLE;
#endif
#if (OPL_OUTPUT_BIT==8)
typedef unsigned char OPLSAMPLE;
#endif
#if BUILD_Y8950
#include "ymdeltat.h"
#endif
typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
typedef void (*OPL_IRQHANDLER)(int param,int irq);
typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data);
typedef unsigned char (*OPL_PORTHANDLER_R)(int param);
/* !!!!! here is private section , do not access there member direct !!!!! */
#define OPL_TYPE_WAVESEL 0x01 /* waveform select */
#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */
#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */
#define OPL_TYPE_IO 0x08 /* I/O port */
/* Saving is necessary for member of the 'R' mark for suspend/resume */
/* ---------- OPL one of slot ---------- */
typedef struct fm_opl_slot {
INT32 TL; /* total level :TL << 8 */
INT32 TLL; /* adjusted now TL */
UINT8 KSR; /* key scale rate :(shift down bit) */
INT32 *AR; /* attack rate :&AR_TABLE[AR<<2] */
INT32 *DR; /* decay rate :&DR_TALBE[DR<<2] */
INT32 SL; /* sustin level :SL_TALBE[SL] */
INT32 *RR; /* release rate :&DR_TABLE[RR<<2] */
UINT8 ksl; /* keyscale level :(shift down bits) */
UINT8 ksr; /* key scale rate :kcode>>KSR */
UINT32 mul; /* multiple :ML_TABLE[ML] */
UINT32 Cnt; /* frequency count : */
UINT32 Incr; /* frequency step : */
/* envelope generator state */
UINT8 eg_typ; /* envelope type flag */
UINT8 evm; /* envelope phase */
INT32 evc; /* envelope counter */
INT32 eve; /* envelope counter end point */
INT32 evs; /* envelope counter step */
INT32 evsa; /* envelope step for AR :AR[ksr] */
INT32 evsd; /* envelope step for DR :DR[ksr] */
INT32 evsr; /* envelope step for RR :RR[ksr] */
/* LFO */
UINT8 ams; /* ams flag */
UINT8 vib; /* vibrate flag */
/* wave selector */
INT32 **wavetable;
}OPL_SLOT;
/* ---------- OPL one of channel ---------- */
typedef struct fm_opl_channel {
OPL_SLOT SLOT[2];
UINT8 CON; /* connection type */
UINT8 FB; /* feed back :(shift down bit) */
INT32 *connect1; /* slot1 output pointer */
INT32 *connect2; /* slot2 output pointer */
INT32 op1_out[2]; /* slot1 output for selfeedback */
/* phase generator state */
UINT32 block_fnum; /* block+fnum : */
UINT8 kcode; /* key code : KeyScaleCode */
UINT32 fc; /* Freq. Increment base */
UINT32 ksl_base; /* KeyScaleLevel Base step */
UINT8 keyon; /* key on/off flag */
} OPL_CH;
/* OPL state */
typedef struct fm_opl_f {
UINT8 type; /* chip type */
int clock; /* master clock (Hz) */
int rate; /* sampling rate (Hz) */
double freqbase; /* frequency base */
double TimerBase; /* Timer base time (==sampling time) */
UINT8 address; /* address register */
UINT8 status; /* status flag */
UINT8 statusmask; /* status mask */
UINT32 mode; /* Reg.08 : CSM , notesel,etc. */
/* Timer */
int T[2]; /* timer counter */
UINT8 st[2]; /* timer enable */
/* FM channel slots */
OPL_CH *P_CH; /* pointer of CH */
int max_ch; /* maximum channel */
/* Rythm sention */
UINT8 rythm; /* Rythm mode , key flag */
#if BUILD_Y8950
/* Delta-T ADPCM unit (Y8950) */
YM_DELTAT *deltat; /* DELTA-T ADPCM */
#endif
/* Keyboard / I/O interface unit (Y8950) */
UINT8 portDirection;
UINT8 portLatch;
OPL_PORTHANDLER_R porthandler_r;
OPL_PORTHANDLER_W porthandler_w;
int port_param;
OPL_PORTHANDLER_R keyboardhandler_r;
OPL_PORTHANDLER_W keyboardhandler_w;
int keyboard_param;
/* time tables */
INT32 AR_TABLE[75]; /* atttack rate tables */
INT32 DR_TABLE[75]; /* decay rate tables */
UINT32 FN_TABLE[1024]; /* fnumber -> increment counter */
/* LFO */
INT32 *ams_table;
INT32 *vib_table;
INT32 amsCnt;
INT32 amsIncr;
INT32 vibCnt;
INT32 vibIncr;
/* wave selector enable flag */
UINT8 wavesel;
/* external event callback handler */
OPL_TIMERHANDLER TimerHandler; /* TIMER handler */
int TimerParam; /* TIMER parameter */
OPL_IRQHANDLER IRQHandler; /* IRQ handler */
int IRQParam; /* IRQ parameter */
OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */
int UpdateParam; /* stream update parameter */
} FM_OPL;
/* ---------- Generic interface section ---------- */
#define OPL_TYPE_YM3526 (0)
#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO)
FM_OPL *OPLCreate(int type, int clock, int rate);
void OPLDestroy(FM_OPL *OPL);
void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset);
void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param);
void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param);
/* Y8950 port handlers */
void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param);
void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param);
void OPLResetChip(FM_OPL *OPL);
int OPLWrite(FM_OPL *OPL,int a,int v);
unsigned char OPLRead(FM_OPL *OPL,int a);
int OPLTimerOver(FM_OPL *OPL,int c);
/* YM3626/YM3812 local section */
void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
#endif
-168
View File
@@ -1,168 +0,0 @@
/*
* Heathrow PIC support (standard PowerMac PIC)
*
* Copyright (c) 2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
//#define DEBUG
typedef struct HeathrowPIC {
uint32_t events;
uint32_t mask;
uint32_t levels;
uint32_t level_triggered;
} HeathrowPIC;
struct HeathrowPICS {
HeathrowPIC pics[2];
};
static inline int check_irq(HeathrowPIC *pic)
{
return (pic->events | (pic->levels & pic->level_triggered)) & pic->mask;
}
/* update the CPU irq state */
static void heathrow_pic_update(HeathrowPICS *s)
{
if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) {
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
} else {
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
}
static void pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
HeathrowPICS *s = opaque;
HeathrowPIC *pic;
unsigned int n;
value = bswap32(value);
#ifdef DEBUG
printf("pic_writel: %08x: %08x\n",
addr, value);
#endif
n = ((addr & 0xfff) - 0x10) >> 4;
if (n >= 2)
return;
pic = &s->pics[n];
switch(addr & 0xf) {
case 0x04:
pic->mask = value;
heathrow_pic_update(s);
break;
case 0x08:
/* do not reset level triggered IRQs */
value &= ~pic->level_triggered;
pic->events &= ~value;
heathrow_pic_update(s);
break;
default:
break;
}
}
static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
{
HeathrowPICS *s = opaque;
HeathrowPIC *pic;
unsigned int n;
uint32_t value;
n = ((addr & 0xfff) - 0x10) >> 4;
if (n >= 2) {
value = 0;
} else {
pic = &s->pics[n];
switch(addr & 0xf) {
case 0x0:
value = pic->events;
break;
case 0x4:
value = pic->mask;
break;
case 0xc:
value = pic->levels;
break;
default:
value = 0;
break;
}
}
#ifdef DEBUG
printf("pic_readl: %08x: %08x\n",
addr, value);
#endif
value = bswap32(value);
return value;
}
static CPUWriteMemoryFunc *pic_write[] = {
&pic_writel,
&pic_writel,
&pic_writel,
};
static CPUReadMemoryFunc *pic_read[] = {
&pic_readl,
&pic_readl,
&pic_readl,
};
void heathrow_pic_set_irq(void *opaque, int num, int level)
{
HeathrowPICS *s = opaque;
HeathrowPIC *pic;
unsigned int irq_bit;
#if defined(DEBUG)
{
static int last_level[64];
if (last_level[num] != level) {
printf("set_irq: num=0x%02x level=%d\n", num, level);
last_level[num] = level;
}
}
#endif
pic = &s->pics[1 - (num >> 5)];
irq_bit = 1 << (num & 0x1f);
if (level) {
pic->events |= irq_bit & ~pic->level_triggered;
pic->levels |= irq_bit;
} else {
pic->levels &= ~irq_bit;
}
heathrow_pic_update(s);
}
HeathrowPICS *heathrow_pic_init(int *pmem_index)
{
HeathrowPICS *s;
s = qemu_mallocz(sizeof(HeathrowPICS));
s->pics[0].level_triggered = 0;
s->pics[1].level_triggered = 0x1ff00000;
*pmem_index = cpu_register_io_memory(0, pic_read, pic_write, s);
return s;
}
-470
View File
@@ -1,470 +0,0 @@
/*
* QEMU 8253/8254 interval timer emulation
*
* Copyright (c) 2003-2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
//#define DEBUG_PIT
#define RW_STATE_LSB 1
#define RW_STATE_MSB 2
#define RW_STATE_WORD0 3
#define RW_STATE_WORD1 4
typedef struct PITChannelState {
int count; /* can be 65536 */
uint16_t latched_count;
uint8_t count_latched;
uint8_t status_latched;
uint8_t status;
uint8_t read_state;
uint8_t write_state;
uint8_t write_latch;
uint8_t rw_mode;
uint8_t mode;
uint8_t bcd; /* not supported */
uint8_t gate; /* timer start */
int64_t count_load_time;
/* irq handling */
int64_t next_transition_time;
QEMUTimer *irq_timer;
int irq;
} PITChannelState;
struct PITState {
PITChannelState channels[3];
};
static PITState pit_state;
static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
static int pit_get_count(PITChannelState *s)
{
uint64_t d;
int counter;
d = muldiv64(qemu_get_clock(vm_clock) - s->count_load_time, PIT_FREQ, ticks_per_sec);
switch(s->mode) {
case 0:
case 1:
case 4:
case 5:
counter = (s->count - d) & 0xffff;
break;
case 3:
/* XXX: may be incorrect for odd counts */
counter = s->count - ((2 * d) % s->count);
break;
default:
counter = s->count - (d % s->count);
break;
}
return counter;
}
/* get pit output bit */
static int pit_get_out1(PITChannelState *s, int64_t current_time)
{
uint64_t d;
int out;
d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec);
switch(s->mode) {
default:
case 0:
out = (d >= s->count);
break;
case 1:
out = (d < s->count);
break;
case 2:
if ((d % s->count) == 0 && d != 0)
out = 1;
else
out = 0;
break;
case 3:
out = (d % s->count) < ((s->count + 1) >> 1);
break;
case 4:
case 5:
out = (d == s->count);
break;
}
return out;
}
int pit_get_out(PITState *pit, int channel, int64_t current_time)
{
PITChannelState *s = &pit->channels[channel];
return pit_get_out1(s, current_time);
}
/* return -1 if no transition will occur. */
static int64_t pit_get_next_transition_time(PITChannelState *s,
int64_t current_time)
{
uint64_t d, next_time, base;
int period2;
d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec);
switch(s->mode) {
default:
case 0:
case 1:
if (d < s->count)
next_time = s->count;
else
return -1;
break;
case 2:
base = (d / s->count) * s->count;
if ((d - base) == 0 && d != 0)
next_time = base + s->count;
else
next_time = base + s->count + 1;
break;
case 3:
base = (d / s->count) * s->count;
period2 = ((s->count + 1) >> 1);
if ((d - base) < period2)
next_time = base + period2;
else
next_time = base + s->count;
break;
case 4:
case 5:
if (d < s->count)
next_time = s->count;
else if (d == s->count)
next_time = s->count + 1;
else
return -1;
break;
}
/* convert to timer units */
next_time = s->count_load_time + muldiv64(next_time, ticks_per_sec, PIT_FREQ);
/* fix potential rounding problems */
/* XXX: better solution: use a clock at PIT_FREQ Hz */
if (next_time <= current_time)
next_time = current_time + 1;
return next_time;
}
/* val must be 0 or 1 */
void pit_set_gate(PITState *pit, int channel, int val)
{
PITChannelState *s = &pit->channels[channel];
switch(s->mode) {
default:
case 0:
case 4:
/* XXX: just disable/enable counting */
break;
case 1:
case 5:
if (s->gate < val) {
/* restart counting on rising edge */
s->count_load_time = qemu_get_clock(vm_clock);
pit_irq_timer_update(s, s->count_load_time);
}
break;
case 2:
case 3:
if (s->gate < val) {
/* restart counting on rising edge */
s->count_load_time = qemu_get_clock(vm_clock);
pit_irq_timer_update(s, s->count_load_time);
}
/* XXX: disable/enable counting */
break;
}
s->gate = val;
}
int pit_get_gate(PITState *pit, int channel)
{
PITChannelState *s = &pit->channels[channel];
return s->gate;
}
static inline void pit_load_count(PITChannelState *s, int val)
{
if (val == 0)
val = 0x10000;
s->count_load_time = qemu_get_clock(vm_clock);
s->count = val;
pit_irq_timer_update(s, s->count_load_time);
}
/* if already latched, do not latch again */
static void pit_latch_count(PITChannelState *s)
{
if (!s->count_latched) {
s->latched_count = pit_get_count(s);
s->count_latched = s->rw_mode;
}
}
static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
PITState *pit = opaque;
int channel, access;
PITChannelState *s;
addr &= 3;
if (addr == 3) {
channel = val >> 6;
if (channel == 3) {
/* read back command */
for(channel = 0; channel < 3; channel++) {
s = &pit->channels[channel];
if (val & (2 << channel)) {
if (!(val & 0x20)) {
pit_latch_count(s);
}
if (!(val & 0x10) && !s->status_latched) {
/* status latch */
/* XXX: add BCD and null count */
s->status = (pit_get_out1(s, qemu_get_clock(vm_clock)) << 7) |
(s->rw_mode << 4) |
(s->mode << 1) |
s->bcd;
s->status_latched = 1;
}
}
}
} else {
s = &pit->channels[channel];
access = (val >> 4) & 3;
if (access == 0) {
pit_latch_count(s);
} else {
s->rw_mode = access;
s->read_state = access;
s->write_state = access;
s->mode = (val >> 1) & 7;
s->bcd = val & 1;
/* XXX: update irq timer ? */
}
}
} else {
s = &pit->channels[addr];
switch(s->write_state) {
default:
case RW_STATE_LSB:
pit_load_count(s, val);
break;
case RW_STATE_MSB:
pit_load_count(s, val << 8);
break;
case RW_STATE_WORD0:
s->write_latch = val;
s->write_state = RW_STATE_WORD1;
break;
case RW_STATE_WORD1:
pit_load_count(s, s->write_latch | (val << 8));
s->write_state = RW_STATE_WORD0;
break;
}
}
}
static uint32_t pit_ioport_read(void *opaque, uint32_t addr)
{
PITState *pit = opaque;
int ret, count;
PITChannelState *s;
addr &= 3;
s = &pit->channels[addr];
if (s->status_latched) {
s->status_latched = 0;
ret = s->status;
} else if (s->count_latched) {
switch(s->count_latched) {
default:
case RW_STATE_LSB:
ret = s->latched_count & 0xff;
s->count_latched = 0;
break;
case RW_STATE_MSB:
ret = s->latched_count >> 8;
s->count_latched = 0;
break;
case RW_STATE_WORD0:
ret = s->latched_count & 0xff;
s->count_latched = RW_STATE_MSB;
break;
}
} else {
switch(s->read_state) {
default:
case RW_STATE_LSB:
count = pit_get_count(s);
ret = count & 0xff;
break;
case RW_STATE_MSB:
count = pit_get_count(s);
ret = (count >> 8) & 0xff;
break;
case RW_STATE_WORD0:
count = pit_get_count(s);
ret = count & 0xff;
s->read_state = RW_STATE_WORD1;
break;
case RW_STATE_WORD1:
count = pit_get_count(s);
ret = (count >> 8) & 0xff;
s->read_state = RW_STATE_WORD0;
break;
}
}
return ret;
}
static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
{
int64_t expire_time;
int irq_level;
if (!s->irq_timer)
return;
expire_time = pit_get_next_transition_time(s, current_time);
irq_level = pit_get_out1(s, current_time);
pic_set_irq(s->irq, irq_level);
#ifdef DEBUG_PIT
printf("irq_level=%d next_delay=%f\n",
irq_level,
(double)(expire_time - current_time) / ticks_per_sec);
#endif
s->next_transition_time = expire_time;
if (expire_time != -1)
qemu_mod_timer(s->irq_timer, expire_time);
else
qemu_del_timer(s->irq_timer);
}
static void pit_irq_timer(void *opaque)
{
PITChannelState *s = opaque;
pit_irq_timer_update(s, s->next_transition_time);
}
static void pit_save(QEMUFile *f, void *opaque)
{
PITState *pit = opaque;
PITChannelState *s;
int i;
for(i = 0; i < 3; i++) {
s = &pit->channels[i];
qemu_put_be32s(f, &s->count);
qemu_put_be16s(f, &s->latched_count);
qemu_put_8s(f, &s->count_latched);
qemu_put_8s(f, &s->status_latched);
qemu_put_8s(f, &s->status);
qemu_put_8s(f, &s->read_state);
qemu_put_8s(f, &s->write_state);
qemu_put_8s(f, &s->write_latch);
qemu_put_8s(f, &s->rw_mode);
qemu_put_8s(f, &s->mode);
qemu_put_8s(f, &s->bcd);
qemu_put_8s(f, &s->gate);
qemu_put_be64s(f, &s->count_load_time);
if (s->irq_timer) {
qemu_put_be64s(f, &s->next_transition_time);
qemu_put_timer(f, s->irq_timer);
}
}
}
static int pit_load(QEMUFile *f, void *opaque, int version_id)
{
PITState *pit = opaque;
PITChannelState *s;
int i;
if (version_id != 1)
return -EINVAL;
for(i = 0; i < 3; i++) {
s = &pit->channels[i];
qemu_get_be32s(f, &s->count);
qemu_get_be16s(f, &s->latched_count);
qemu_get_8s(f, &s->count_latched);
qemu_get_8s(f, &s->status_latched);
qemu_get_8s(f, &s->status);
qemu_get_8s(f, &s->read_state);
qemu_get_8s(f, &s->write_state);
qemu_get_8s(f, &s->write_latch);
qemu_get_8s(f, &s->rw_mode);
qemu_get_8s(f, &s->mode);
qemu_get_8s(f, &s->bcd);
qemu_get_8s(f, &s->gate);
qemu_get_be64s(f, &s->count_load_time);
if (s->irq_timer) {
qemu_get_be64s(f, &s->next_transition_time);
qemu_get_timer(f, s->irq_timer);
}
}
return 0;
}
static void pit_reset(void *opaque)
{
PITState *pit = opaque;
PITChannelState *s;
int i;
for(i = 0;i < 3; i++) {
s = &pit->channels[i];
s->mode = 3;
s->gate = (i != 2);
pit_load_count(s, 0);
}
}
PITState *pit_init(int base, int irq)
{
PITState *pit = &pit_state;
PITChannelState *s;
s = &pit->channels[0];
/* the timer 0 is connected to an IRQ */
s->irq_timer = qemu_new_timer(vm_clock, pit_irq_timer, s);
s->irq = irq;
register_savevm("i8254", base, 1, pit_save, pit_load, pit);
qemu_register_reset(pit_reset, pit);
register_ioport_write(base, 4, 1, pit_ioport_write, pit);
register_ioport_read(base, 3, 1, pit_ioport_read, pit);
pit_reset(pit);
return pit;
}
-561
View File
@@ -1,561 +0,0 @@
/*
* QEMU 8259 interrupt controller emulation
*
* Copyright (c) 2003-2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
/* debug PIC */
//#define DEBUG_PIC
//#define DEBUG_IRQ_LATENCY
//#define DEBUG_IRQ_COUNT
typedef struct PicState {
uint8_t last_irr; /* edge detection */
uint8_t irr; /* interrupt request register */
uint8_t imr; /* interrupt mask register */
uint8_t isr; /* interrupt service register */
uint8_t priority_add; /* highest irq priority */
uint8_t irq_base;
uint8_t read_reg_select;
uint8_t poll;
uint8_t special_mask;
uint8_t init_state;
uint8_t auto_eoi;
uint8_t rotate_on_auto_eoi;
uint8_t special_fully_nested_mode;
uint8_t init4; /* true if 4 byte init */
uint8_t elcr; /* PIIX edge/trigger selection*/
uint8_t elcr_mask;
PicState2 *pics_state;
} PicState;
struct PicState2 {
/* 0 is master pic, 1 is slave pic */
/* XXX: better separation between the two pics */
PicState pics[2];
IRQRequestFunc *irq_request;
void *irq_request_opaque;
/* IOAPIC callback support */
SetIRQFunc *alt_irq_func;
void *alt_irq_opaque;
};
#if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT)
static int irq_level[16];
#endif
#ifdef DEBUG_IRQ_COUNT
static uint64_t irq_count[16];
#endif
/* set irq level. If an edge is detected, then the IRR is set to 1 */
static inline void pic_set_irq1(PicState *s, int irq, int level)
{
int mask;
mask = 1 << irq;
if (s->elcr & mask) {
/* level triggered */
if (level) {
s->irr |= mask;
s->last_irr |= mask;
} else {
s->irr &= ~mask;
s->last_irr &= ~mask;
}
} else {
/* edge triggered */
if (level) {
if ((s->last_irr & mask) == 0)
s->irr |= mask;
s->last_irr |= mask;
} else {
s->last_irr &= ~mask;
}
}
}
/* return the highest priority found in mask (highest = smallest
number). Return 8 if no irq */
static inline int get_priority(PicState *s, int mask)
{
int priority;
if (mask == 0)
return 8;
priority = 0;
while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
priority++;
return priority;
}
/* return the pic wanted interrupt. return -1 if none */
static int pic_get_irq(PicState *s)
{
int mask, cur_priority, priority;
mask = s->irr & ~s->imr;
priority = get_priority(s, mask);
if (priority == 8)
return -1;
/* compute current priority. If special fully nested mode on the
master, the IRQ coming from the slave is not taken into account
for the priority computation. */
mask = s->isr;
if (s->special_fully_nested_mode && s == &s->pics_state->pics[0])
mask &= ~(1 << 2);
cur_priority = get_priority(s, mask);
if (priority < cur_priority) {
/* higher priority found: an irq should be generated */
return (priority + s->priority_add) & 7;
} else {
return -1;
}
}
/* raise irq to CPU if necessary. must be called every time the active
irq may change */
/* XXX: should not export it, but it is needed for an APIC kludge */
void pic_update_irq(PicState2 *s)
{
int irq2, irq;
/* first look at slave pic */
irq2 = pic_get_irq(&s->pics[1]);
if (irq2 >= 0) {
/* if irq request by slave pic, signal master PIC */
pic_set_irq1(&s->pics[0], 2, 1);
pic_set_irq1(&s->pics[0], 2, 0);
}
/* look at requested irq */
irq = pic_get_irq(&s->pics[0]);
if (irq >= 0) {
#if defined(DEBUG_PIC)
{
int i;
for(i = 0; i < 2; i++) {
printf("pic%d: imr=%x irr=%x padd=%d\n",
i, s->pics[i].imr, s->pics[i].irr,
s->pics[i].priority_add);
}
}
printf("pic: cpu_interrupt\n");
#endif
s->irq_request(s->irq_request_opaque, 1);
}
}
#ifdef DEBUG_IRQ_LATENCY
int64_t irq_time[16];
#endif
void pic_set_irq_new(void *opaque, int irq, int level)
{
PicState2 *s = opaque;
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
if (level != irq_level[irq]) {
#if defined(DEBUG_PIC)
printf("pic_set_irq: irq=%d level=%d\n", irq, level);
#endif
irq_level[irq] = level;
#ifdef DEBUG_IRQ_COUNT
if (level == 1)
irq_count[irq]++;
#endif
}
#endif
#ifdef DEBUG_IRQ_LATENCY
if (level) {
irq_time[irq] = qemu_get_clock(vm_clock);
}
#endif
pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
/* used for IOAPIC irqs */
if (s->alt_irq_func)
s->alt_irq_func(s->alt_irq_opaque, irq, level);
pic_update_irq(s);
}
/* obsolete function */
void pic_set_irq(int irq, int level)
{
pic_set_irq_new(isa_pic, irq, level);
}
/* acknowledge interrupt 'irq' */
static inline void pic_intack(PicState *s, int irq)
{
if (s->auto_eoi) {
if (s->rotate_on_auto_eoi)
s->priority_add = (irq + 1) & 7;
} else {
s->isr |= (1 << irq);
}
/* We don't clear a level sensitive interrupt here */
if (!(s->elcr & (1 << irq)))
s->irr &= ~(1 << irq);
}
int pic_read_irq(PicState2 *s)
{
int irq, irq2, intno;
irq = pic_get_irq(&s->pics[0]);
if (irq >= 0) {
pic_intack(&s->pics[0], irq);
if (irq == 2) {
irq2 = pic_get_irq(&s->pics[1]);
if (irq2 >= 0) {
pic_intack(&s->pics[1], irq2);
} else {
/* spurious IRQ on slave controller */
irq2 = 7;
}
intno = s->pics[1].irq_base + irq2;
irq = irq2 + 8;
} else {
intno = s->pics[0].irq_base + irq;
}
} else {
/* spurious IRQ on host controller */
irq = 7;
intno = s->pics[0].irq_base + irq;
}
pic_update_irq(s);
#ifdef DEBUG_IRQ_LATENCY
printf("IRQ%d latency=%0.3fus\n",
irq,
(double)(qemu_get_clock(vm_clock) - irq_time[irq]) * 1000000.0 / ticks_per_sec);
#endif
#if defined(DEBUG_PIC)
printf("pic_interrupt: irq=%d\n", irq);
#endif
return intno;
}
static void pic_reset(void *opaque)
{
PicState *s = opaque;
s->last_irr = 0;
s->irr = 0;
s->imr = 0;
s->isr = 0;
s->priority_add = 0;
s->irq_base = 0;
s->read_reg_select = 0;
s->poll = 0;
s->special_mask = 0;
s->init_state = 0;
s->auto_eoi = 0;
s->rotate_on_auto_eoi = 0;
s->special_fully_nested_mode = 0;
s->init4 = 0;
s->elcr = 0;
}
static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
PicState *s = opaque;
int priority, cmd, irq;
#ifdef DEBUG_PIC
printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val);
#endif
addr &= 1;
if (addr == 0) {
if (val & 0x10) {
/* init */
pic_reset(s);
/* deassert a pending interrupt */
s->pics_state->irq_request(s->pics_state->irq_request_opaque, 0);
s->init_state = 1;
s->init4 = val & 1;
if (val & 0x02)
hw_error("single mode not supported");
if (val & 0x08)
hw_error("level sensitive irq not supported");
} else if (val & 0x08) {
if (val & 0x04)
s->poll = 1;
if (val & 0x02)
s->read_reg_select = val & 1;
if (val & 0x40)
s->special_mask = (val >> 5) & 1;
} else {
cmd = val >> 5;
switch(cmd) {
case 0:
case 4:
s->rotate_on_auto_eoi = cmd >> 2;
break;
case 1: /* end of interrupt */
case 5:
priority = get_priority(s, s->isr);
if (priority != 8) {
irq = (priority + s->priority_add) & 7;
s->isr &= ~(1 << irq);
if (cmd == 5)
s->priority_add = (irq + 1) & 7;
pic_update_irq(s->pics_state);
}
break;
case 3:
irq = val & 7;
s->isr &= ~(1 << irq);
pic_update_irq(s->pics_state);
break;
case 6:
s->priority_add = (val + 1) & 7;
pic_update_irq(s->pics_state);
break;
case 7:
irq = val & 7;
s->isr &= ~(1 << irq);
s->priority_add = (irq + 1) & 7;
pic_update_irq(s->pics_state);
break;
default:
/* no operation */
break;
}
}
} else {
switch(s->init_state) {
case 0:
/* normal mode */
s->imr = val;
pic_update_irq(s->pics_state);
break;
case 1:
s->irq_base = val & 0xf8;
s->init_state = 2;
break;
case 2:
if (s->init4) {
s->init_state = 3;
} else {
s->init_state = 0;
}
break;
case 3:
s->special_fully_nested_mode = (val >> 4) & 1;
s->auto_eoi = (val >> 1) & 1;
s->init_state = 0;
break;
}
}
}
static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
{
int ret;
ret = pic_get_irq(s);
if (ret >= 0) {
if (addr1 >> 7) {
s->pics_state->pics[0].isr &= ~(1 << 2);
s->pics_state->pics[0].irr &= ~(1 << 2);
}
s->irr &= ~(1 << ret);
s->isr &= ~(1 << ret);
if (addr1 >> 7 || ret != 2)
pic_update_irq(s->pics_state);
} else {
ret = 0x07;
pic_update_irq(s->pics_state);
}
return ret;
}
static uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
{
PicState *s = opaque;
unsigned int addr;
int ret;
addr = addr1;
addr &= 1;
if (s->poll) {
ret = pic_poll_read(s, addr1);
s->poll = 0;
} else {
if (addr == 0) {
if (s->read_reg_select)
ret = s->isr;
else
ret = s->irr;
} else {
ret = s->imr;
}
}
#ifdef DEBUG_PIC
printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret);
#endif
return ret;
}
/* memory mapped interrupt status */
/* XXX: may be the same than pic_read_irq() */
uint32_t pic_intack_read(PicState2 *s)
{
int ret;
ret = pic_poll_read(&s->pics[0], 0x00);
if (ret == 2)
ret = pic_poll_read(&s->pics[1], 0x80) + 8;
/* Prepare for ISR read */
s->pics[0].read_reg_select = 1;
return ret;
}
static void elcr_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
PicState *s = opaque;
s->elcr = val & s->elcr_mask;
}
static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1)
{
PicState *s = opaque;
return s->elcr;
}
static void pic_save(QEMUFile *f, void *opaque)
{
PicState *s = opaque;
qemu_put_8s(f, &s->last_irr);
qemu_put_8s(f, &s->irr);
qemu_put_8s(f, &s->imr);
qemu_put_8s(f, &s->isr);
qemu_put_8s(f, &s->priority_add);
qemu_put_8s(f, &s->irq_base);
qemu_put_8s(f, &s->read_reg_select);
qemu_put_8s(f, &s->poll);
qemu_put_8s(f, &s->special_mask);
qemu_put_8s(f, &s->init_state);
qemu_put_8s(f, &s->auto_eoi);
qemu_put_8s(f, &s->rotate_on_auto_eoi);
qemu_put_8s(f, &s->special_fully_nested_mode);
qemu_put_8s(f, &s->init4);
qemu_put_8s(f, &s->elcr);
}
static int pic_load(QEMUFile *f, void *opaque, int version_id)
{
PicState *s = opaque;
if (version_id != 1)
return -EINVAL;
qemu_get_8s(f, &s->last_irr);
qemu_get_8s(f, &s->irr);
qemu_get_8s(f, &s->imr);
qemu_get_8s(f, &s->isr);
qemu_get_8s(f, &s->priority_add);
qemu_get_8s(f, &s->irq_base);
qemu_get_8s(f, &s->read_reg_select);
qemu_get_8s(f, &s->poll);
qemu_get_8s(f, &s->special_mask);
qemu_get_8s(f, &s->init_state);
qemu_get_8s(f, &s->auto_eoi);
qemu_get_8s(f, &s->rotate_on_auto_eoi);
qemu_get_8s(f, &s->special_fully_nested_mode);
qemu_get_8s(f, &s->init4);
qemu_get_8s(f, &s->elcr);
return 0;
}
/* XXX: add generic master/slave system */
static void pic_init1(int io_addr, int elcr_addr, PicState *s)
{
register_ioport_write(io_addr, 2, 1, pic_ioport_write, s);
register_ioport_read(io_addr, 2, 1, pic_ioport_read, s);
if (elcr_addr >= 0) {
register_ioport_write(elcr_addr, 1, 1, elcr_ioport_write, s);
register_ioport_read(elcr_addr, 1, 1, elcr_ioport_read, s);
}
register_savevm("i8259", io_addr, 1, pic_save, pic_load, s);
qemu_register_reset(pic_reset, s);
}
void pic_info(void)
{
int i;
PicState *s;
if (!isa_pic)
return;
for(i=0;i<2;i++) {
s = &isa_pic->pics[i];
term_printf("pic%d: irr=%02x imr=%02x isr=%02x hprio=%d irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
i, s->irr, s->imr, s->isr, s->priority_add,
s->irq_base, s->read_reg_select, s->elcr,
s->special_fully_nested_mode);
}
}
void irq_info(void)
{
#ifndef DEBUG_IRQ_COUNT
term_printf("irq statistic code not compiled.\n");
#else
int i;
int64_t count;
term_printf("IRQ statistics:\n");
for (i = 0; i < 16; i++) {
count = irq_count[i];
if (count > 0)
term_printf("%2d: %lld\n", i, count);
}
#endif
}
PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque)
{
PicState2 *s;
s = qemu_mallocz(sizeof(PicState2));
if (!s)
return NULL;
pic_init1(0x20, 0x4d0, &s->pics[0]);
pic_init1(0xa0, 0x4d1, &s->pics[1]);
s->pics[0].elcr_mask = 0xf8;
s->pics[1].elcr_mask = 0xde;
s->irq_request = irq_request;
s->irq_request_opaque = irq_request_opaque;
s->pics[0].pics_state = s;
s->pics[1].pics_state = s;
return s;
}
void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func,
void *alt_irq_opaque)
{
s->alt_irq_func = alt_irq_func;
s->alt_irq_opaque = alt_irq_opaque;
}
-2473
View File
File diff suppressed because it is too large. Load diff
-207
View File
@@ -1,207 +0,0 @@
/*
* QEMU SPARC iommu emulation
*
* Copyright (c) 2003-2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
/* debug iommu */
//#define DEBUG_IOMMU
#ifdef DEBUG_IOMMU
#define DPRINTF(fmt, args...) \
do { printf("IOMMU: " fmt , ##args); } while (0)
#else
#define DPRINTF(fmt, args...)
#endif
#define IOMMU_NREGS (3*4096)
#define IOMMU_CTRL_IMPL 0xf0000000 /* Implementation */
#define IOMMU_CTRL_VERS 0x0f000000 /* Version */
#define IOMMU_CTRL_RNGE 0x0000001c /* Mapping RANGE */
#define IOMMU_RNGE_16MB 0x00000000 /* 0xff000000 -> 0xffffffff */
#define IOMMU_RNGE_32MB 0x00000004 /* 0xfe000000 -> 0xffffffff */
#define IOMMU_RNGE_64MB 0x00000008 /* 0xfc000000 -> 0xffffffff */
#define IOMMU_RNGE_128MB 0x0000000c /* 0xf8000000 -> 0xffffffff */
#define IOMMU_RNGE_256MB 0x00000010 /* 0xf0000000 -> 0xffffffff */
#define IOMMU_RNGE_512MB 0x00000014 /* 0xe0000000 -> 0xffffffff */
#define IOMMU_RNGE_1GB 0x00000018 /* 0xc0000000 -> 0xffffffff */
#define IOMMU_RNGE_2GB 0x0000001c /* 0x80000000 -> 0xffffffff */
#define IOMMU_CTRL_ENAB 0x00000001 /* IOMMU Enable */
/* The format of an iopte in the page tables */
#define IOPTE_PAGE 0x07ffff00 /* Physical page number (PA[30:12]) */
#define IOPTE_CACHE 0x00000080 /* Cached (in vme IOCACHE or Viking/MXCC) */
#define IOPTE_WRITE 0x00000004 /* Writeable */
#define IOPTE_VALID 0x00000002 /* IOPTE is valid */
#define IOPTE_WAZ 0x00000001 /* Write as zeros */
#define PAGE_SHIFT 12
#define PAGE_SIZE (1 << PAGE_SHIFT)
#define PAGE_MASK (PAGE_SIZE - 1)
typedef struct IOMMUState {
uint32_t addr;
uint32_t regs[IOMMU_NREGS];
uint32_t iostart;
} IOMMUState;
static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr)
{
IOMMUState *s = opaque;
uint32_t saddr;
saddr = (addr - s->addr) >> 2;
switch (saddr) {
default:
DPRINTF("read reg[%d] = %x\n", saddr, s->regs[saddr]);
return s->regs[saddr];
break;
}
return 0;
}
static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
{
IOMMUState *s = opaque;
uint32_t saddr;
saddr = (addr - s->addr) >> 2;
DPRINTF("write reg[%d] = %x\n", saddr, val);
switch (saddr) {
case 0:
switch (val & IOMMU_CTRL_RNGE) {
case IOMMU_RNGE_16MB:
s->iostart = 0xff000000;
break;
case IOMMU_RNGE_32MB:
s->iostart = 0xfe000000;
break;
case IOMMU_RNGE_64MB:
s->iostart = 0xfc000000;
break;
case IOMMU_RNGE_128MB:
s->iostart = 0xf8000000;
break;
case IOMMU_RNGE_256MB:
s->iostart = 0xf0000000;
break;
case IOMMU_RNGE_512MB:
s->iostart = 0xe0000000;
break;
case IOMMU_RNGE_1GB:
s->iostart = 0xc0000000;
break;
default:
case IOMMU_RNGE_2GB:
s->iostart = 0x80000000;
break;
}
DPRINTF("iostart = %x\n", s->iostart);
/* Fall through */
default:
s->regs[saddr] = val;
break;
}
}
static CPUReadMemoryFunc *iommu_mem_read[3] = {
iommu_mem_readw,
iommu_mem_readw,
iommu_mem_readw,
};
static CPUWriteMemoryFunc *iommu_mem_write[3] = {
iommu_mem_writew,
iommu_mem_writew,
iommu_mem_writew,
};
uint32_t iommu_translate_local(void *opaque, uint32_t addr)
{
IOMMUState *s = opaque;
uint32_t iopte, pa, tmppte;
iopte = s->regs[1] << 4;
addr &= ~s->iostart;
iopte += (addr >> (PAGE_SHIFT - 2)) & ~3;
cpu_physical_memory_read(iopte, (void *) &pa, 4);
bswap32s(&pa);
tmppte = pa;
pa = ((pa & IOPTE_PAGE) << 4) + (addr & PAGE_MASK);
DPRINTF("xlate dva %x => pa %x (iopte[%x] = %x)\n", addr, pa, iopte, tmppte);
return pa;
}
static void iommu_save(QEMUFile *f, void *opaque)
{
IOMMUState *s = opaque;
int i;
qemu_put_be32s(f, &s->addr);
for (i = 0; i < IOMMU_NREGS; i++)
qemu_put_be32s(f, &s->regs[i]);
qemu_put_be32s(f, &s->iostart);
}
static int iommu_load(QEMUFile *f, void *opaque, int version_id)
{
IOMMUState *s = opaque;
int i;
if (version_id != 1)
return -EINVAL;
qemu_get_be32s(f, &s->addr);
for (i = 0; i < IOMMU_NREGS; i++)
qemu_put_be32s(f, &s->regs[i]);
qemu_get_be32s(f, &s->iostart);
return 0;
}
static void iommu_reset(void *opaque)
{
IOMMUState *s = opaque;
memset(s->regs, 0, IOMMU_NREGS * 4);
s->iostart = 0;
}
void *iommu_init(uint32_t addr)
{
IOMMUState *s;
int iommu_io_memory;
s = qemu_mallocz(sizeof(IOMMUState));
if (!s)
return NULL;
s->addr = addr;
iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, iommu_mem_write, s);
cpu_register_physical_memory(addr, IOMMU_NREGS * 4, iommu_io_memory);
register_savevm("iommu", addr, 1, iommu_save, iommu_load, s);
qemu_register_reset(iommu_reset, s);
return s;
}
-469
View File
@@ -1,469 +0,0 @@
/*
* QEMU Lance emulation
*
* Copyright (c) 2003-2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
/* debug LANCE card */
//#define DEBUG_LANCE
#ifdef DEBUG_LANCE
#define DPRINTF(fmt, args...) \
do { printf("LANCE: " fmt , ##args); } while (0)
#else
#define DPRINTF(fmt, args...)
#endif
#ifndef LANCE_LOG_TX_BUFFERS
#define LANCE_LOG_TX_BUFFERS 4
#define LANCE_LOG_RX_BUFFERS 4
#endif
#define LE_CSR0 0
#define LE_CSR1 1
#define LE_CSR2 2
#define LE_CSR3 3
#define LE_NREGS (LE_CSR3 + 1)
#define LE_MAXREG LE_CSR3
#define LE_RDP 0
#define LE_RAP 1
#define LE_MO_PROM 0x8000 /* Enable promiscuous mode */
#define LE_C0_ERR 0x8000 /* Error: set if BAB, SQE, MISS or ME is set */
#define LE_C0_BABL 0x4000 /* BAB: Babble: tx timeout. */
#define LE_C0_CERR 0x2000 /* SQE: Signal quality error */
#define LE_C0_MISS 0x1000 /* MISS: Missed a packet */
#define LE_C0_MERR 0x0800 /* ME: Memory error */
#define LE_C0_RINT 0x0400 /* Received interrupt */
#define LE_C0_TINT 0x0200 /* Transmitter Interrupt */
#define LE_C0_IDON 0x0100 /* IFIN: Init finished. */
#define LE_C0_INTR 0x0080 /* Interrupt or error */
#define LE_C0_INEA 0x0040 /* Interrupt enable */
#define LE_C0_RXON 0x0020 /* Receiver on */
#define LE_C0_TXON 0x0010 /* Transmitter on */
#define LE_C0_TDMD 0x0008 /* Transmitter demand */
#define LE_C0_STOP 0x0004 /* Stop the card */
#define LE_C0_STRT 0x0002 /* Start the card */
#define LE_C0_INIT 0x0001 /* Init the card */
#define LE_C3_BSWP 0x4 /* SWAP */
#define LE_C3_ACON 0x2 /* ALE Control */
#define LE_C3_BCON 0x1 /* Byte control */
/* Receive message descriptor 1 */
#define LE_R1_OWN 0x80 /* Who owns the entry */
#define LE_R1_ERR 0x40 /* Error: if FRA, OFL, CRC or BUF is set */
#define LE_R1_FRA 0x20 /* FRA: Frame error */
#define LE_R1_OFL 0x10 /* OFL: Frame overflow */
#define LE_R1_CRC 0x08 /* CRC error */
#define LE_R1_BUF 0x04 /* BUF: Buffer error */
#define LE_R1_SOP 0x02 /* Start of packet */
#define LE_R1_EOP 0x01 /* End of packet */
#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */
#define LE_T1_OWN 0x80 /* Lance owns the packet */
#define LE_T1_ERR 0x40 /* Error summary */
#define LE_T1_EMORE 0x10 /* Error: more than one retry needed */
#define LE_T1_EONE 0x08 /* Error: one retry needed */
#define LE_T1_EDEF 0x04 /* Error: deferred */
#define LE_T1_SOP 0x02 /* Start of packet */
#define LE_T1_EOP 0x01 /* End of packet */
#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */
#define LE_T3_BUF 0x8000 /* Buffer error */
#define LE_T3_UFL 0x4000 /* Error underflow */
#define LE_T3_LCOL 0x1000 /* Error late collision */
#define LE_T3_CLOS 0x0800 /* Error carrier loss */
#define LE_T3_RTY 0x0400 /* Error retry */
#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry counter */
#define TX_RING_SIZE (1 << (LANCE_LOG_TX_BUFFERS))
#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)
#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29)
#define RX_RING_SIZE (1 << (LANCE_LOG_RX_BUFFERS))
#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)
#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29)
#define PKT_BUF_SZ 1544
#define RX_BUFF_SIZE PKT_BUF_SZ
#define TX_BUFF_SIZE PKT_BUF_SZ
struct lance_rx_desc {
unsigned short rmd0; /* low address of packet */
unsigned char rmd1_bits; /* descriptor bits */
unsigned char rmd1_hadr; /* high address of packet */
short length; /* This length is 2s complement (negative)!
* Buffer length
*/
unsigned short mblength; /* This is the actual number of bytes received */
};
struct lance_tx_desc {
unsigned short tmd0; /* low address of packet */
unsigned char tmd1_bits; /* descriptor bits */
unsigned char tmd1_hadr; /* high address of packet */
short length; /* Length is 2s complement (negative)! */
unsigned short misc;
};
/* The LANCE initialization block, described in databook. */
/* On the Sparc, this block should be on a DMA region */
struct lance_init_block {
unsigned short mode; /* Pre-set mode (reg. 15) */
unsigned char phys_addr[6]; /* Physical ethernet address */
unsigned filter[2]; /* Multicast filter. */
/* Receive and transmit ring base, along with extra bits. */
unsigned short rx_ptr; /* receive descriptor addr */
unsigned short rx_len; /* receive len and high addr */
unsigned short tx_ptr; /* transmit descriptor addr */
unsigned short tx_len; /* transmit len and high addr */
/* The Tx and Rx ring entries must aligned on 8-byte boundaries. */
struct lance_rx_desc brx_ring[RX_RING_SIZE];
struct lance_tx_desc btx_ring[TX_RING_SIZE];
char tx_buf [TX_RING_SIZE][TX_BUFF_SIZE];
char pad[2]; /* align rx_buf for copy_and_sum(). */
char rx_buf [RX_RING_SIZE][RX_BUFF_SIZE];
};
#define LEDMA_REGS 4
#define LEDMA_MAXADDR (LEDMA_REGS * 4 - 1)
typedef struct LANCEState {
NetDriverState *nd;
uint32_t leptr;
uint16_t addr;
uint16_t regs[LE_NREGS];
uint8_t phys[6]; /* mac address */
int irq;
unsigned int rxptr, txptr;
uint32_t ledmaregs[LEDMA_REGS];
} LANCEState;
static void lance_send(void *opaque);
static void lance_reset(void *opaque)
{
LANCEState *s = opaque;
memcpy(s->phys, s->nd->macaddr, 6);
s->rxptr = 0;
s->txptr = 0;
memset(s->regs, 0, LE_NREGS * 2);
s->regs[LE_CSR0] = LE_C0_STOP;
memset(s->ledmaregs, 0, LEDMA_REGS * 4);
}
static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
{
LANCEState *s = opaque;
uint32_t saddr;
saddr = addr & LE_MAXREG;
switch (saddr >> 1) {
case LE_RDP:
DPRINTF("read dreg[%d] = %4.4x\n", s->addr, s->regs[s->addr]);
return s->regs[s->addr];
case LE_RAP:
DPRINTF("read areg = %4.4x\n", s->addr);
return s->addr;
default:
DPRINTF("read unknown(%d)\n", saddr>>1);
break;
}
return 0;
}
static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
{
LANCEState *s = opaque;
uint32_t saddr;
uint16_t reg;
saddr = addr & LE_MAXREG;
switch (saddr >> 1) {
case LE_RDP:
DPRINTF("write dreg[%d] = %4.4x\n", s->addr, val);
switch(s->addr) {
case LE_CSR0:
if (val & LE_C0_STOP) {
s->regs[LE_CSR0] = LE_C0_STOP;
break;
}
reg = s->regs[LE_CSR0];
// 1 = clear for some bits
reg &= ~(val & 0x7f00);
// generated bits
reg &= ~(LE_C0_ERR | LE_C0_INTR);
if (reg & 0x7100)
reg |= LE_C0_ERR;
if (reg & 0x7f00)
reg |= LE_C0_INTR;
// direct bit
reg &= ~LE_C0_INEA;
reg |= val & LE_C0_INEA;
// exclusive bits
if (val & LE_C0_INIT) {
reg |= LE_C0_IDON | LE_C0_INIT;
reg &= ~LE_C0_STOP;
}
else if (val & LE_C0_STRT) {
reg |= LE_C0_STRT | LE_C0_RXON | LE_C0_TXON;
reg &= ~LE_C0_STOP;
}
s->regs[LE_CSR0] = reg;
break;
case LE_CSR1:
s->leptr = (s->leptr & 0xffff0000) | (val & 0xffff);
s->regs[s->addr] = val;
break;
case LE_CSR2:
s->leptr = (s->leptr & 0xffff) | ((val & 0xffff) << 16);
s->regs[s->addr] = val;
break;
case LE_CSR3:
s->regs[s->addr] = val;
break;
}
break;
case LE_RAP:
DPRINTF("write areg = %4.4x\n", val);
if (val < LE_NREGS)
s->addr = val;
break;
default:
DPRINTF("write unknown(%d) = %4.4x\n", saddr>>1, val);
break;
}
lance_send(s);
}
static CPUReadMemoryFunc *lance_mem_read[3] = {
lance_mem_readw,
lance_mem_readw,
lance_mem_readw,
};
static CPUWriteMemoryFunc *lance_mem_write[3] = {
lance_mem_writew,
lance_mem_writew,
lance_mem_writew,
};
/* return the max buffer size if the LANCE can receive more data */
static int lance_can_receive(void *opaque)
{
LANCEState *s = opaque;
uint32_t dmaptr = s->leptr + s->ledmaregs[3];
struct lance_init_block *ib;
int i;
uint8_t temp8;
if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
return 0;
ib = (void *) iommu_translate(dmaptr);
for (i = 0; i < RX_RING_SIZE; i++) {
cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1);
if (temp8 == (LE_R1_OWN)) {
DPRINTF("can receive %d\n", RX_BUFF_SIZE);
return RX_BUFF_SIZE;
}
}
DPRINTF("cannot receive\n");
return 0;
}
#define MIN_BUF_SIZE 60
static void lance_receive(void *opaque, const uint8_t *buf, int size)
{
LANCEState *s = opaque;
uint32_t dmaptr = s->leptr + s->ledmaregs[3];
struct lance_init_block *ib;
unsigned int i, old_rxptr;
uint16_t temp16;
uint8_t temp8;
DPRINTF("receive size %d\n", size);
if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
return;
ib = (void *) iommu_translate(dmaptr);
old_rxptr = s->rxptr;
for (i = s->rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) {
cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1);
if (temp8 == (LE_R1_OWN)) {
s->rxptr = (s->rxptr + 1) & RX_RING_MOD_MASK;
temp16 = size + 4;
bswap16s(&temp16);
cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].mblength, (void *) &temp16, 2);
cpu_physical_memory_write((uint32_t)&ib->rx_buf[i], buf, size);
temp8 = LE_R1_POK;
cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1);
s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR;
if (s->regs[LE_CSR0] & LE_C0_INEA)
pic_set_irq(s->irq, 1);
DPRINTF("got packet, len %d\n", size);
return;
}
}
}
static void lance_send(void *opaque)
{
LANCEState *s = opaque;
uint32_t dmaptr = s->leptr + s->ledmaregs[3];
struct lance_init_block *ib;
unsigned int i, old_txptr;
uint16_t temp16;
uint8_t temp8;
char pkt_buf[PKT_BUF_SZ];
DPRINTF("sending packet? (csr0 %4.4x)\n", s->regs[LE_CSR0]);
if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
return;
ib = (void *) iommu_translate(dmaptr);
DPRINTF("sending packet? (dmaptr %8.8x) (ib %p) (btx_ring %p)\n", dmaptr, ib, &ib->btx_ring);
old_txptr = s->txptr;
for (i = s->txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) {
cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1);
if (temp8 == (LE_T1_POK|LE_T1_OWN)) {
cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].length, (void *) &temp16, 2);
bswap16s(&temp16);
temp16 = (~temp16) + 1;
cpu_physical_memory_read((uint32_t)&ib->tx_buf[i], pkt_buf, temp16);
DPRINTF("sending packet, len %d\n", temp16);
qemu_send_packet(s->nd, pkt_buf, temp16);
temp8 = LE_T1_POK;
cpu_physical_memory_write((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1);
s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK;
s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR;
}
}
if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA))
pic_set_irq(s->irq, 1);
}
static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr)
{
LANCEState *s = opaque;
uint32_t saddr;
saddr = (addr & LEDMA_MAXADDR) >> 2;
return s->ledmaregs[saddr];
}
static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
LANCEState *s = opaque;
uint32_t saddr;
saddr = (addr & LEDMA_MAXADDR) >> 2;
s->ledmaregs[saddr] = val;
}
static CPUReadMemoryFunc *ledma_mem_read[3] = {
ledma_mem_readl,
ledma_mem_readl,
ledma_mem_readl,
};
static CPUWriteMemoryFunc *ledma_mem_write[3] = {
ledma_mem_writel,
ledma_mem_writel,
ledma_mem_writel,
};
static void lance_save(QEMUFile *f, void *opaque)
{
LANCEState *s = opaque;
int i;
qemu_put_be32s(f, &s->leptr);
qemu_put_be16s(f, &s->addr);
for (i = 0; i < LE_NREGS; i ++)
qemu_put_be16s(f, &s->regs[i]);
qemu_put_buffer(f, s->phys, 6);
qemu_put_be32s(f, &s->irq);
for (i = 0; i < LEDMA_REGS; i ++)
qemu_put_be32s(f, &s->ledmaregs[i]);
}
static int lance_load(QEMUFile *f, void *opaque, int version_id)
{
LANCEState *s = opaque;
int i;
if (version_id != 1)
return -EINVAL;
qemu_get_be32s(f, &s->leptr);
qemu_get_be16s(f, &s->addr);
for (i = 0; i < LE_NREGS; i ++)
qemu_get_be16s(f, &s->regs[i]);
qemu_get_buffer(f, s->phys, 6);
qemu_get_be32s(f, &s->irq);
for (i = 0; i < LEDMA_REGS; i ++)
qemu_get_be32s(f, &s->ledmaregs[i]);
return 0;
}
void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr)
{
LANCEState *s;
int lance_io_memory, ledma_io_memory;
s = qemu_mallocz(sizeof(LANCEState));
if (!s)
return;
s->nd = nd;
s->irq = irq;
lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s);
cpu_register_physical_memory(leaddr, 4, lance_io_memory);
ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s);
cpu_register_physical_memory(ledaddr, 16, ledma_io_memory);
lance_reset(s);
qemu_add_read_packet(nd, lance_can_receive, lance_receive, s);
register_savevm("lance", leaddr, 1, lance_save, lance_load, s);
qemu_register_reset(lance_reset, s);
}
-356
View File
@@ -1,356 +0,0 @@
/*
* QEMU M48T08 NVRAM emulation for Sparc platform
*
* Copyright (c) 2003-2004 Jocelyn Mayer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "m48t08.h"
//#define DEBUG_NVRAM
#if defined(DEBUG_NVRAM)
#define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)
#else
#define NVRAM_PRINTF(fmt, args...) do { } while (0)
#endif
#define NVRAM_MAX_MEM 0x1ff0
#define NVRAM_MAXADDR 0x1fff
struct m48t08_t {
/* RTC management */
time_t time_offset;
time_t stop_time;
/* NVRAM storage */
uint8_t *buffer;
};
/* Fake timer functions */
/* Generic helpers for BCD */
static inline uint8_t toBCD (uint8_t value)
{
return (((value / 10) % 10) << 4) | (value % 10);
}
static inline uint8_t fromBCD (uint8_t BCD)
{
return ((BCD >> 4) * 10) + (BCD & 0x0F);
}
/* RTC management helpers */
static void get_time (m48t08_t *NVRAM, struct tm *tm)
{
time_t t;
t = time(NULL) + NVRAM->time_offset;
#ifdef _WIN32
memcpy(tm,localtime(&t),sizeof(*tm));
#else
localtime_r (&t, tm) ;
#endif
}
static void set_time (m48t08_t *NVRAM, struct tm *tm)
{
time_t now, new_time;
new_time = mktime(tm);
now = time(NULL);
NVRAM->time_offset = new_time - now;
}
/* Direct access to NVRAM */
void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val)
{
struct tm tm;
int tmp;
addr &= NVRAM_MAXADDR;
switch (addr) {
case 0x1FF8:
/* control */
NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90;
break;
case 0x1FF9:
/* seconds (BCD) */
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_time(NVRAM, &tm);
tm.tm_sec = tmp;
set_time(NVRAM, &tm);
}
if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) {
if (val & 0x80) {
NVRAM->stop_time = time(NULL);
} else {
NVRAM->time_offset += NVRAM->stop_time - time(NULL);
NVRAM->stop_time = 0;
}
}
NVRAM->buffer[0x1FF9] = val & 0x80;
break;
case 0x1FFA:
/* minutes (BCD) */
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_time(NVRAM, &tm);
tm.tm_min = tmp;
set_time(NVRAM, &tm);
}
break;
case 0x1FFB:
/* hours (BCD) */
tmp = fromBCD(val & 0x3F);
if (tmp >= 0 && tmp <= 23) {
get_time(NVRAM, &tm);
tm.tm_hour = tmp;
set_time(NVRAM, &tm);
}
break;
case 0x1FFC:
/* day of the week / century */
tmp = fromBCD(val & 0x07);
get_time(NVRAM, &tm);
tm.tm_wday = tmp;
set_time(NVRAM, &tm);
NVRAM->buffer[0x1FFC] = val & 0x40;
break;
case 0x1FFD:
/* date */
tmp = fromBCD(val & 0x1F);
if (tmp != 0) {
get_time(NVRAM, &tm);
tm.tm_mday = tmp;
set_time(NVRAM, &tm);
}
break;
case 0x1FFE:
/* month */
tmp = fromBCD(val & 0x1F);
if (tmp >= 1 && tmp <= 12) {
get_time(NVRAM, &tm);
tm.tm_mon = tmp - 1;
set_time(NVRAM, &tm);
}
break;
case 0x1FFF:
/* year */
tmp = fromBCD(val);
if (tmp >= 0 && tmp <= 99) {
get_time(NVRAM, &tm);
tm.tm_year = fromBCD(val);
set_time(NVRAM, &tm);
}
break;
default:
NVRAM->buffer[addr] = val & 0xFF;
break;
}
}
uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr)
{
struct tm tm;
uint8_t retval = 0xFF;
addr &= NVRAM_MAXADDR;
switch (addr) {
case 0x1FF8:
/* control */
goto do_read;
case 0x1FF9:
/* seconds (BCD) */
get_time(NVRAM, &tm);
retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec);
break;
case 0x1FFA:
/* minutes (BCD) */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_min);
break;
case 0x1FFB:
/* hours (BCD) */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_hour);
break;
case 0x1FFC:
/* day of the week / century */
get_time(NVRAM, &tm);
retval = NVRAM->buffer[0x1FFC] | tm.tm_wday;
break;
case 0x1FFD:
/* date */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_mday);
break;
case 0x1FFE:
/* month */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_mon + 1);
break;
case 0x1FFF:
/* year */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_year);
break;
default:
do_read:
retval = NVRAM->buffer[addr];
break;
}
return retval;
}
static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
m48t08_t *NVRAM = opaque;
m48t08_write(NVRAM, addr, value);
}
static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
{
m48t08_t *NVRAM = opaque;
m48t08_write(NVRAM, addr, value);
m48t08_write(NVRAM, addr + 1, value >> 8);
}
static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
m48t08_t *NVRAM = opaque;
m48t08_write(NVRAM, addr, value);
m48t08_write(NVRAM, addr + 1, value >> 8);
m48t08_write(NVRAM, addr + 2, value >> 16);
m48t08_write(NVRAM, addr + 3, value >> 24);
}
static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
{
m48t08_t *NVRAM = opaque;
uint32_t retval = 0;
retval = m48t08_read(NVRAM, addr);
return retval;
}
static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
{
m48t08_t *NVRAM = opaque;
uint32_t retval = 0;
retval = m48t08_read(NVRAM, addr) << 8;
retval |= m48t08_read(NVRAM, addr + 1);
return retval;
}
static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
{
m48t08_t *NVRAM = opaque;
uint32_t retval = 0;
retval = m48t08_read(NVRAM, addr) << 24;
retval |= m48t08_read(NVRAM, addr + 1) << 16;
retval |= m48t08_read(NVRAM, addr + 2) << 8;
retval |= m48t08_read(NVRAM, addr + 3);
return retval;
}
static CPUWriteMemoryFunc *nvram_write[] = {
&nvram_writeb,
&nvram_writew,
&nvram_writel,
};
static CPUReadMemoryFunc *nvram_read[] = {
&nvram_readb,
&nvram_readw,
&nvram_readl,
};
static void nvram_save(QEMUFile *f, void *opaque)
{
m48t08_t *s = opaque;
qemu_put_be32s(f, (uint32_t *)&s->time_offset);
qemu_put_be32s(f, (uint32_t *)&s->stop_time);
qemu_put_buffer(f, s->buffer, 0x2000);
}
static int nvram_load(QEMUFile *f, void *opaque, int version_id)
{
m48t08_t *s = opaque;
if (version_id != 1)
return -EINVAL;
qemu_get_be32s(f, (uint32_t *)&s->time_offset);
qemu_get_be32s(f, (uint32_t *)&s->stop_time);
qemu_get_buffer(f, s->buffer, 0x2000);
return 0;
}
static void m48t08_reset(void *opaque)
{
m48t08_t *s = opaque;
s->time_offset = 0;
s->stop_time = 0;
}
/* Initialisation routine */
m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size)
{
m48t08_t *s;
int mem_index;
s = qemu_mallocz(sizeof(m48t08_t));
if (!s)
return NULL;
s->buffer = qemu_mallocz(size);
if (!s->buffer) {
qemu_free(s);
return NULL;
}
if (mem_base != 0) {
mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
cpu_register_physical_memory(mem_base, 0x2000, mem_index);
}
register_savevm("nvram", mem_base, 1, nvram_save, nvram_load, s);
qemu_register_reset(m48t08_reset, s);
return s;
}
#if 0
struct idprom
{
unsigned char id_format; /* Format identifier (always 0x01) */
unsigned char id_machtype; /* Machine type */
unsigned char id_ethaddr[6]; /* Hardware ethernet address */
long id_date; /* Date of manufacture */
unsigned int id_sernum:24; /* Unique serial number */
unsigned char id_cksum; /* Checksum - xor of the data bytes */
unsigned char reserved[16];
};
#endif
-10
View File
@@ -1,10 +0,0 @@
#if !defined (__M48T08_H__)
#define __M48T08_H__
typedef struct m48t08_t m48t08_t;
void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val);
uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr);
m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size);
#endif /* !defined (__M48T08_H__) */
-602
View File
@@ -1,602 +0,0 @@
/*
* QEMU M48T59 NVRAM emulation for PPC PREP platform
*
* Copyright (c) 2003-2004 Jocelyn Mayer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "m48t59.h"
//#define DEBUG_NVRAM
#if defined(DEBUG_NVRAM)
#define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)
#else
#define NVRAM_PRINTF(fmt, args...) do { } while (0)
#endif
struct m48t59_t {
/* Hardware parameters */
int IRQ;
int mem_index;
uint32_t mem_base;
uint32_t io_base;
uint16_t size;
/* RTC management */
time_t time_offset;
time_t stop_time;
/* Alarm & watchdog */
time_t alarm;
struct QEMUTimer *alrm_timer;
struct QEMUTimer *wd_timer;
/* NVRAM storage */
uint8_t lock;
uint16_t addr;
uint8_t *buffer;
};
/* Fake timer functions */
/* Generic helpers for BCD */
static inline uint8_t toBCD (uint8_t value)
{
return (((value / 10) % 10) << 4) | (value % 10);
}
static inline uint8_t fromBCD (uint8_t BCD)
{
return ((BCD >> 4) * 10) + (BCD & 0x0F);
}
/* RTC management helpers */
static void get_time (m48t59_t *NVRAM, struct tm *tm)
{
time_t t;
t = time(NULL) + NVRAM->time_offset;
#ifdef _WIN32
memcpy(tm,localtime(&t),sizeof(*tm));
#else
localtime_r (&t, tm) ;
#endif
}
static void set_time (m48t59_t *NVRAM, struct tm *tm)
{
time_t now, new_time;
new_time = mktime(tm);
now = time(NULL);
NVRAM->time_offset = new_time - now;
}
/* Alarm management */
static void alarm_cb (void *opaque)
{
struct tm tm, tm_now;
uint64_t next_time;
m48t59_t *NVRAM = opaque;
pic_set_irq(NVRAM->IRQ, 1);
if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF2] & 0x80) == 0) {
/* Repeat once a month */
get_time(NVRAM, &tm_now);
memcpy(&tm, &tm_now, sizeof(struct tm));
tm.tm_mon++;
if (tm.tm_mon == 13) {
tm.tm_mon = 1;
tm.tm_year++;
}
next_time = mktime(&tm);
} else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF2] & 0x80) == 0) {
/* Repeat once a day */
next_time = 24 * 60 * 60 + mktime(&tm_now);
} else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF2] & 0x80) == 0) {
/* Repeat once an hour */
next_time = 60 * 60 + mktime(&tm_now);
} else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF3] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF2] & 0x80) == 0) {
/* Repeat once a minute */
next_time = 60 + mktime(&tm_now);
} else {
/* Repeat once a second */
next_time = 1 + mktime(&tm_now);
}
qemu_mod_timer(NVRAM->alrm_timer, next_time * 1000);
pic_set_irq(NVRAM->IRQ, 0);
}
static void get_alarm (m48t59_t *NVRAM, struct tm *tm)
{
#ifdef _WIN32
memcpy(tm,localtime(&NVRAM->alarm),sizeof(*tm));
#else
localtime_r (&NVRAM->alarm, tm);
#endif
}
static void set_alarm (m48t59_t *NVRAM, struct tm *tm)
{
NVRAM->alarm = mktime(tm);
if (NVRAM->alrm_timer != NULL) {
qemu_del_timer(NVRAM->alrm_timer);
NVRAM->alrm_timer = NULL;
}
if (NVRAM->alarm - time(NULL) > 0)
qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000);
}
/* Watchdog management */
static void watchdog_cb (void *opaque)
{
m48t59_t *NVRAM = opaque;
NVRAM->buffer[0x1FF0] |= 0x80;
if (NVRAM->buffer[0x1FF7] & 0x80) {
NVRAM->buffer[0x1FF7] = 0x00;
NVRAM->buffer[0x1FFC] &= ~0x40;
/* May it be a hw CPU Reset instead ? */
qemu_system_reset_request();
} else {
pic_set_irq(NVRAM->IRQ, 1);
pic_set_irq(NVRAM->IRQ, 0);
}
}
static void set_up_watchdog (m48t59_t *NVRAM, uint8_t value)
{
uint64_t interval; /* in 1/16 seconds */
if (NVRAM->wd_timer != NULL) {
qemu_del_timer(NVRAM->wd_timer);
NVRAM->wd_timer = NULL;
}
NVRAM->buffer[0x1FF0] &= ~0x80;
if (value != 0) {
interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F);
qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) +
((interval * 1000) >> 4));
}
}
/* Direct access to NVRAM */
void m48t59_write (m48t59_t *NVRAM, uint32_t val)
{
struct tm tm;
int tmp;
if (NVRAM->addr > 0x1FF8 && NVRAM->addr < 0x2000)
NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val);
switch (NVRAM->addr) {
case 0x1FF0:
/* flags register : read-only */
break;
case 0x1FF1:
/* unused */
break;
case 0x1FF2:
/* alarm seconds */
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_alarm(NVRAM, &tm);
tm.tm_sec = tmp;
NVRAM->buffer[0x1FF2] = val;
set_alarm(NVRAM, &tm);
}
break;
case 0x1FF3:
/* alarm minutes */
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_alarm(NVRAM, &tm);
tm.tm_min = tmp;
NVRAM->buffer[0x1FF3] = val;
set_alarm(NVRAM, &tm);
}
break;
case 0x1FF4:
/* alarm hours */
tmp = fromBCD(val & 0x3F);
if (tmp >= 0 && tmp <= 23) {
get_alarm(NVRAM, &tm);
tm.tm_hour = tmp;
NVRAM->buffer[0x1FF4] = val;
set_alarm(NVRAM, &tm);
}
break;
case 0x1FF5:
/* alarm date */
tmp = fromBCD(val & 0x1F);
if (tmp != 0) {
get_alarm(NVRAM, &tm);
tm.tm_mday = tmp;
NVRAM->buffer[0x1FF5] = val;
set_alarm(NVRAM, &tm);
}
break;
case 0x1FF6:
/* interrupts */
NVRAM->buffer[0x1FF6] = val;
break;
case 0x1FF7:
/* watchdog */
NVRAM->buffer[0x1FF7] = val;
set_up_watchdog(NVRAM, val);
break;
case 0x1FF8:
/* control */
NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90;
break;
case 0x1FF9:
/* seconds (BCD) */
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_time(NVRAM, &tm);
tm.tm_sec = tmp;
set_time(NVRAM, &tm);
}
if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) {
if (val & 0x80) {
NVRAM->stop_time = time(NULL);
} else {
NVRAM->time_offset += NVRAM->stop_time - time(NULL);
NVRAM->stop_time = 0;
}
}
NVRAM->buffer[0x1FF9] = val & 0x80;
break;
case 0x1FFA:
/* minutes (BCD) */
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_time(NVRAM, &tm);
tm.tm_min = tmp;
set_time(NVRAM, &tm);
}
break;
case 0x1FFB:
/* hours (BCD) */
tmp = fromBCD(val & 0x3F);
if (tmp >= 0 && tmp <= 23) {
get_time(NVRAM, &tm);
tm.tm_hour = tmp;
set_time(NVRAM, &tm);
}
break;
case 0x1FFC:
/* day of the week / century */
tmp = fromBCD(val & 0x07);
get_time(NVRAM, &tm);
tm.tm_wday = tmp;
set_time(NVRAM, &tm);
NVRAM->buffer[0x1FFC] = val & 0x40;
break;
case 0x1FFD:
/* date */
tmp = fromBCD(val & 0x1F);
if (tmp != 0) {
get_time(NVRAM, &tm);
tm.tm_mday = tmp;
set_time(NVRAM, &tm);
}
break;
case 0x1FFE:
/* month */
tmp = fromBCD(val & 0x1F);
if (tmp >= 1 && tmp <= 12) {
get_time(NVRAM, &tm);
tm.tm_mon = tmp - 1;
set_time(NVRAM, &tm);
}
break;
case 0x1FFF:
/* year */
tmp = fromBCD(val);
if (tmp >= 0 && tmp <= 99) {
get_time(NVRAM, &tm);
tm.tm_year = fromBCD(val);
set_time(NVRAM, &tm);
}
break;
default:
/* Check lock registers state */
if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
break;
if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
break;
if (NVRAM->addr < 0x1FF0 ||
(NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
NVRAM->buffer[NVRAM->addr] = val & 0xFF;
}
break;
}
}
uint32_t m48t59_read (m48t59_t *NVRAM)
{
struct tm tm;
uint32_t retval = 0xFF;
switch (NVRAM->addr) {
case 0x1FF0:
/* flags register */
goto do_read;
case 0x1FF1:
/* unused */
retval = 0;
break;
case 0x1FF2:
/* alarm seconds */
goto do_read;
case 0x1FF3:
/* alarm minutes */
goto do_read;
case 0x1FF4:
/* alarm hours */
goto do_read;
case 0x1FF5:
/* alarm date */
goto do_read;
case 0x1FF6:
/* interrupts */
goto do_read;
case 0x1FF7:
/* A read resets the watchdog */
set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]);
goto do_read;
case 0x1FF8:
/* control */
goto do_read;
case 0x1FF9:
/* seconds (BCD) */
get_time(NVRAM, &tm);
retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec);
break;
case 0x1FFA:
/* minutes (BCD) */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_min);
break;
case 0x1FFB:
/* hours (BCD) */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_hour);
break;
case 0x1FFC:
/* day of the week / century */
get_time(NVRAM, &tm);
retval = NVRAM->buffer[0x1FFC] | tm.tm_wday;
break;
case 0x1FFD:
/* date */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_mday);
break;
case 0x1FFE:
/* month */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_mon + 1);
break;
case 0x1FFF:
/* year */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_year);
break;
default:
/* Check lock registers state */
if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
break;
if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
break;
if (NVRAM->addr < 0x1FF0 ||
(NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
do_read:
retval = NVRAM->buffer[NVRAM->addr];
}
break;
}
if (NVRAM->addr > 0x1FF9 && NVRAM->addr < 0x2000)
NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval);
return retval;
}
void m48t59_set_addr (m48t59_t *NVRAM, uint32_t addr)
{
NVRAM->addr = addr;
}
void m48t59_toggle_lock (m48t59_t *NVRAM, int lock)
{
NVRAM->lock ^= 1 << lock;
}
/* IO access to NVRAM */
static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val)
{
m48t59_t *NVRAM = opaque;
addr -= NVRAM->io_base;
NVRAM_PRINTF("0x%08x => 0x%08x\n", addr, val);
switch (addr) {
case 0:
NVRAM->addr &= ~0x00FF;
NVRAM->addr |= val;
break;
case 1:
NVRAM->addr &= ~0xFF00;
NVRAM->addr |= val << 8;
break;
case 3:
m48t59_write(NVRAM, val);
NVRAM->addr = 0x0000;
break;
default:
break;
}
}
static uint32_t NVRAM_readb (void *opaque, uint32_t addr)
{
m48t59_t *NVRAM = opaque;
uint32_t retval;
addr -= NVRAM->io_base;
switch (addr) {
case 3:
retval = m48t59_read(NVRAM);
break;
default:
retval = -1;
break;
}
NVRAM_PRINTF("0x%08x <= 0x%08x\n", addr, retval);
return retval;
}
static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
m48t59_t *NVRAM = opaque;
addr -= NVRAM->mem_base;
if (addr < 0x1FF0)
NVRAM->buffer[addr] = value;
}
static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
{
m48t59_t *NVRAM = opaque;
addr -= NVRAM->mem_base;
if (addr < 0x1FF0) {
NVRAM->buffer[addr] = value >> 8;
NVRAM->buffer[addr + 1] = value;
}
}
static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
m48t59_t *NVRAM = opaque;
addr -= NVRAM->mem_base;
if (addr < 0x1FF0) {
NVRAM->buffer[addr] = value >> 24;
NVRAM->buffer[addr + 1] = value >> 16;
NVRAM->buffer[addr + 2] = value >> 8;
NVRAM->buffer[addr + 3] = value;
}
}
static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
{
m48t59_t *NVRAM = opaque;
uint32_t retval = 0;
addr -= NVRAM->mem_base;
if (addr < 0x1FF0)
retval = NVRAM->buffer[addr];
return retval;
}
static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
{
m48t59_t *NVRAM = opaque;
uint32_t retval = 0;
addr -= NVRAM->mem_base;
if (addr < 0x1FF0) {
retval = NVRAM->buffer[addr] << 8;
retval |= NVRAM->buffer[addr + 1];
}
return retval;
}
static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
{
m48t59_t *NVRAM = opaque;
uint32_t retval = 0;
addr -= NVRAM->mem_base;
if (addr < 0x1FF0) {
retval = NVRAM->buffer[addr] << 24;
retval |= NVRAM->buffer[addr + 1] << 16;
retval |= NVRAM->buffer[addr + 2] << 8;
retval |= NVRAM->buffer[addr + 3];
}
return retval;
}
static CPUWriteMemoryFunc *nvram_write[] = {
&nvram_writeb,
&nvram_writew,
&nvram_writel,
};
static CPUReadMemoryFunc *nvram_read[] = {
&nvram_readb,
&nvram_readw,
&nvram_readl,
};
/* Initialisation routine */
m48t59_t *m48t59_init (int IRQ, uint32_t mem_base,
uint32_t io_base, uint16_t size)
{
m48t59_t *s;
s = qemu_mallocz(sizeof(m48t59_t));
if (!s)
return NULL;
s->buffer = qemu_mallocz(size);
if (!s->buffer) {
qemu_free(s);
return NULL;
}
s->IRQ = IRQ;
s->size = size;
s->mem_base = mem_base;
s->io_base = io_base;
s->addr = 0;
register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s);
register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s);
if (mem_base != 0) {
s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
cpu_register_physical_memory(mem_base, 0x4000, s->mem_index);
}
s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s);
s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s);
s->lock = 0;
return s;
}
-13
View File
@@ -1,13 +0,0 @@
#if !defined (__M48T59_H__)
#define __M48T59_H__
typedef struct m48t59_t m48t59_t;
void m48t59_write (m48t59_t *NVRAM, uint32_t val);
uint32_t m48t59_read (m48t59_t *NVRAM);
void m48t59_set_addr (m48t59_t *NVRAM, uint32_t addr);
void m48t59_toggle_lock (m48t59_t *NVRAM, int lock);
m48t59_t *m48t59_init (int IRQ, uint32_t io_base,
uint32_t mem_base, uint16_t size);
#endif /* !defined (__M48T59_H__) */
-201
View File
@@ -1,201 +0,0 @@
#include "vl.h"
#include "disas.h"
#include "exec-all.h"
struct exec
{
uint32_t a_info; /* Use macros N_MAGIC, etc for access */
uint32_t a_text; /* length of text, in bytes */
uint32_t a_data; /* length of data, in bytes */
uint32_t a_bss; /* length of uninitialized data area, in bytes */
uint32_t a_syms; /* length of symbol table data in file, in bytes */
uint32_t a_entry; /* start address */
uint32_t a_trsize; /* length of relocation info for text, in bytes */
uint32_t a_drsize; /* length of relocation info for data, in bytes */
};
#ifdef BSWAP_NEEDED
static void bswap_ahdr(struct exec *e)
{
bswap32s(&e->a_info);
bswap32s(&e->a_text);
bswap32s(&e->a_data);
bswap32s(&e->a_bss);
bswap32s(&e->a_syms);
bswap32s(&e->a_entry);
bswap32s(&e->a_trsize);
bswap32s(&e->a_drsize);
}
#else
#define bswap_ahdr(x) do { } while (0)
#endif
#define N_MAGIC(exec) ((exec).a_info & 0xffff)
#define OMAGIC 0407
#define NMAGIC 0410
#define ZMAGIC 0413
#define QMAGIC 0314
#define _N_HDROFF(x) (1024 - sizeof (struct exec))
#define N_TXTOFF(x) \
(N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \
(N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec)))
#define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? TARGET_PAGE_SIZE : 0)
#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text)
#define _N_SEGMENT_ROUND(x) (((x) + TARGET_PAGE_SIZE - 1) & ~(TARGET_PAGE_SIZE - 1))
#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
#define N_DATADDR(x) \
(N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \
: (_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
#define ELF_CLASS ELFCLASS32
#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_SPARC
#include "elf.h"
#ifndef BSWAP_NEEDED
#define bswap_ehdr32(e) do { } while (0)
#define bswap_phdr32(e) do { } while (0)
#define bswap_shdr32(e) do { } while (0)
#define bswap_sym32(e) do { } while (0)
#ifdef TARGET_SPARC64
#define bswap_ehdr64(e) do { } while (0)
#define bswap_phdr64(e) do { } while (0)
#define bswap_shdr64(e) do { } while (0)
#define bswap_sym64(e) do { } while (0)
#endif
#endif
#define SZ 32
#define elf_word uint32_t
#define bswapSZs bswap32s
#include "elf_ops.h"
#ifdef TARGET_SPARC64
#undef elfhdr
#undef elf_phdr
#undef elf_shdr
#undef elf_sym
#undef elf_note
#undef elf_word
#undef bswapSZs
#undef SZ
#define elfhdr elf64_hdr
#define elf_phdr elf64_phdr
#define elf_note elf64_note
#define elf_shdr elf64_shdr
#define elf_sym elf64_sym
#define elf_word uint64_t
#define bswapSZs bswap64s
#define SZ 64
#include "elf_ops.h"
#endif
int load_elf(const char *filename, uint8_t *addr)
{
struct elf32_hdr ehdr;
int retval, fd;
Elf32_Half machine;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
goto error;
retval = read(fd, &ehdr, sizeof(ehdr));
if (retval < 0)
goto error;
if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E'
|| ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F')
goto error;
machine = tswap16(ehdr.e_machine);
if (machine == EM_SPARC || machine == EM_SPARC32PLUS) {
struct elf32_phdr phdr;
bswap_ehdr32(&ehdr);
if (find_phdr32(&ehdr, fd, &phdr, PT_LOAD))
goto error;
retval = read_program32(fd, &phdr, addr, ehdr.e_entry);
if (retval < 0)
goto error;
load_symbols32(&ehdr, fd);
}
#ifdef TARGET_SPARC64
else if (machine == EM_SPARCV9) {
struct elf64_hdr ehdr64;
struct elf64_phdr phdr;
lseek(fd, 0, SEEK_SET);
retval = read(fd, &ehdr64, sizeof(ehdr64));
if (retval < 0)
goto error;
bswap_ehdr64(&ehdr64);
if (find_phdr64(&ehdr64, fd, &phdr, PT_LOAD))
goto error;
retval = read_program64(fd, &phdr, phys_ram_base + ehdr64.e_entry, ehdr64.e_entry);
if (retval < 0)
goto error;
load_symbols64(&ehdr64, fd);
}
#endif
close(fd);
return retval;
error:
close(fd);
return -1;
}
int load_aout(const char *filename, uint8_t *addr)
{
int fd, size, ret;
struct exec e;
uint32_t magic;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
return -1;
size = read(fd, &e, sizeof(e));
if (size < 0)
goto fail;
bswap_ahdr(&e);
magic = N_MAGIC(e);
switch (magic) {
case ZMAGIC:
case QMAGIC:
case OMAGIC:
lseek(fd, N_TXTOFF(e), SEEK_SET);
size = read(fd, addr, e.a_text + e.a_data);
if (size < 0)
goto fail;
break;
case NMAGIC:
lseek(fd, N_TXTOFF(e), SEEK_SET);
size = read(fd, addr, e.a_text);
if (size < 0)
goto fail;
ret = read(fd, addr + N_DATADDR(e), e.a_data);
if (ret < 0)
goto fail;
size += ret;
break;
default:
goto fail;
}
close(fd);
return size;
fail:
close(fd);
return -1;
}
-463
View File
@@ -1,463 +0,0 @@
/*
* QEMU MC146818 RTC emulation
*
* Copyright (c) 2003-2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
//#define DEBUG_CMOS
#define RTC_SECONDS 0
#define RTC_SECONDS_ALARM 1
#define RTC_MINUTES 2
#define RTC_MINUTES_ALARM 3
#define RTC_HOURS 4
#define RTC_HOURS_ALARM 5
#define RTC_ALARM_DONT_CARE 0xC0
#define RTC_DAY_OF_WEEK 6
#define RTC_DAY_OF_MONTH 7
#define RTC_MONTH 8
#define RTC_YEAR 9
#define RTC_REG_A 10
#define RTC_REG_B 11
#define RTC_REG_C 12
#define RTC_REG_D 13
#define REG_A_UIP 0x80
#define REG_B_SET 0x80
#define REG_B_PIE 0x40
#define REG_B_AIE 0x20
#define REG_B_UIE 0x10
struct RTCState {
uint8_t cmos_data[128];
uint8_t cmos_index;
struct tm current_tm;
int irq;
/* periodic timer */
QEMUTimer *periodic_timer;
int64_t next_periodic_time;
/* second update */
int64_t next_second_time;
QEMUTimer *second_timer;
QEMUTimer *second_timer2;
};
static void rtc_set_time(RTCState *s);
static void rtc_copy_date(RTCState *s);
static void rtc_timer_update(RTCState *s, int64_t current_time)
{
int period_code, period;
int64_t cur_clock, next_irq_clock;
period_code = s->cmos_data[RTC_REG_A] & 0x0f;
if (period_code != 0 &&
(s->cmos_data[RTC_REG_B] & REG_B_PIE)) {
if (period_code <= 2)
period_code += 7;
/* period in 32 Khz cycles */
period = 1 << (period_code - 1);
/* compute 32 khz clock */
cur_clock = muldiv64(current_time, 32768, ticks_per_sec);
next_irq_clock = (cur_clock & ~(period - 1)) + period;
s->next_periodic_time = muldiv64(next_irq_clock, ticks_per_sec, 32768) + 1;
qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
} else {
qemu_del_timer(s->periodic_timer);
}
}
static void rtc_periodic_timer(void *opaque)
{
RTCState *s = opaque;
rtc_timer_update(s, s->next_periodic_time);
s->cmos_data[RTC_REG_C] |= 0xc0;
pic_set_irq(s->irq, 1);
}
static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
{
RTCState *s = opaque;
if ((addr & 1) == 0) {
s->cmos_index = data & 0x7f;
} else {
#ifdef DEBUG_CMOS
printf("cmos: write index=0x%02x val=0x%02x\n",
s->cmos_index, data);
#endif
switch(s->cmos_index) {
case RTC_SECONDS_ALARM:
case RTC_MINUTES_ALARM:
case RTC_HOURS_ALARM:
/* XXX: not supported */
s->cmos_data[s->cmos_index] = data;
break;
case RTC_SECONDS:
case RTC_MINUTES:
case RTC_HOURS:
case RTC_DAY_OF_WEEK:
case RTC_DAY_OF_MONTH:
case RTC_MONTH:
case RTC_YEAR:
s->cmos_data[s->cmos_index] = data;
/* if in set mode, do not update the time */
if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
rtc_set_time(s);
}
break;
case RTC_REG_A:
/* UIP bit is read only */
s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) |
(s->cmos_data[RTC_REG_A] & REG_A_UIP);
rtc_timer_update(s, qemu_get_clock(vm_clock));
break;
case RTC_REG_B:
if (data & REG_B_SET) {
/* set mode: reset UIP mode */
s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
data &= ~REG_B_UIE;
} else {
/* if disabling set mode, update the time */
if (s->cmos_data[RTC_REG_B] & REG_B_SET) {
rtc_set_time(s);
}
}
s->cmos_data[RTC_REG_B] = data;
rtc_timer_update(s, qemu_get_clock(vm_clock));
break;
case RTC_REG_C:
case RTC_REG_D:
/* cannot write to them */
break;
default:
s->cmos_data[s->cmos_index] = data;
break;
}
}
}
static inline int to_bcd(RTCState *s, int a)
{
if (s->cmos_data[RTC_REG_B] & 0x04) {
return a;
} else {
return ((a / 10) << 4) | (a % 10);
}
}
static inline int from_bcd(RTCState *s, int a)
{
if (s->cmos_data[RTC_REG_B] & 0x04) {
return a;
} else {
return ((a >> 4) * 10) + (a & 0x0f);
}
}
static void rtc_set_time(RTCState *s)
{
struct tm *tm = &s->current_tm;
tm->tm_sec = from_bcd(s, s->cmos_data[RTC_SECONDS]);
tm->tm_min = from_bcd(s, s->cmos_data[RTC_MINUTES]);
tm->tm_hour = from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
if (!(s->cmos_data[RTC_REG_B] & 0x02) &&
(s->cmos_data[RTC_HOURS] & 0x80)) {
tm->tm_hour += 12;
}
tm->tm_wday = from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]);
tm->tm_mday = from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
tm->tm_mon = from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + 100;
}
static void rtc_copy_date(RTCState *s)
{
const struct tm *tm = &s->current_tm;
s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec);
s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min);
if (s->cmos_data[RTC_REG_B] & 0x02) {
/* 24 hour format */
s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour);
} else {
/* 12 hour format */
s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour % 12);
if (tm->tm_hour >= 12)
s->cmos_data[RTC_HOURS] |= 0x80;
}
s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday);
s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday);
s->cmos_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1);
s->cmos_data[RTC_YEAR] = to_bcd(s, tm->tm_year % 100);
}
/* month is between 0 and 11. */
static int get_days_in_month(int month, int year)
{
static const int days_tab[12] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
int d;
if ((unsigned )month >= 12)
return 31;
d = days_tab[month];
if (month == 1) {
if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0))
d++;
}
return d;
}
/* update 'tm' to the next second */
static void rtc_next_second(struct tm *tm)
{
int days_in_month;
tm->tm_sec++;
if ((unsigned)tm->tm_sec >= 60) {
tm->tm_sec = 0;
tm->tm_min++;
if ((unsigned)tm->tm_min >= 60) {
tm->tm_min = 0;
tm->tm_hour++;
if ((unsigned)tm->tm_hour >= 24) {
tm->tm_hour = 0;
/* next day */
tm->tm_wday++;
if ((unsigned)tm->tm_wday >= 7)
tm->tm_wday = 0;
days_in_month = get_days_in_month(tm->tm_mon,
tm->tm_year + 1900);
tm->tm_mday++;
if (tm->tm_mday < 1) {
tm->tm_mday = 1;
} else if (tm->tm_mday > days_in_month) {
tm->tm_mday = 1;
tm->tm_mon++;
if (tm->tm_mon >= 12) {
tm->tm_mon = 0;
tm->tm_year++;
}
}
}
}
}
}
static void rtc_update_second(void *opaque)
{
RTCState *s = opaque;
int64_t delay;
/* if the oscillator is not in normal operation, we do not update */
if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) {
s->next_second_time += ticks_per_sec;
qemu_mod_timer(s->second_timer, s->next_second_time);
} else {
rtc_next_second(&s->current_tm);
if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
/* update in progress bit */
s->cmos_data[RTC_REG_A] |= REG_A_UIP;
}
/* should be 244 us = 8 / 32768 seconds, but currently the
timers do not have the necessary resolution. */
delay = (ticks_per_sec * 1) / 100;
if (delay < 1)
delay = 1;
qemu_mod_timer(s->second_timer2,
s->next_second_time + delay);
}
}
static void rtc_update_second2(void *opaque)
{
RTCState *s = opaque;
if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
rtc_copy_date(s);
}
/* check alarm */
if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
s->cmos_data[RTC_SECONDS_ALARM] == s->current_tm.tm_sec) &&
((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
s->cmos_data[RTC_MINUTES_ALARM] == s->current_tm.tm_mon) &&
((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {
s->cmos_data[RTC_REG_C] |= 0xa0;
pic_set_irq(s->irq, 1);
}
}
/* update ended interrupt */
if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
s->cmos_data[RTC_REG_C] |= 0x90;
pic_set_irq(s->irq, 1);
}
/* clear update in progress bit */
s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
s->next_second_time += ticks_per_sec;
qemu_mod_timer(s->second_timer, s->next_second_time);
}
static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
{
RTCState *s = opaque;
int ret;
if ((addr & 1) == 0) {
return 0xff;
} else {
switch(s->cmos_index) {
case RTC_SECONDS:
case RTC_MINUTES:
case RTC_HOURS:
case RTC_DAY_OF_WEEK:
case RTC_DAY_OF_MONTH:
case RTC_MONTH:
case RTC_YEAR:
ret = s->cmos_data[s->cmos_index];
break;
case RTC_REG_A:
ret = s->cmos_data[s->cmos_index];
break;
case RTC_REG_C:
ret = s->cmos_data[s->cmos_index];
pic_set_irq(s->irq, 0);
s->cmos_data[RTC_REG_C] = 0x00;
break;
default:
ret = s->cmos_data[s->cmos_index];
break;
}
#ifdef DEBUG_CMOS
printf("cmos: read index=0x%02x val=0x%02x\n",
s->cmos_index, ret);
#endif
return ret;
}
}
void rtc_set_memory(RTCState *s, int addr, int val)
{
if (addr >= 0 && addr <= 127)
s->cmos_data[addr] = val;
}
void rtc_set_date(RTCState *s, const struct tm *tm)
{
s->current_tm = *tm;
rtc_copy_date(s);
}
static void rtc_save(QEMUFile *f, void *opaque)
{
RTCState *s = opaque;
qemu_put_buffer(f, s->cmos_data, 128);
qemu_put_8s(f, &s->cmos_index);
qemu_put_be32s(f, &s->current_tm.tm_sec);
qemu_put_be32s(f, &s->current_tm.tm_min);
qemu_put_be32s(f, &s->current_tm.tm_hour);
qemu_put_be32s(f, &s->current_tm.tm_wday);
qemu_put_be32s(f, &s->current_tm.tm_mday);
qemu_put_be32s(f, &s->current_tm.tm_mon);
qemu_put_be32s(f, &s->current_tm.tm_year);
qemu_put_timer(f, s->periodic_timer);
qemu_put_be64s(f, &s->next_periodic_time);
qemu_put_be64s(f, &s->next_second_time);
qemu_put_timer(f, s->second_timer);
qemu_put_timer(f, s->second_timer2);
}
static int rtc_load(QEMUFile *f, void *opaque, int version_id)
{
RTCState *s = opaque;
if (version_id != 1)
return -EINVAL;
qemu_get_buffer(f, s->cmos_data, 128);
qemu_get_8s(f, &s->cmos_index);
qemu_get_be32s(f, &s->current_tm.tm_sec);
qemu_get_be32s(f, &s->current_tm.tm_min);
qemu_get_be32s(f, &s->current_tm.tm_hour);
qemu_get_be32s(f, &s->current_tm.tm_wday);
qemu_get_be32s(f, &s->current_tm.tm_mday);
qemu_get_be32s(f, &s->current_tm.tm_mon);
qemu_get_be32s(f, &s->current_tm.tm_year);
qemu_get_timer(f, s->periodic_timer);
qemu_get_be64s(f, &s->next_periodic_time);
qemu_get_be64s(f, &s->next_second_time);
qemu_get_timer(f, s->second_timer);
qemu_get_timer(f, s->second_timer2);
return 0;
}
RTCState *rtc_init(int base, int irq)
{
RTCState *s;
s = qemu_mallocz(sizeof(RTCState));
if (!s)
return NULL;
s->irq = irq;
s->cmos_data[RTC_REG_A] = 0x26;
s->cmos_data[RTC_REG_B] = 0x02;
s->cmos_data[RTC_REG_C] = 0x00;
s->cmos_data[RTC_REG_D] = 0x80;
s->periodic_timer = qemu_new_timer(vm_clock,
rtc_periodic_timer, s);
s->second_timer = qemu_new_timer(vm_clock,
rtc_update_second, s);
s->second_timer2 = qemu_new_timer(vm_clock,
rtc_update_second2, s);
s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100;
qemu_mod_timer(s->second_timer2, s->next_second_time);
register_ioport_write(base, 2, 1, cmos_ioport_write, s);
register_ioport_read(base, 2, 1, cmos_ioport_read, s);
register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
return s;
}
-254
View File
@@ -1,254 +0,0 @@
#include "vl.h"
#define BIOS_FILENAME "mips_bios.bin"
//#define BIOS_FILENAME "system.bin"
#define KERNEL_LOAD_ADDR 0x80010000
#define INITRD_LOAD_ADDR 0x80800000
extern FILE *logfile;
static void pic_irq_request(void *opaque, int level)
{
if (level) {
cpu_single_env->CP0_Cause |= 0x00000400;
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
} else {
cpu_single_env->CP0_Cause &= ~0x00000400;
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
}
void cpu_mips_irqctrl_init (void)
{
}
uint32_t cpu_mips_get_random (CPUState *env)
{
uint32_t now = qemu_get_clock(vm_clock);
return now % (MIPS_TLB_NB - env->CP0_Wired) + env->CP0_Wired;
}
/* MIPS R4K timer */
uint32_t cpu_mips_get_count (CPUState *env)
{
return env->CP0_Count +
(uint32_t)muldiv64(qemu_get_clock(vm_clock),
100 * 1000 * 1000, ticks_per_sec);
}
static void cpu_mips_update_count (CPUState *env, uint32_t count,
uint32_t compare)
{
uint64_t now, next;
uint32_t tmp;
tmp = count;
if (count == compare)
tmp++;
now = qemu_get_clock(vm_clock);
next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000);
if (next == now)
next++;
#if 1
if (logfile) {
fprintf(logfile, "%s: 0x%08llx %08x %08x => 0x%08llx\n",
__func__, now, count, compare, next - now);
}
#endif
/* Store new count and compare registers */
env->CP0_Compare = compare;
env->CP0_Count =
count - (uint32_t)muldiv64(now, 100 * 1000 * 1000, ticks_per_sec);
/* Adjust timer */
qemu_mod_timer(env->timer, next);
}
void cpu_mips_store_count (CPUState *env, uint32_t value)
{
cpu_mips_update_count(env, value, env->CP0_Compare);
}
void cpu_mips_store_compare (CPUState *env, uint32_t value)
{
cpu_mips_update_count(env, cpu_mips_get_count(env), value);
pic_set_irq(5, 0);
}
static void mips_timer_cb (void *opaque)
{
CPUState *env;
env = opaque;
#if 1
if (logfile) {
fprintf(logfile, "%s\n", __func__);
}
#endif
cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare);
pic_set_irq(5, 1);
}
void cpu_mips_clock_init (CPUState *env)
{
env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env);
env->CP0_Compare = 0;
cpu_mips_update_count(env, 1, 0);
}
static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
cpu_outb(NULL, addr & 0xffff, value);
}
static uint32_t io_readb (void *opaque, target_phys_addr_t addr)
{
uint32_t ret = cpu_inb(NULL, addr & 0xffff);
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
return ret;
}
static void io_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
{
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap16(value);
#endif
cpu_outw(NULL, addr & 0xffff, value);
}
static uint32_t io_readw (void *opaque, target_phys_addr_t addr)
{
uint32_t ret = cpu_inw(NULL, addr & 0xffff);
#ifdef TARGET_WORDS_BIGENDIAN
ret = bswap16(ret);
#endif
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
return ret;
}
static void io_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap32(value);
#endif
cpu_outl(NULL, addr & 0xffff, value);
}
static uint32_t io_readl (void *opaque, target_phys_addr_t addr)
{
uint32_t ret = cpu_inl(NULL, addr & 0xffff);
#ifdef TARGET_WORDS_BIGENDIAN
ret = bswap32(ret);
#endif
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
return ret;
}
CPUWriteMemoryFunc *io_write[] = {
&io_writeb,
&io_writew,
&io_writel,
};
CPUReadMemoryFunc *io_read[] = {
&io_readb,
&io_readw,
&io_readl,
};
void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
char buf[1024];
target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
unsigned long bios_offset;
int io_memory;
int linux_boot;
int ret;
printf("%s: start\n", __func__);
linux_boot = (kernel_filename != NULL);
/* allocate RAM */
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
bios_offset = ram_size + vga_ram_size;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
printf("%s: load BIOS '%s' size %d\n", __func__, buf, BIOS_SIZE);
ret = load_image(buf, phys_ram_base + bios_offset);
if (ret != BIOS_SIZE) {
fprintf(stderr, "qemu: could not load MIPS bios '%s'\n", buf);
exit(1);
}
cpu_register_physical_memory((uint32_t)(0x1fc00000),
BIOS_SIZE, bios_offset | IO_MEM_ROM);
#if 0
memcpy(phys_ram_base + 0x10000, phys_ram_base + bios_offset, BIOS_SIZE);
cpu_single_env->PC = 0x80010004;
#else
cpu_single_env->PC = 0xBFC00004;
#endif
if (linux_boot) {
kernel_base = KERNEL_LOAD_ADDR;
/* now we can load the kernel */
kernel_size = load_image(kernel_filename,
phys_ram_base + (kernel_base - 0x80000000));
if (kernel_size == (target_ulong) -1) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
kernel_filename);
exit(1);
}
/* load initrd */
if (initrd_filename) {
initrd_base = INITRD_LOAD_ADDR;
initrd_size = load_image(initrd_filename,
phys_ram_base + initrd_base);
if (initrd_size == (target_ulong) -1) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
exit(1);
}
} else {
initrd_base = 0;
initrd_size = 0;
}
cpu_single_env->PC = KERNEL_LOAD_ADDR;
} else {
kernel_base = 0;
kernel_size = 0;
initrd_base = 0;
initrd_size = 0;
}
/* Init internal devices */
cpu_mips_clock_init(cpu_single_env);
cpu_mips_irqctrl_init();
/* Register 64 KB of ISA IO space at 0x14000000 */
io_memory = cpu_register_io_memory(0, io_read, io_write, NULL);
cpu_register_physical_memory(0x14000000, 0x00010000, io_memory);
isa_mem_base = 0x10000000;
isa_pic = pic_init(pic_irq_request, cpu_single_env);
serial_init(0x3f8, 4, serial_hds[0]);
vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size,
vga_ram_size, 0, 0);
isa_ne2000_init(0x300, 9, &nd_table[0]);
}
QEMUMachine mips_machine = {
"mips",
"mips r4k platform",
mips_r4k_init,
};
-701
View File
@@ -1,701 +0,0 @@
/*
* QEMU NE2000 emulation
*
* Copyright (c) 2003-2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
/* debug NE2000 card */
//#define DEBUG_NE2000
#define MAX_ETH_FRAME_SIZE 1514
#define E8390_CMD 0x00 /* The command register (for all pages) */
/* Page 0 register offsets. */
#define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */
#define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */
#define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */
#define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */
#define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */
#define EN0_TSR 0x04 /* Transmit status reg RD */
#define EN0_TPSR 0x04 /* Transmit starting page WR */
#define EN0_NCR 0x05 /* Number of collision reg RD */
#define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */
#define EN0_FIFO 0x06 /* FIFO RD */
#define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */
#define EN0_ISR 0x07 /* Interrupt status reg RD WR */
#define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */
#define EN0_RSARLO 0x08 /* Remote start address reg 0 */
#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */
#define EN0_RSARHI 0x09 /* Remote start address reg 1 */
#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */
#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */
#define EN0_RSR 0x0c /* rx status reg RD */
#define EN0_RXCR 0x0c /* RX configuration reg WR */
#define EN0_TXCR 0x0d /* TX configuration reg WR */
#define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */
#define EN0_DCFG 0x0e /* Data configuration reg WR */
#define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */
#define EN0_IMR 0x0f /* Interrupt mask reg WR */
#define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */
#define EN1_PHYS 0x11
#define EN1_CURPAG 0x17
#define EN1_MULT 0x18
#define EN2_STARTPG 0x21 /* Starting page of ring bfr RD */
#define EN2_STOPPG 0x22 /* Ending page +1 of ring bfr RD */
/* Register accessed at EN_CMD, the 8390 base addr. */
#define E8390_STOP 0x01 /* Stop and reset the chip */
#define E8390_START 0x02 /* Start the chip, clear reset */
#define E8390_TRANS 0x04 /* Transmit a frame */
#define E8390_RREAD 0x08 /* Remote read */
#define E8390_RWRITE 0x10 /* Remote write */
#define E8390_NODMA 0x20 /* Remote DMA */
#define E8390_PAGE0 0x00 /* Select page chip registers */
#define E8390_PAGE1 0x40 /* using the two high-order bits */
#define E8390_PAGE2 0x80 /* Page 3 is invalid. */
/* Bits in EN0_ISR - Interrupt status register */
#define ENISR_RX 0x01 /* Receiver, no error */
#define ENISR_TX 0x02 /* Transmitter, no error */
#define ENISR_RX_ERR 0x04 /* Receiver, with error */
#define ENISR_TX_ERR 0x08 /* Transmitter, with error */
#define ENISR_OVER 0x10 /* Receiver overwrote the ring */
#define ENISR_COUNTERS 0x20 /* Counters need emptying */
#define ENISR_RDC 0x40 /* remote dma complete */
#define ENISR_RESET 0x80 /* Reset completed */
#define ENISR_ALL 0x3f /* Interrupts we will enable */
/* Bits in received packet status byte and EN0_RSR*/
#define ENRSR_RXOK 0x01 /* Received a good packet */
#define ENRSR_CRC 0x02 /* CRC error */
#define ENRSR_FAE 0x04 /* frame alignment error */
#define ENRSR_FO 0x08 /* FIFO overrun */
#define ENRSR_MPA 0x10 /* missed pkt */
#define ENRSR_PHY 0x20 /* physical/multicast address */
#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */
#define ENRSR_DEF 0x80 /* deferring */
/* Transmitted packet status, EN0_TSR. */
#define ENTSR_PTX 0x01 /* Packet transmitted without error */
#define ENTSR_ND 0x02 /* The transmit wasn't deferred. */
#define ENTSR_COL 0x04 /* The transmit collided at least once. */
#define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */
#define ENTSR_CRS 0x10 /* The carrier sense was lost. */
#define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */
#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */
#define ENTSR_OWC 0x80 /* There was an out-of-window collision. */
#define NE2000_PMEM_SIZE (32*1024)
#define NE2000_PMEM_START (16*1024)
#define NE2000_PMEM_END (NE2000_PMEM_SIZE+NE2000_PMEM_START)
#define NE2000_MEM_SIZE NE2000_PMEM_END
typedef struct NE2000State {
uint8_t cmd;
uint32_t start;
uint32_t stop;
uint8_t boundary;
uint8_t tsr;
uint8_t tpsr;
uint16_t tcnt;
uint16_t rcnt;
uint32_t rsar;
uint8_t rsr;
uint8_t isr;
uint8_t dcfg;
uint8_t imr;
uint8_t phys[6]; /* mac address */
uint8_t curpag;
uint8_t mult[8]; /* multicast mask array */
int irq;
PCIDevice *pci_dev;
NetDriverState *nd;
uint8_t mem[NE2000_MEM_SIZE];
} NE2000State;
static void ne2000_reset(NE2000State *s)
{
int i;
s->isr = ENISR_RESET;
memcpy(s->mem, s->nd->macaddr, 6);
s->mem[14] = 0x57;
s->mem[15] = 0x57;
/* duplicate prom data */
for(i = 15;i >= 0; i--) {
s->mem[2 * i] = s->mem[i];
s->mem[2 * i + 1] = s->mem[i];
}
}
static void ne2000_update_irq(NE2000State *s)
{
int isr;
isr = (s->isr & s->imr) & 0x7f;
#if defined(DEBUG_NE2000)
printf("NE2000: Set IRQ line %d to %d (%02x %02x)\n",
s->irq, isr ? 1 : 0, s->isr, s->imr);
#endif
if (s->irq == 16) {
/* PCI irq */
pci_set_irq(s->pci_dev, 0, (isr != 0));
} else {
/* ISA irq */
pic_set_irq(s->irq, (isr != 0));
}
}
/* return the max buffer size if the NE2000 can receive more data */
static int ne2000_can_receive(void *opaque)
{
NE2000State *s = opaque;
int avail, index, boundary;
if (s->cmd & E8390_STOP)
return 0;
index = s->curpag << 8;
boundary = s->boundary << 8;
if (index < boundary)
avail = boundary - index;
else
avail = (s->stop - s->start) - (index - boundary);
if (avail < (MAX_ETH_FRAME_SIZE + 4))
return 0;
return MAX_ETH_FRAME_SIZE;
}
#define MIN_BUF_SIZE 60
static void ne2000_receive(void *opaque, const uint8_t *buf, int size)
{
NE2000State *s = opaque;
uint8_t *p;
int total_len, next, avail, len, index;
uint8_t buf1[60];
#if defined(DEBUG_NE2000)
printf("NE2000: received len=%d\n", size);
#endif
/* if too small buffer, then expand it */
if (size < MIN_BUF_SIZE) {
memcpy(buf1, buf, size);
memset(buf1 + size, 0, MIN_BUF_SIZE - size);
buf = buf1;
size = MIN_BUF_SIZE;
}
index = s->curpag << 8;
/* 4 bytes for header */
total_len = size + 4;
/* address for next packet (4 bytes for CRC) */
next = index + ((total_len + 4 + 255) & ~0xff);
if (next >= s->stop)
next -= (s->stop - s->start);
/* prepare packet header */
p = s->mem + index;
s->rsr = ENRSR_RXOK; /* receive status */
/* XXX: check this */
if (buf[0] & 0x01)
s->rsr |= ENRSR_PHY;
p[0] = s->rsr;
p[1] = next >> 8;
p[2] = total_len;
p[3] = total_len >> 8;
index += 4;
/* write packet data */
while (size > 0) {
avail = s->stop - index;
len = size;
if (len > avail)
len = avail;
memcpy(s->mem + index, buf, len);
buf += len;
index += len;
if (index == s->stop)
index = s->start;
size -= len;
}
s->curpag = next >> 8;
/* now we can signal we have receive something */
s->isr |= ENISR_RX;
ne2000_update_irq(s);
}
static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
NE2000State *s = opaque;
int offset, page, index;
addr &= 0xf;
#ifdef DEBUG_NE2000
printf("NE2000: write addr=0x%x val=0x%02x\n", addr, val);
#endif
if (addr == E8390_CMD) {
/* control register */
s->cmd = val;
if (!(val & E8390_STOP)) { /* START bit makes no sense on RTL8029... */
s->isr &= ~ENISR_RESET;
/* test specific case: zero length transfert */
if ((val & (E8390_RREAD | E8390_RWRITE)) &&
s->rcnt == 0) {
s->isr |= ENISR_RDC;
ne2000_update_irq(s);
}
if (val & E8390_TRANS) {
index = (s->tpsr << 8);
/* XXX: next 2 lines are a hack to make netware 3.11 work */
if (index >= NE2000_PMEM_END)
index -= NE2000_PMEM_SIZE;
/* fail safe: check range on the transmitted length */
if (index + s->tcnt <= NE2000_PMEM_END) {
qemu_send_packet(s->nd, s->mem + index, s->tcnt);
}
/* signal end of transfert */
s->tsr = ENTSR_PTX;
s->isr |= ENISR_TX;
s->cmd &= ~E8390_TRANS;
ne2000_update_irq(s);
}
}
} else {
page = s->cmd >> 6;
offset = addr | (page << 4);
switch(offset) {
case EN0_STARTPG:
s->start = val << 8;
break;
case EN0_STOPPG:
s->stop = val << 8;
break;
case EN0_BOUNDARY:
s->boundary = val;
break;
case EN0_IMR:
s->imr = val;
ne2000_update_irq(s);
break;
case EN0_TPSR:
s->tpsr = val;
break;
case EN0_TCNTLO:
s->tcnt = (s->tcnt & 0xff00) | val;
break;
case EN0_TCNTHI:
s->tcnt = (s->tcnt & 0x00ff) | (val << 8);
break;
case EN0_RSARLO:
s->rsar = (s->rsar & 0xff00) | val;
break;
case EN0_RSARHI:
s->rsar = (s->rsar & 0x00ff) | (val << 8);
break;
case EN0_RCNTLO:
s->rcnt = (s->rcnt & 0xff00) | val;
break;
case EN0_RCNTHI:
s->rcnt = (s->rcnt & 0x00ff) | (val << 8);
break;
case EN0_DCFG:
s->dcfg = val;
break;
case EN0_ISR:
s->isr &= ~(val & 0x7f);
ne2000_update_irq(s);
break;
case EN1_PHYS ... EN1_PHYS + 5:
s->phys[offset - EN1_PHYS] = val;
break;
case EN1_CURPAG:
s->curpag = val;
break;
case EN1_MULT ... EN1_MULT + 7:
s->mult[offset - EN1_MULT] = val;
break;
}
}
}
static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
{
NE2000State *s = opaque;
int offset, page, ret;
addr &= 0xf;
if (addr == E8390_CMD) {
ret = s->cmd;
} else {
page = s->cmd >> 6;
offset = addr | (page << 4);
switch(offset) {
case EN0_TSR:
ret = s->tsr;
break;
case EN0_BOUNDARY:
ret = s->boundary;
break;
case EN0_ISR:
ret = s->isr;
break;
case EN0_RSARLO:
ret = s->rsar & 0x00ff;
break;
case EN0_RSARHI:
ret = s->rsar >> 8;
break;
case EN1_PHYS ... EN1_PHYS + 5:
ret = s->phys[offset - EN1_PHYS];
break;
case EN1_CURPAG:
ret = s->curpag;
break;
case EN1_MULT ... EN1_MULT + 7:
ret = s->mult[offset - EN1_MULT];
break;
case EN0_RSR:
ret = s->rsr;
break;
case EN2_STARTPG:
ret = s->start >> 8;
break;
case EN2_STOPPG:
ret = s->stop >> 8;
break;
default:
ret = 0x00;
break;
}
}
#ifdef DEBUG_NE2000
printf("NE2000: read addr=0x%x val=%02x\n", addr, ret);
#endif
return ret;
}
static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr,
uint32_t val)
{
if (addr < 32 ||
(addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
s->mem[addr] = val;
}
}
static inline void ne2000_mem_writew(NE2000State *s, uint32_t addr,
uint32_t val)
{
addr &= ~1; /* XXX: check exact behaviour if not even */
if (addr < 32 ||
(addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
*(uint16_t *)(s->mem + addr) = cpu_to_le16(val);
}
}
static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr,
uint32_t val)
{
addr &= ~1; /* XXX: check exact behaviour if not even */
if (addr < 32 ||
(addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
cpu_to_le32wu((uint32_t *)(s->mem + addr), val);
}
}
static inline uint32_t ne2000_mem_readb(NE2000State *s, uint32_t addr)
{
if (addr < 32 ||
(addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
return s->mem[addr];
} else {
return 0xff;
}
}
static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr)
{
addr &= ~1; /* XXX: check exact behaviour if not even */
if (addr < 32 ||
(addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
return le16_to_cpu(*(uint16_t *)(s->mem + addr));
} else {
return 0xffff;
}
}
static inline uint32_t ne2000_mem_readl(NE2000State *s, uint32_t addr)
{
addr &= ~1; /* XXX: check exact behaviour if not even */
if (addr < 32 ||
(addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
return le32_to_cpupu((uint32_t *)(s->mem + addr));
} else {
return 0xffffffff;
}
}
static inline void ne2000_dma_update(NE2000State *s, int len)
{
s->rsar += len;
/* wrap */
/* XXX: check what to do if rsar > stop */
if (s->rsar == s->stop)
s->rsar = s->start;
if (s->rcnt <= len) {
s->rcnt = 0;
/* signal end of transfert */
s->isr |= ENISR_RDC;
ne2000_update_irq(s);
} else {
s->rcnt -= len;
}
}
static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
NE2000State *s = opaque;
#ifdef DEBUG_NE2000
printf("NE2000: asic write val=0x%04x\n", val);
#endif
if (s->rcnt == 0)
return;
if (s->dcfg & 0x01) {
/* 16 bit access */
ne2000_mem_writew(s, s->rsar, val);
ne2000_dma_update(s, 2);
} else {
/* 8 bit access */
ne2000_mem_writeb(s, s->rsar, val);
ne2000_dma_update(s, 1);
}
}
static uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr)
{
NE2000State *s = opaque;
int ret;
if (s->dcfg & 0x01) {
/* 16 bit access */
ret = ne2000_mem_readw(s, s->rsar);
ne2000_dma_update(s, 2);
} else {
/* 8 bit access */
ret = ne2000_mem_readb(s, s->rsar);
ne2000_dma_update(s, 1);
}
#ifdef DEBUG_NE2000
printf("NE2000: asic read val=0x%04x\n", ret);
#endif
return ret;
}
static void ne2000_asic_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
{
NE2000State *s = opaque;
#ifdef DEBUG_NE2000
printf("NE2000: asic writel val=0x%04x\n", val);
#endif
if (s->rcnt == 0)
return;
/* 32 bit access */
ne2000_mem_writel(s, s->rsar, val);
ne2000_dma_update(s, 4);
}
static uint32_t ne2000_asic_ioport_readl(void *opaque, uint32_t addr)
{
NE2000State *s = opaque;
int ret;
/* 32 bit access */
ret = ne2000_mem_readl(s, s->rsar);
ne2000_dma_update(s, 4);
#ifdef DEBUG_NE2000
printf("NE2000: asic readl val=0x%04x\n", ret);
#endif
return ret;
}
static void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
/* nothing to do (end of reset pulse) */
}
static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr)
{
NE2000State *s = opaque;
ne2000_reset(s);
return 0;
}
static void ne2000_save(QEMUFile* f,void* opaque)
{
NE2000State* s=(NE2000State*)opaque;
qemu_put_8s(f, &s->cmd);
qemu_put_be32s(f, &s->start);
qemu_put_be32s(f, &s->stop);
qemu_put_8s(f, &s->boundary);
qemu_put_8s(f, &s->tsr);
qemu_put_8s(f, &s->tpsr);
qemu_put_be16s(f, &s->tcnt);
qemu_put_be16s(f, &s->rcnt);
qemu_put_be32s(f, &s->rsar);
qemu_put_8s(f, &s->rsr);
qemu_put_8s(f, &s->isr);
qemu_put_8s(f, &s->dcfg);
qemu_put_8s(f, &s->imr);
qemu_put_buffer(f, s->phys, 6);
qemu_put_8s(f, &s->curpag);
qemu_put_buffer(f, s->mult, 8);
qemu_put_be32s(f, &s->irq);
qemu_put_buffer(f, s->mem, NE2000_MEM_SIZE);
}
static int ne2000_load(QEMUFile* f,void* opaque,int version_id)
{
NE2000State* s=(NE2000State*)opaque;
if (version_id != 1)
return -EINVAL;
qemu_get_8s(f, &s->cmd);
qemu_get_be32s(f, &s->start);
qemu_get_be32s(f, &s->stop);
qemu_get_8s(f, &s->boundary);
qemu_get_8s(f, &s->tsr);
qemu_get_8s(f, &s->tpsr);
qemu_get_be16s(f, &s->tcnt);
qemu_get_be16s(f, &s->rcnt);
qemu_get_be32s(f, &s->rsar);
qemu_get_8s(f, &s->rsr);
qemu_get_8s(f, &s->isr);
qemu_get_8s(f, &s->dcfg);
qemu_get_8s(f, &s->imr);
qemu_get_buffer(f, s->phys, 6);
qemu_get_8s(f, &s->curpag);
qemu_get_buffer(f, s->mult, 8);
qemu_get_be32s(f, &s->irq);
qemu_get_buffer(f, s->mem, NE2000_MEM_SIZE);
return 0;
}
void isa_ne2000_init(int base, int irq, NetDriverState *nd)
{
NE2000State *s;
s = qemu_mallocz(sizeof(NE2000State));
if (!s)
return;
register_ioport_write(base, 16, 1, ne2000_ioport_write, s);
register_ioport_read(base, 16, 1, ne2000_ioport_read, s);
register_ioport_write(base + 0x10, 1, 1, ne2000_asic_ioport_write, s);
register_ioport_read(base + 0x10, 1, 1, ne2000_asic_ioport_read, s);
register_ioport_write(base + 0x10, 2, 2, ne2000_asic_ioport_write, s);
register_ioport_read(base + 0x10, 2, 2, ne2000_asic_ioport_read, s);
register_ioport_write(base + 0x1f, 1, 1, ne2000_reset_ioport_write, s);
register_ioport_read(base + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
s->irq = irq;
s->nd = nd;
ne2000_reset(s);
qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s);
register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s);
}
/***********************************************************/
/* PCI NE2000 definitions */
typedef struct PCINE2000State {
PCIDevice dev;
NE2000State ne2000;
} PCINE2000State;
static void ne2000_map(PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type)
{
PCINE2000State *d = (PCINE2000State *)pci_dev;
NE2000State *s = &d->ne2000;
register_ioport_write(addr, 16, 1, ne2000_ioport_write, s);
register_ioport_read(addr, 16, 1, ne2000_ioport_read, s);
register_ioport_write(addr + 0x10, 1, 1, ne2000_asic_ioport_write, s);
register_ioport_read(addr + 0x10, 1, 1, ne2000_asic_ioport_read, s);
register_ioport_write(addr + 0x10, 2, 2, ne2000_asic_ioport_write, s);
register_ioport_read(addr + 0x10, 2, 2, ne2000_asic_ioport_read, s);
register_ioport_write(addr + 0x10, 4, 4, ne2000_asic_ioport_writel, s);
register_ioport_read(addr + 0x10, 4, 4, ne2000_asic_ioport_readl, s);
register_ioport_write(addr + 0x1f, 1, 1, ne2000_reset_ioport_write, s);
register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
}
void pci_ne2000_init(PCIBus *bus, NetDriverState *nd)
{
PCINE2000State *d;
NE2000State *s;
uint8_t *pci_conf;
d = (PCINE2000State *)pci_register_device(bus,
"NE2000", sizeof(PCINE2000State),
-1,
NULL, NULL);
pci_conf = d->dev.config;
pci_conf[0x00] = 0xec; // Realtek 8029
pci_conf[0x01] = 0x10;
pci_conf[0x02] = 0x29;
pci_conf[0x03] = 0x80;
pci_conf[0x0a] = 0x00; // ethernet network controller
pci_conf[0x0b] = 0x02;
pci_conf[0x0e] = 0x00; // header_type
pci_conf[0x3d] = 1; // interrupt pin 0
pci_register_io_region(&d->dev, 0, 0x100,
PCI_ADDRESS_SPACE_IO, ne2000_map);
s = &d->ne2000;
s->irq = 16; // PCI interrupt
s->pci_dev = (PCIDevice *)d;
s->nd = nd;
ne2000_reset(s);
qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s);
/* XXX: instance number ? */
register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s);
register_savevm("ne2000_pci", 0, 1, generic_pci_save, generic_pci_load,
&d->dev);
}
-1024
View File
File diff suppressed because it is too large. Load diff
-183
View File
@@ -1,183 +0,0 @@
/*
* QEMU Parallel PORT emulation
*
* Copyright (c) 2003-2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
//#define DEBUG_PARALLEL
/*
* These are the definitions for the Printer Status Register
*/
#define PARA_STS_BUSY 0x80 /* Busy complement */
#define PARA_STS_ACK 0x40 /* Acknowledge */
#define PARA_STS_PAPER 0x20 /* Out of paper */
#define PARA_STS_ONLINE 0x10 /* Online */
#define PARA_STS_ERROR 0x08 /* Error complement */
/*
* These are the definitions for the Printer Control Register
*/
#define PARA_CTR_INTEN 0x10 /* IRQ Enable */
#define PARA_CTR_SELECT 0x08 /* Select In complement */
#define PARA_CTR_INIT 0x04 /* Initialize Printer complement */
#define PARA_CTR_AUTOLF 0x02 /* Auto linefeed complement */
#define PARA_CTR_STROBE 0x01 /* Strobe complement */
struct ParallelState {
uint8_t data;
uint8_t status; /* read only register */
uint8_t control;
int irq;
int irq_pending;
CharDriverState *chr;
};
static void parallel_update_irq(ParallelState *s)
{
if (s->irq_pending)
pic_set_irq(s->irq, 1);
else
pic_set_irq(s->irq, 0);
}
static void parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
ParallelState *s = opaque;
addr &= 7;
#ifdef DEBUG_PARALLEL
printf("parallel: write addr=0x%02x val=0x%02x\n", addr, val);
#endif
switch(addr) {
case 0:
s->data = val;
parallel_update_irq(s);
break;
case 2:
if ((val & PARA_CTR_INIT) == 0 ) {
s->status = PARA_STS_BUSY;
s->status |= PARA_STS_ACK;
s->status |= PARA_STS_ONLINE;
s->status |= PARA_STS_ERROR;
}
else if (val & PARA_CTR_SELECT) {
if (val & PARA_CTR_STROBE) {
s->status &= ~PARA_STS_BUSY;
if ((s->control & PARA_CTR_STROBE) == 0)
qemu_chr_write(s->chr, &s->data, 1);
} else {
if (s->control & PARA_CTR_INTEN) {
s->irq_pending = 1;
}
}
}
parallel_update_irq(s);
s->control = val;
break;
}
}
static uint32_t parallel_ioport_read(void *opaque, uint32_t addr)
{
ParallelState *s = opaque;
uint32_t ret = 0xff;
addr &= 7;
switch(addr) {
case 0:
ret = s->data;
break;
case 1:
ret = s->status;
s->irq_pending = 0;
if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) {
/* XXX Fixme: wait 5 microseconds */
if (s->status & PARA_STS_ACK)
s->status &= ~PARA_STS_ACK;
else {
/* XXX Fixme: wait 5 microseconds */
s->status |= PARA_STS_ACK;
s->status |= PARA_STS_BUSY;
}
}
parallel_update_irq(s);
break;
case 2:
ret = s->control;
break;
}
#ifdef DEBUG_PARALLEL
printf("parallel: read addr=0x%02x val=0x%02x\n", addr, ret);
#endif
return ret;
}
static int parallel_can_receive(ParallelState *s)
{
return 0;
}
static void parallel_receive_byte(ParallelState *s, int ch)
{
}
static int parallel_can_receive1(void *opaque)
{
ParallelState *s = opaque;
return parallel_can_receive(s);
}
static void parallel_receive1(void *opaque, const uint8_t *buf, int size)
{
ParallelState *s = opaque;
parallel_receive_byte(s, buf[0]);
}
static void parallel_event(void *opaque, int event)
{
}
/* If fd is zero, it means that the parallel device uses the console */
ParallelState *parallel_init(int base, int irq, CharDriverState *chr)
{
ParallelState *s;
s = qemu_mallocz(sizeof(ParallelState));
if (!s)
return NULL;
s->irq = irq;
s->data = 0;
s->status = PARA_STS_BUSY;
s->status |= PARA_STS_ACK;
s->status |= PARA_STS_ONLINE;
s->status |= PARA_STS_ERROR;
s->control = PARA_CTR_SELECT;
s->control |= PARA_CTR_INIT;
register_ioport_write(base, 8, 1, parallel_ioport_write, s);
register_ioport_read(base, 8, 1, parallel_ioport_read, s);
s->chr = chr;
qemu_chr_add_read_handler(chr, parallel_can_receive1, parallel_receive1, s);
qemu_chr_add_event_handler(chr, parallel_event);
return s;
}
-634
View File
@@ -1,634 +0,0 @@
/*
* QEMU PC System Emulator
*
* Copyright (c) 2003-2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
/* output Bochs bios info messages */
//#define DEBUG_BIOS
#define BIOS_FILENAME "bios.bin"
#define VGABIOS_FILENAME "vgabios.bin"
#define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin"
#define LINUX_BOOT_FILENAME "linux_boot.bin"
#define KERNEL_LOAD_ADDR 0x00100000
#define INITRD_LOAD_ADDR 0x00400000
#define KERNEL_PARAMS_ADDR 0x00090000
#define KERNEL_CMDLINE_ADDR 0x00099000
int speaker_data_on;
int dummy_refresh_clock;
static fdctrl_t *floppy_controller;
static RTCState *rtc_state;
static PITState *pit;
static IOAPICState *ioapic;
static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
{
}
/* MSDOS compatibility mode FPU exception support */
/* XXX: add IGNNE support */
void cpu_set_ferr(CPUX86State *s)
{
pic_set_irq(13, 1);
}
static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data)
{
pic_set_irq(13, 0);
}
/* TSC handling */
uint64_t cpu_get_tsc(CPUX86State *env)
{
return qemu_get_clock(vm_clock);
}
/* IRQ handling */
int cpu_get_pic_interrupt(CPUState *env)
{
int intno;
intno = apic_get_interrupt(env);
if (intno >= 0) {
/* set irq request if a PIC irq is still pending */
/* XXX: improve that */
pic_update_irq(isa_pic);
return intno;
}
/* read the irq from the PIC */
intno = pic_read_irq(isa_pic);
return intno;
}
static void pic_irq_request(void *opaque, int level)
{
if (level)
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
else
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
/* PC cmos mappings */
#define REG_EQUIPMENT_BYTE 0x14
#define REG_IBM_CENTURY_BYTE 0x32
#define REG_IBM_PS2_CENTURY_BYTE 0x37
static inline int to_bcd(RTCState *s, int a)
{
return ((a / 10) << 4) | (a % 10);
}
static int cmos_get_fd_drive_type(int fd0)
{
int val;
switch (fd0) {
case 0:
/* 1.44 Mb 3"5 drive */
val = 4;
break;
case 1:
/* 2.88 Mb 3"5 drive */
val = 5;
break;
case 2:
/* 1.2 Mb 5"5 drive */
val = 2;
break;
default:
val = 0;
break;
}
return val;
}
static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd)
{
RTCState *s = rtc_state;
int cylinders, heads, sectors;
bdrv_get_geometry_hint(hd, &cylinders, &heads, &sectors);
rtc_set_memory(s, type_ofs, 47);
rtc_set_memory(s, info_ofs, cylinders);
rtc_set_memory(s, info_ofs + 1, cylinders >> 8);
rtc_set_memory(s, info_ofs + 2, heads);
rtc_set_memory(s, info_ofs + 3, 0xff);
rtc_set_memory(s, info_ofs + 4, 0xff);
rtc_set_memory(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3));
rtc_set_memory(s, info_ofs + 6, cylinders);
rtc_set_memory(s, info_ofs + 7, cylinders >> 8);
rtc_set_memory(s, info_ofs + 8, sectors);
}
/* hd_table must contain 4 block drivers */
static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table)
{
RTCState *s = rtc_state;
int val;
int fd0, fd1, nb;
time_t ti;
struct tm *tm;
int i;
/* set the CMOS date */
time(&ti);
if (rtc_utc)
tm = gmtime(&ti);
else
tm = localtime(&ti);
rtc_set_date(s, tm);
val = to_bcd(s, (tm->tm_year / 100) + 19);
rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val);
rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val);
/* various important CMOS locations needed by PC/Bochs bios */
/* memory size */
val = 640; /* base memory in K */
rtc_set_memory(s, 0x15, val);
rtc_set_memory(s, 0x16, val >> 8);
val = (ram_size / 1024) - 1024;
if (val > 65535)
val = 65535;
rtc_set_memory(s, 0x17, val);
rtc_set_memory(s, 0x18, val >> 8);
rtc_set_memory(s, 0x30, val);
rtc_set_memory(s, 0x31, val >> 8);
if (ram_size > (16 * 1024 * 1024))
val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536);
else
val = 0;
if (val > 65535)
val = 65535;
rtc_set_memory(s, 0x34, val);
rtc_set_memory(s, 0x35, val >> 8);
switch(boot_device) {
case 'a':
case 'b':
rtc_set_memory(s, 0x3d, 0x01); /* floppy boot */
break;
default:
case 'c':
rtc_set_memory(s, 0x3d, 0x02); /* hard drive boot */
break;
case 'd':
rtc_set_memory(s, 0x3d, 0x03); /* CD-ROM boot */
break;
}
/* floppy type */
fd0 = fdctrl_get_drive_type(floppy_controller, 0);
fd1 = fdctrl_get_drive_type(floppy_controller, 1);
val = (cmos_get_fd_drive_type(fd0) << 4) | cmos_get_fd_drive_type(fd1);
rtc_set_memory(s, 0x10, val);
val = 0;
nb = 0;
if (fd0 < 3)
nb++;
if (fd1 < 3)
nb++;
switch (nb) {
case 0:
break;
case 1:
val |= 0x01; /* 1 drive, ready for boot */
break;
case 2:
val |= 0x41; /* 2 drives, ready for boot */
break;
}
val |= 0x02; /* FPU is there */
val |= 0x04; /* PS/2 mouse installed */
rtc_set_memory(s, REG_EQUIPMENT_BYTE, val);
/* hard drives */
rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0));
if (hd_table[0])
cmos_init_hd(0x19, 0x1b, hd_table[0]);
if (hd_table[1])
cmos_init_hd(0x1a, 0x24, hd_table[1]);
val = 0;
for (i = 0; i < 4; i++) {
if (hd_table[i]) {
int cylinders, heads, sectors, translation;
/* NOTE: bdrv_get_geometry_hint() returns the physical
geometry. It is always such that: 1 <= sects <= 63, 1
<= heads <= 16, 1 <= cylinders <= 16383. The BIOS
geometry can be different if a translation is done. */
translation = bdrv_get_translation_hint(hd_table[i]);
if (translation == BIOS_ATA_TRANSLATION_AUTO) {
bdrv_get_geometry_hint(hd_table[i], &cylinders, &heads, &sectors);
if (cylinders <= 1024 && heads <= 16 && sectors <= 63) {
/* No translation. */
translation = 0;
} else {
/* LBA translation. */
translation = 1;
}
} else {
translation--;
}
val |= translation << (i * 2);
}
}
rtc_set_memory(s, 0x39, val);
/* Disable check of 0x55AA signature on the last two bytes of
first sector of disk. XXX: make it the default ? */
// rtc_set_memory(s, 0x38, 1);
}
static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
speaker_data_on = (val >> 1) & 1;
pit_set_gate(pit, 2, val & 1);
}
static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
{
int out;
out = pit_get_out(pit, 2, qemu_get_clock(vm_clock));
dummy_refresh_clock ^= 1;
return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) |
(dummy_refresh_clock << 4);
}
static void ioport92_write(void *opaque, uint32_t addr, uint32_t val)
{
cpu_x86_set_a20(cpu_single_env, (val >> 1) & 1);
/* XXX: bit 0 is fast reset */
}
static uint32_t ioport92_read(void *opaque, uint32_t addr)
{
return ((cpu_single_env->a20_mask >> 20) & 1) << 1;
}
/***********************************************************/
/* Bochs BIOS debug ports */
void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val)
{
static const char shutdown_str[8] = "Shutdown";
static int shutdown_index = 0;
switch(addr) {
/* Bochs BIOS messages */
case 0x400:
case 0x401:
fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val);
exit(1);
case 0x402:
case 0x403:
#ifdef DEBUG_BIOS
fprintf(stderr, "%c", val);
#endif
break;
case 0x8900:
/* same as Bochs power off */
if (val == shutdown_str[shutdown_index]) {
shutdown_index++;
if (shutdown_index == 8) {
shutdown_index = 0;
qemu_system_shutdown_request();
}
} else {
shutdown_index = 0;
}
break;
/* LGPL'ed VGA BIOS messages */
case 0x501:
case 0x502:
fprintf(stderr, "VGA BIOS panic, line %d\n", val);
exit(1);
case 0x500:
case 0x503:
#ifdef DEBUG_BIOS
fprintf(stderr, "%c", val);
#endif
break;
}
}
void bochs_bios_init(void)
{
register_ioport_write(0x400, 1, 2, bochs_bios_write, NULL);
register_ioport_write(0x401, 1, 2, bochs_bios_write, NULL);
register_ioport_write(0x402, 1, 1, bochs_bios_write, NULL);
register_ioport_write(0x403, 1, 1, bochs_bios_write, NULL);
register_ioport_write(0x8900, 1, 1, bochs_bios_write, NULL);
register_ioport_write(0x501, 1, 2, bochs_bios_write, NULL);
register_ioport_write(0x502, 1, 2, bochs_bios_write, NULL);
register_ioport_write(0x500, 1, 1, bochs_bios_write, NULL);
register_ioport_write(0x503, 1, 1, bochs_bios_write, NULL);
}
int load_kernel(const char *filename, uint8_t *addr,
uint8_t *real_addr)
{
int fd, size;
int setup_sects;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
return -1;
/* load 16 bit code */
if (read(fd, real_addr, 512) != 512)
goto fail;
setup_sects = real_addr[0x1F1];
if (!setup_sects)
setup_sects = 4;
if (read(fd, real_addr + 512, setup_sects * 512) !=
setup_sects * 512)
goto fail;
/* load 32 bit code */
size = read(fd, addr, 16 * 1024 * 1024);
if (size < 0)
goto fail;
close(fd);
return size;
fail:
close(fd);
return -1;
}
static const int ide_iobase[2] = { 0x1f0, 0x170 };
static const int ide_iobase2[2] = { 0x3f6, 0x376 };
static const int ide_irq[2] = { 14, 15 };
#define NE2000_NB_MAX 6
static int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };
static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };
static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
/* PC hardware initialisation */
static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
char buf[1024];
int ret, linux_boot, initrd_size, i, nb_nics1;
unsigned long bios_offset, vga_bios_offset;
int bios_size, isa_bios_size;
PCIBus *pci_bus;
linux_boot = (kernel_filename != NULL);
/* allocate RAM */
cpu_register_physical_memory(0, ram_size, 0);
/* BIOS load */
bios_offset = ram_size + vga_ram_size;
vga_bios_offset = bios_offset + 256 * 1024;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
bios_size = get_image_size(buf);
if (bios_size <= 0 ||
(bios_size % 65536) != 0 ||
bios_size > (256 * 1024)) {
goto bios_error;
}
ret = load_image(buf, phys_ram_base + bios_offset);
if (ret != bios_size) {
bios_error:
fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf);
exit(1);
}
/* VGA BIOS load */
if (cirrus_vga_enabled) {
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_CIRRUS_FILENAME);
} else {
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
}
ret = load_image(buf, phys_ram_base + vga_bios_offset);
/* setup basic memory access */
cpu_register_physical_memory(0xc0000, 0x10000,
vga_bios_offset | IO_MEM_ROM);
/* map the last 128KB of the BIOS in ISA space */
isa_bios_size = bios_size;
if (isa_bios_size > (128 * 1024))
isa_bios_size = 128 * 1024;
cpu_register_physical_memory(0xd0000, (192 * 1024) - isa_bios_size,
IO_MEM_UNASSIGNED);
cpu_register_physical_memory(0x100000 - isa_bios_size,
isa_bios_size,
(bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM);
/* map all the bios at the top of memory */
cpu_register_physical_memory((uint32_t)(-bios_size),
bios_size, bios_offset | IO_MEM_ROM);
bochs_bios_init();
if (linux_boot) {
uint8_t bootsect[512];
uint8_t old_bootsect[512];
if (bs_table[0] == NULL) {
fprintf(stderr, "A disk image must be given for 'hda' when booting a Linux kernel\n");
exit(1);
}
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, LINUX_BOOT_FILENAME);
ret = load_image(buf, bootsect);
if (ret != sizeof(bootsect)) {
fprintf(stderr, "qemu: could not load linux boot sector '%s'\n",
buf);
exit(1);
}
if (bdrv_read(bs_table[0], 0, old_bootsect, 1) >= 0) {
/* copy the MSDOS partition table */
memcpy(bootsect + 0x1be, old_bootsect + 0x1be, 0x40);
}
bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect));
/* now we can load the kernel */
ret = load_kernel(kernel_filename,
phys_ram_base + KERNEL_LOAD_ADDR,
phys_ram_base + KERNEL_PARAMS_ADDR);
if (ret < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
kernel_filename);
exit(1);
}
/* load initrd */
initrd_size = 0;
if (initrd_filename) {
initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR);
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
exit(1);
}
}
if (initrd_size > 0) {
stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, INITRD_LOAD_ADDR);
stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x21c, initrd_size);
}
pstrcpy(phys_ram_base + KERNEL_CMDLINE_ADDR, 4096,
kernel_cmdline);
stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x20, 0xA33F);
stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x22,
KERNEL_CMDLINE_ADDR - KERNEL_PARAMS_ADDR);
/* loader type */
stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01);
}
if (pci_enabled) {
pci_bus = i440fx_init();
piix3_init(pci_bus);
} else {
pci_bus = NULL;
}
/* init basic PC hardware */
register_ioport_write(0x80, 1, 1, ioport80_write, NULL);
register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
if (cirrus_vga_enabled) {
if (pci_enabled) {
pci_cirrus_vga_init(pci_bus,
ds, phys_ram_base + ram_size, ram_size,
vga_ram_size);
} else {
isa_cirrus_vga_init(ds, phys_ram_base + ram_size, ram_size,
vga_ram_size);
}
} else {
vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
vga_ram_size, 0, 0);
}
rtc_state = rtc_init(0x70, 8);
register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL);
register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL);
register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
if (pci_enabled) {
apic_init(cpu_single_env);
ioapic = ioapic_init();
}
isa_pic = pic_init(pic_irq_request, cpu_single_env);
pit = pit_init(0x40, 0);
if (pci_enabled) {
pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic);
}
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
if (serial_hds[i]) {
serial_init(serial_io[i], serial_irq[i], serial_hds[i]);
}
}
for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
if (parallel_hds[i]) {
parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]);
}
}
if (pci_enabled) {
for(i = 0; i < nb_nics; i++) {
pci_ne2000_init(pci_bus, &nd_table[i]);
}
pci_piix3_ide_init(pci_bus, bs_table);
} else {
nb_nics1 = nb_nics;
if (nb_nics1 > NE2000_NB_MAX)
nb_nics1 = NE2000_NB_MAX;
for(i = 0; i < nb_nics1; i++) {
isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]);
}
for(i = 0; i < 2; i++) {
isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
bs_table[2 * i], bs_table[2 * i + 1]);
}
}
kbd_init();
DMA_init(0);
if (audio_enabled) {
AUD_init();
#ifdef USE_SB16
if (sb16_enabled)
SB16_init ();
#endif
#ifdef CONFIG_ADLIB
if (adlib_enabled)
Adlib_init ();
#endif
#ifdef USE_GUS
if (gus_enabled)
GUS_init ();
#endif
}
floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table);
cmos_init(ram_size, boot_device, bs_table);
/* must be done after all PCI devices are instanciated */
/* XXX: should be done in the Bochs BIOS */
if (pci_enabled) {
pci_bios_init();
}
}
QEMUMachine pc_machine = {
"pc",
"Standard PC",
pc_init1,
};
-1839
View File
File diff suppressed because it is too large. Load diff
-705
View File
@@ -1,705 +0,0 @@
/*
* QEMU PC keyboard emulation
*
* Copyright (c) 2003 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
/* debug PC keyboard */
//#define DEBUG_KBD
/* debug PC keyboard : only mouse */
//#define DEBUG_MOUSE
/* Keyboard Controller Commands */
#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */
#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */
#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */
#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */
#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */
#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */
#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */
#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */
#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */
#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */
#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */
#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */
#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */
#define KBD_CCMD_WRITE_OBUF 0xD2
#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if
initiated by the auxiliary device */
#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */
#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */
#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */
#define KBD_CCMD_RESET 0xFE
/* Keyboard Commands */
#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
#define KBD_CMD_ECHO 0xEE
#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */
#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */
#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */
#define KBD_CMD_RESET 0xFF /* Reset */
/* Keyboard Replies */
#define KBD_REPLY_POR 0xAA /* Power on reset */
#define KBD_REPLY_ACK 0xFA /* Command ACK */
#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
/* Status Register Bits */
#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */
#define KBD_STAT_SELFTEST 0x04 /* Self test successful */
#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */
#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */
#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */
#define KBD_STAT_PERR 0x80 /* Parity error */
/* Controller Mode Register Bits */
#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */
#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */
#define KBD_MODE_SYS 0x04 /* The system flag (?) */
#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */
#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */
#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */
#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */
#define KBD_MODE_RFU 0x80
/* Mouse Commands */
#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
#define AUX_SET_RES 0xE8 /* Set resolution */
#define AUX_GET_SCALE 0xE9 /* Get scaling factor */
#define AUX_SET_STREAM 0xEA /* Set stream mode */
#define AUX_POLL 0xEB /* Poll */
#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
#define AUX_SET_WRAP 0xEE /* Set wrap mode */
#define AUX_SET_REMOTE 0xF0 /* Set remote mode */
#define AUX_GET_TYPE 0xF2 /* Get type */
#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
#define AUX_SET_DEFAULT 0xF6
#define AUX_RESET 0xFF /* Reset aux device */
#define AUX_ACK 0xFA /* Command byte ACK. */
#define MOUSE_STATUS_REMOTE 0x40
#define MOUSE_STATUS_ENABLED 0x20
#define MOUSE_STATUS_SCALE21 0x10
#define KBD_QUEUE_SIZE 256
typedef struct {
uint8_t aux[KBD_QUEUE_SIZE];
uint8_t data[KBD_QUEUE_SIZE];
int rptr, wptr, count;
} KBDQueue;
typedef struct KBDState {
KBDQueue queue;
uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
uint8_t status;
uint8_t mode;
/* keyboard state */
int kbd_write_cmd;
int scan_enabled;
/* mouse state */
int mouse_write_cmd;
uint8_t mouse_status;
uint8_t mouse_resolution;
uint8_t mouse_sample_rate;
uint8_t mouse_wrap;
uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
uint8_t mouse_detect_state;
int mouse_dx; /* current values, needed for 'poll' mode */
int mouse_dy;
int mouse_dz;
uint8_t mouse_buttons;
} KBDState;
KBDState kbd_state;
/* update irq and KBD_STAT_[MOUSE_]OBF */
/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
incorrect, but it avoids having to simulate exact delays */
static void kbd_update_irq(KBDState *s)
{
KBDQueue *q = &s->queue;
int irq12_level, irq1_level;
irq1_level = 0;
irq12_level = 0;
s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
if (q->count != 0) {
s->status |= KBD_STAT_OBF;
if (q->aux[q->rptr]) {
s->status |= KBD_STAT_MOUSE_OBF;
if (s->mode & KBD_MODE_MOUSE_INT)
irq12_level = 1;
} else {
if ((s->mode & KBD_MODE_KBD_INT) &&
!(s->mode & KBD_MODE_DISABLE_KBD))
irq1_level = 1;
}
}
pic_set_irq(1, irq1_level);
pic_set_irq(12, irq12_level);
}
static void kbd_queue(KBDState *s, int b, int aux)
{
KBDQueue *q = &s->queue;
#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD)
if (aux)
printf("mouse event: 0x%02x\n", b);
#ifdef DEBUG_KBD
else
printf("kbd event: 0x%02x\n", b);
#endif
#endif
if (q->count >= KBD_QUEUE_SIZE)
return;
q->aux[q->wptr] = aux;
q->data[q->wptr] = b;
if (++q->wptr == KBD_QUEUE_SIZE)
q->wptr = 0;
q->count++;
kbd_update_irq(s);
}
static void pc_kbd_put_keycode(void *opaque, int keycode)
{
KBDState *s = opaque;
kbd_queue(s, keycode, 0);
}
static uint32_t kbd_read_status(void *opaque, uint32_t addr)
{
KBDState *s = opaque;
int val;
val = s->status;
#if defined(DEBUG_KBD)
printf("kbd: read status=0x%02x\n", val);
#endif
return val;
}
static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
{
KBDState *s = opaque;
#ifdef DEBUG_KBD
printf("kbd: write cmd=0x%02x\n", val);
#endif
switch(val) {
case KBD_CCMD_READ_MODE:
kbd_queue(s, s->mode, 0);
break;
case KBD_CCMD_WRITE_MODE:
case KBD_CCMD_WRITE_OBUF:
case KBD_CCMD_WRITE_AUX_OBUF:
case KBD_CCMD_WRITE_MOUSE:
case KBD_CCMD_WRITE_OUTPORT:
s->write_cmd = val;
break;
case KBD_CCMD_MOUSE_DISABLE:
s->mode |= KBD_MODE_DISABLE_MOUSE;
break;
case KBD_CCMD_MOUSE_ENABLE:
s->mode &= ~KBD_MODE_DISABLE_MOUSE;
break;
case KBD_CCMD_TEST_MOUSE:
kbd_queue(s, 0x00, 0);
break;
case KBD_CCMD_SELF_TEST:
s->status |= KBD_STAT_SELFTEST;
kbd_queue(s, 0x55, 0);
break;
case KBD_CCMD_KBD_TEST:
kbd_queue(s, 0x00, 0);
break;
case KBD_CCMD_KBD_DISABLE:
s->mode |= KBD_MODE_DISABLE_KBD;
kbd_update_irq(s);
break;
case KBD_CCMD_KBD_ENABLE:
s->mode &= ~KBD_MODE_DISABLE_KBD;
kbd_update_irq(s);
break;
case KBD_CCMD_READ_INPORT:
kbd_queue(s, 0x00, 0);
break;
case KBD_CCMD_READ_OUTPORT:
/* XXX: check that */
#ifdef TARGET_I386
val = 0x01 | (((cpu_single_env->a20_mask >> 20) & 1) << 1);
#else
val = 0x01;
#endif
if (s->status & KBD_STAT_OBF)
val |= 0x10;
if (s->status & KBD_STAT_MOUSE_OBF)
val |= 0x20;
kbd_queue(s, val, 0);
break;
#ifdef TARGET_I386
case KBD_CCMD_ENABLE_A20:
cpu_x86_set_a20(cpu_single_env, 1);
break;
case KBD_CCMD_DISABLE_A20:
cpu_x86_set_a20(cpu_single_env, 0);
break;
#endif
case KBD_CCMD_RESET:
qemu_system_reset_request();
break;
case 0xff:
/* ignore that - I don't know what is its use */
break;
default:
fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val);
break;
}
}
static uint32_t kbd_read_data(void *opaque, uint32_t addr)
{
KBDState *s = opaque;
KBDQueue *q;
int val, index, aux;
q = &s->queue;
if (q->count == 0) {
/* NOTE: if no data left, we return the last keyboard one
(needed for EMM386) */
/* XXX: need a timer to do things correctly */
index = q->rptr - 1;
if (index < 0)
index = KBD_QUEUE_SIZE - 1;
val = q->data[index];
} else {
aux = q->aux[q->rptr];
val = q->data[q->rptr];
if (++q->rptr == KBD_QUEUE_SIZE)
q->rptr = 0;
q->count--;
/* reading deasserts IRQ */
if (aux)
pic_set_irq(12, 0);
else
pic_set_irq(1, 0);
}
/* reassert IRQs if data left */
kbd_update_irq(s);
#ifdef DEBUG_KBD
printf("kbd: read data=0x%02x\n", val);
#endif
return val;
}
static void kbd_reset_keyboard(KBDState *s)
{
s->scan_enabled = 1;
}
static void kbd_write_keyboard(KBDState *s, int val)
{
switch(s->kbd_write_cmd) {
default:
case -1:
switch(val) {
case 0x00:
kbd_queue(s, KBD_REPLY_ACK, 0);
break;
case 0x05:
kbd_queue(s, KBD_REPLY_RESEND, 0);
break;
case KBD_CMD_GET_ID:
kbd_queue(s, KBD_REPLY_ACK, 0);
kbd_queue(s, 0xab, 0);
kbd_queue(s, 0x83, 0);
break;
case KBD_CMD_ECHO:
kbd_queue(s, KBD_CMD_ECHO, 0);
break;
case KBD_CMD_ENABLE:
s->scan_enabled = 1;
kbd_queue(s, KBD_REPLY_ACK, 0);
break;
case KBD_CMD_SET_LEDS:
case KBD_CMD_SET_RATE:
s->kbd_write_cmd = val;
kbd_queue(s, KBD_REPLY_ACK, 0);
break;
case KBD_CMD_RESET_DISABLE:
kbd_reset_keyboard(s);
s->scan_enabled = 0;
kbd_queue(s, KBD_REPLY_ACK, 0);
break;
case KBD_CMD_RESET_ENABLE:
kbd_reset_keyboard(s);
s->scan_enabled = 1;
kbd_queue(s, KBD_REPLY_ACK, 0);
break;
case KBD_CMD_RESET:
kbd_reset_keyboard(s);
kbd_queue(s, KBD_REPLY_ACK, 0);
kbd_queue(s, KBD_REPLY_POR, 0);
break;
default:
kbd_queue(s, KBD_REPLY_ACK, 0);
break;
}
break;
case KBD_CMD_SET_LEDS:
kbd_queue(s, KBD_REPLY_ACK, 0);
s->kbd_write_cmd = -1;
break;
case KBD_CMD_SET_RATE:
kbd_queue(s, KBD_REPLY_ACK, 0);
s->kbd_write_cmd = -1;
break;
}
}
static void kbd_mouse_send_packet(KBDState *s)
{
unsigned int b;
int dx1, dy1, dz1;
dx1 = s->mouse_dx;
dy1 = s->mouse_dy;
dz1 = s->mouse_dz;
/* XXX: increase range to 8 bits ? */
if (dx1 > 127)
dx1 = 127;
else if (dx1 < -127)
dx1 = -127;
if (dy1 > 127)
dy1 = 127;
else if (dy1 < -127)
dy1 = -127;
b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
kbd_queue(s, b, 1);
kbd_queue(s, dx1 & 0xff, 1);
kbd_queue(s, dy1 & 0xff, 1);
/* extra byte for IMPS/2 or IMEX */
switch(s->mouse_type) {
default:
break;
case 3:
if (dz1 > 127)
dz1 = 127;
else if (dz1 < -127)
dz1 = -127;
kbd_queue(s, dz1 & 0xff, 1);
break;
case 4:
if (dz1 > 7)
dz1 = 7;
else if (dz1 < -7)
dz1 = -7;
b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
kbd_queue(s, b, 1);
break;
}
/* update deltas */
s->mouse_dx -= dx1;
s->mouse_dy -= dy1;
s->mouse_dz -= dz1;
}
static void pc_kbd_mouse_event(void *opaque,
int dx, int dy, int dz, int buttons_state)
{
KBDState *s = opaque;
/* check if deltas are recorded when disabled */
if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
return;
s->mouse_dx += dx;
s->mouse_dy -= dy;
s->mouse_dz += dz;
/* XXX: SDL sometimes generates nul events: we delete them */
if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
s->mouse_buttons == buttons_state)
return;
s->mouse_buttons = buttons_state;
if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
(s->queue.count < (KBD_QUEUE_SIZE - 16))) {
for(;;) {
/* if not remote, send event. Multiple events are sent if
too big deltas */
kbd_mouse_send_packet(s);
if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
break;
}
}
}
static void kbd_write_mouse(KBDState *s, int val)
{
#ifdef DEBUG_MOUSE
printf("kbd: write mouse 0x%02x\n", val);
#endif
switch(s->mouse_write_cmd) {
default:
case -1:
/* mouse command */
if (s->mouse_wrap) {
if (val == AUX_RESET_WRAP) {
s->mouse_wrap = 0;
kbd_queue(s, AUX_ACK, 1);
return;
} else if (val != AUX_RESET) {
kbd_queue(s, val, 1);
return;
}
}
switch(val) {
case AUX_SET_SCALE11:
s->mouse_status &= ~MOUSE_STATUS_SCALE21;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_SET_SCALE21:
s->mouse_status |= MOUSE_STATUS_SCALE21;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_SET_STREAM:
s->mouse_status &= ~MOUSE_STATUS_REMOTE;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_SET_WRAP:
s->mouse_wrap = 1;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_SET_REMOTE:
s->mouse_status |= MOUSE_STATUS_REMOTE;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_GET_TYPE:
kbd_queue(s, AUX_ACK, 1);
kbd_queue(s, s->mouse_type, 1);
break;
case AUX_SET_RES:
case AUX_SET_SAMPLE:
s->mouse_write_cmd = val;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_GET_SCALE:
kbd_queue(s, AUX_ACK, 1);
kbd_queue(s, s->mouse_status, 1);
kbd_queue(s, s->mouse_resolution, 1);
kbd_queue(s, s->mouse_sample_rate, 1);
break;
case AUX_POLL:
kbd_queue(s, AUX_ACK, 1);
kbd_mouse_send_packet(s);
break;
case AUX_ENABLE_DEV:
s->mouse_status |= MOUSE_STATUS_ENABLED;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_DISABLE_DEV:
s->mouse_status &= ~MOUSE_STATUS_ENABLED;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_SET_DEFAULT:
s->mouse_sample_rate = 100;
s->mouse_resolution = 2;
s->mouse_status = 0;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_RESET:
s->mouse_sample_rate = 100;
s->mouse_resolution = 2;
s->mouse_status = 0;
s->mouse_type = 0;
kbd_queue(s, AUX_ACK, 1);
kbd_queue(s, 0xaa, 1);
kbd_queue(s, s->mouse_type, 1);
break;
default:
break;
}
break;
case AUX_SET_SAMPLE:
s->mouse_sample_rate = val;
/* detect IMPS/2 or IMEX */
switch(s->mouse_detect_state) {
default:
case 0:
if (val == 200)
s->mouse_detect_state = 1;
break;
case 1:
if (val == 100)
s->mouse_detect_state = 2;
else if (val == 200)
s->mouse_detect_state = 3;
else
s->mouse_detect_state = 0;
break;
case 2:
if (val == 80)
s->mouse_type = 3; /* IMPS/2 */
s->mouse_detect_state = 0;
break;
case 3:
if (val == 80)
s->mouse_type = 4; /* IMEX */
s->mouse_detect_state = 0;
break;
}
kbd_queue(s, AUX_ACK, 1);
s->mouse_write_cmd = -1;
break;
case AUX_SET_RES:
s->mouse_resolution = val;
kbd_queue(s, AUX_ACK, 1);
s->mouse_write_cmd = -1;
break;
}
}
void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
{
KBDState *s = opaque;
#ifdef DEBUG_KBD
printf("kbd: write data=0x%02x\n", val);
#endif
switch(s->write_cmd) {
case 0:
kbd_write_keyboard(s, val);
break;
case KBD_CCMD_WRITE_MODE:
s->mode = val;
kbd_update_irq(s);
break;
case KBD_CCMD_WRITE_OBUF:
kbd_queue(s, val, 0);
break;
case KBD_CCMD_WRITE_AUX_OBUF:
kbd_queue(s, val, 1);
break;
case KBD_CCMD_WRITE_OUTPORT:
#ifdef TARGET_I386
cpu_x86_set_a20(cpu_single_env, (val >> 1) & 1);
#endif
if (!(val & 1)) {
qemu_system_reset_request();
}
break;
case KBD_CCMD_WRITE_MOUSE:
kbd_write_mouse(s, val);
break;
default:
break;
}
s->write_cmd = 0;
}
static void kbd_reset(void *opaque)
{
KBDState *s = opaque;
KBDQueue *q;
s->kbd_write_cmd = -1;
s->mouse_write_cmd = -1;
s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
q = &s->queue;
q->rptr = 0;
q->wptr = 0;
q->count = 0;
}
static void kbd_save(QEMUFile* f, void* opaque)
{
KBDState *s = (KBDState*)opaque;
qemu_put_8s(f, &s->write_cmd);
qemu_put_8s(f, &s->status);
qemu_put_8s(f, &s->mode);
qemu_put_be32s(f, &s->kbd_write_cmd);
qemu_put_be32s(f, &s->scan_enabled);
qemu_put_be32s(f, &s->mouse_write_cmd);
qemu_put_8s(f, &s->mouse_status);
qemu_put_8s(f, &s->mouse_resolution);
qemu_put_8s(f, &s->mouse_sample_rate);
qemu_put_8s(f, &s->mouse_wrap);
qemu_put_8s(f, &s->mouse_type);
qemu_put_8s(f, &s->mouse_detect_state);
qemu_put_be32s(f, &s->mouse_dx);
qemu_put_be32s(f, &s->mouse_dy);
qemu_put_be32s(f, &s->mouse_dz);
qemu_put_8s(f, &s->mouse_buttons);
}
static int kbd_load(QEMUFile* f, void* opaque, int version_id)
{
KBDState *s = (KBDState*)opaque;
if (version_id != 1)
return -EINVAL;
qemu_get_8s(f, &s->write_cmd);
qemu_get_8s(f, &s->status);
qemu_get_8s(f, &s->mode);
qemu_get_be32s(f, &s->kbd_write_cmd);
qemu_get_be32s(f, &s->scan_enabled);
qemu_get_be32s(f, &s->mouse_write_cmd);
qemu_get_8s(f, &s->mouse_status);
qemu_get_8s(f, &s->mouse_resolution);
qemu_get_8s(f, &s->mouse_sample_rate);
qemu_get_8s(f, &s->mouse_wrap);
qemu_get_8s(f, &s->mouse_type);
qemu_get_8s(f, &s->mouse_detect_state);
qemu_get_be32s(f, &s->mouse_dx);
qemu_get_be32s(f, &s->mouse_dy);
qemu_get_be32s(f, &s->mouse_dz);
qemu_get_8s(f, &s->mouse_buttons);
return 0;
}
void kbd_init(void)
{
KBDState *s = &kbd_state;
kbd_reset(s);
register_savevm("pckbd", 0, 1, kbd_save, kbd_load, s);
register_ioport_read(0x60, 1, 1, kbd_read_data, s);
register_ioport_write(0x60, 1, 1, kbd_write_data, s);
register_ioport_read(0x64, 1, 1, kbd_read_status, s);
register_ioport_write(0x64, 1, 1, kbd_write_command, s);
qemu_add_kbd_event_handler(pc_kbd_put_keycode, s);
qemu_add_mouse_event_handler(pc_kbd_mouse_event, s);
qemu_register_reset(kbd_reset, s);
}
-446
View File
@@ -1,446 +0,0 @@
/*
* QEMU generic PPC hardware System Emulator
*
* Copyright (c) 2003-2004 Jocelyn Mayer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "m48t59.h"
/*****************************************************************************/
/* PPC time base and decrementer emulation */
//#define DEBUG_TB
struct ppc_tb_t {
/* Time base management */
int64_t tb_offset; /* Compensation */
uint32_t tb_freq; /* TB frequency */
/* Decrementer management */
uint64_t decr_next; /* Tick for next decr interrupt */
struct QEMUTimer *decr_timer;
};
static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env)
{
/* TB time in tb periods */
return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset,
tb_env->tb_freq, ticks_per_sec);
}
uint32_t cpu_ppc_load_tbl (CPUState *env)
{
ppc_tb_t *tb_env = env->tb_env;
uint64_t tb;
tb = cpu_ppc_get_tb(tb_env);
#ifdef DEBUG_TB
{
static int last_time;
int now;
now = time(NULL);
if (last_time != now) {
last_time = now;
printf("%s: tb=0x%016lx %d %08lx\n",
__func__, tb, now, tb_env->tb_offset);
}
}
#endif
return tb & 0xFFFFFFFF;
}
uint32_t cpu_ppc_load_tbu (CPUState *env)
{
ppc_tb_t *tb_env = env->tb_env;
uint64_t tb;
tb = cpu_ppc_get_tb(tb_env);
#ifdef DEBUG_TB
printf("%s: tb=0x%016lx\n", __func__, tb);
#endif
return tb >> 32;
}
static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value)
{
tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq)
- qemu_get_clock(vm_clock);
#ifdef DEBUG_TB
printf("%s: tb=0x%016lx offset=%08x\n", __func__, value);
#endif
}
void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
{
ppc_tb_t *tb_env = env->tb_env;
cpu_ppc_store_tb(tb_env,
((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
}
void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
{
ppc_tb_t *tb_env = env->tb_env;
cpu_ppc_store_tb(tb_env,
((uint64_t)cpu_ppc_load_tbu(env) << 32) | value);
}
uint32_t cpu_ppc_load_decr (CPUState *env)
{
ppc_tb_t *tb_env = env->tb_env;
uint32_t decr;
int64_t diff;
diff = tb_env->decr_next - qemu_get_clock(vm_clock);
if (diff >= 0)
decr = muldiv64(diff, tb_env->tb_freq, ticks_per_sec);
else
decr = -muldiv64(-diff, tb_env->tb_freq, ticks_per_sec);
#if defined(DEBUG_TB)
printf("%s: 0x%08x\n", __func__, decr);
#endif
return decr;
}
/* When decrementer expires,
* all we need to do is generate or queue a CPU exception
*/
static inline void cpu_ppc_decr_excp (CPUState *env)
{
/* Raise it */
#ifdef DEBUG_TB
printf("raise decrementer exception\n");
#endif
cpu_interrupt(env, CPU_INTERRUPT_TIMER);
}
static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
uint32_t value, int is_excp)
{
ppc_tb_t *tb_env = env->tb_env;
uint64_t now, next;
#ifdef DEBUG_TB
printf("%s: 0x%08x => 0x%08x\n", __func__, decr, value);
#endif
now = qemu_get_clock(vm_clock);
next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq);
if (is_excp)
next += tb_env->decr_next - now;
if (next == now)
next++;
tb_env->decr_next = next;
/* Adjust timer */
qemu_mod_timer(tb_env->decr_timer, next);
/* If we set a negative value and the decrementer was positive,
* raise an exception.
*/
if ((value & 0x80000000) && !(decr & 0x80000000))
cpu_ppc_decr_excp(env);
}
void cpu_ppc_store_decr (CPUState *env, uint32_t value)
{
_cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0);
}
static void cpu_ppc_decr_cb (void *opaque)
{
_cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1);
}
/* Set up (once) timebase frequency (in Hz) */
ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq)
{
ppc_tb_t *tb_env;
tb_env = qemu_mallocz(sizeof(ppc_tb_t));
if (tb_env == NULL)
return NULL;
env->tb_env = tb_env;
if (tb_env->tb_freq == 0 || 1) {
tb_env->tb_freq = freq;
/* Create new timer */
tb_env->decr_timer =
qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
/* There is a bug in 2.4 kernels:
* if a decrementer exception is pending when it enables msr_ee,
* it's not ready to handle it...
*/
_cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
}
return tb_env;
}
#if 0
/*****************************************************************************/
/* Handle system reset (for now, just stop emulation) */
void cpu_ppc_reset (CPUState *env)
{
printf("Reset asked... Stop emulation\n");
abort();
}
#endif
static void PPC_io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
cpu_outb(NULL, addr & 0xffff, value);
}
static uint32_t PPC_io_readb (void *opaque, target_phys_addr_t addr)
{
uint32_t ret = cpu_inb(NULL, addr & 0xffff);
return ret;
}
static void PPC_io_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
{
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap16(value);
#endif
cpu_outw(NULL, addr & 0xffff, value);
}
static uint32_t PPC_io_readw (void *opaque, target_phys_addr_t addr)
{
uint32_t ret = cpu_inw(NULL, addr & 0xffff);
#ifdef TARGET_WORDS_BIGENDIAN
ret = bswap16(ret);
#endif
return ret;
}
static void PPC_io_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap32(value);
#endif
cpu_outl(NULL, addr & 0xffff, value);
}
static uint32_t PPC_io_readl (void *opaque, target_phys_addr_t addr)
{
uint32_t ret = cpu_inl(NULL, addr & 0xffff);
#ifdef TARGET_WORDS_BIGENDIAN
ret = bswap32(ret);
#endif
return ret;
}
CPUWriteMemoryFunc *PPC_io_write[] = {
&PPC_io_writeb,
&PPC_io_writew,
&PPC_io_writel,
};
CPUReadMemoryFunc *PPC_io_read[] = {
&PPC_io_readb,
&PPC_io_readw,
&PPC_io_readl,
};
/*****************************************************************************/
/* Debug port */
void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
{
addr &= 0xF;
switch (addr) {
case 0:
printf("%c", val);
break;
case 1:
printf("\n");
fflush(stdout);
break;
case 2:
printf("Set loglevel to %04x\n", val);
cpu_set_log(val | 0x100);
break;
}
}
/*****************************************************************************/
/* NVRAM helpers */
void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value)
{
m48t59_set_addr(nvram, addr);
m48t59_write(nvram, value);
}
uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr)
{
m48t59_set_addr(nvram, addr);
return m48t59_read(nvram);
}
void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
{
m48t59_set_addr(nvram, addr);
m48t59_write(nvram, value >> 8);
m48t59_set_addr(nvram, addr + 1);
m48t59_write(nvram, value & 0xFF);
}
uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr)
{
uint16_t tmp;
m48t59_set_addr(nvram, addr);
tmp = m48t59_read(nvram) << 8;
m48t59_set_addr(nvram, addr + 1);
tmp |= m48t59_read(nvram);
return tmp;
}
void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
{
m48t59_set_addr(nvram, addr);
m48t59_write(nvram, value >> 24);
m48t59_set_addr(nvram, addr + 1);
m48t59_write(nvram, (value >> 16) & 0xFF);
m48t59_set_addr(nvram, addr + 2);
m48t59_write(nvram, (value >> 8) & 0xFF);
m48t59_set_addr(nvram, addr + 3);
m48t59_write(nvram, value & 0xFF);
}
uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
{
uint32_t tmp;
m48t59_set_addr(nvram, addr);
tmp = m48t59_read(nvram) << 24;
m48t59_set_addr(nvram, addr + 1);
tmp |= m48t59_read(nvram) << 16;
m48t59_set_addr(nvram, addr + 2);
tmp |= m48t59_read(nvram) << 8;
m48t59_set_addr(nvram, addr + 3);
tmp |= m48t59_read(nvram);
return tmp;
}
void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
const unsigned char *str, uint32_t max)
{
int i;
for (i = 0; i < max && str[i] != '\0'; i++) {
m48t59_set_addr(nvram, addr + i);
m48t59_write(nvram, str[i]);
}
m48t59_set_addr(nvram, addr + max - 1);
m48t59_write(nvram, '\0');
}
int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max)
{
int i;
memset(dst, 0, max);
for (i = 0; i < max; i++) {
dst[i] = NVRAM_get_byte(nvram, addr + i);
if (dst[i] == '\0')
break;
}
return i;
}
static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
{
uint16_t tmp;
uint16_t pd, pd1, pd2;
tmp = prev >> 8;
pd = prev ^ value;
pd1 = pd & 0x000F;
pd2 = ((pd >> 4) & 0x000F) ^ pd1;
tmp ^= (pd1 << 3) | (pd1 << 8);
tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
return tmp;
}
uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count)
{
uint32_t i;
uint16_t crc = 0xFFFF;
int odd;
odd = count & 1;
count &= ~1;
for (i = 0; i != count; i++) {
crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
}
if (odd) {
crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
}
return crc;
}
#define CMDLINE_ADDR 0x017ff000
int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
const unsigned char *arch,
uint32_t RAM_size, int boot_device,
uint32_t kernel_image, uint32_t kernel_size,
const char *cmdline,
uint32_t initrd_image, uint32_t initrd_size,
uint32_t NVRAM_image,
int width, int height, int depth)
{
uint16_t crc;
/* Set parameters for Open Hack'Ware BIOS */
NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */
NVRAM_set_word(nvram, 0x14, NVRAM_size);
NVRAM_set_string(nvram, 0x20, arch, 16);
NVRAM_set_lword(nvram, 0x30, RAM_size);
NVRAM_set_byte(nvram, 0x34, boot_device);
NVRAM_set_lword(nvram, 0x38, kernel_image);
NVRAM_set_lword(nvram, 0x3C, kernel_size);
if (cmdline) {
/* XXX: put the cmdline in NVRAM too ? */
strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR);
NVRAM_set_lword(nvram, 0x44, strlen(cmdline));
} else {
NVRAM_set_lword(nvram, 0x40, 0);
NVRAM_set_lword(nvram, 0x44, 0);
}
NVRAM_set_lword(nvram, 0x48, initrd_image);
NVRAM_set_lword(nvram, 0x4C, initrd_size);
NVRAM_set_lword(nvram, 0x50, NVRAM_image);
NVRAM_set_word(nvram, 0x54, width);
NVRAM_set_word(nvram, 0x56, height);
NVRAM_set_word(nvram, 0x58, depth);
crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
NVRAM_set_word(nvram, 0xFC, crc);
return 0;
}
-556
View File
@@ -1,556 +0,0 @@
/*
* QEMU PPC CHRP/PMAC hardware System Emulator
*
* Copyright (c) 2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#define BIOS_FILENAME "ppc_rom.bin"
#define VGABIOS_FILENAME "video.x"
#define NVRAM_SIZE 0x2000
#define KERNEL_LOAD_ADDR 0x01000000
#define INITRD_LOAD_ADDR 0x01800000
/* MacIO devices (mapped inside the MacIO address space): CUDA, DBDMA,
NVRAM */
static int dbdma_mem_index;
static int cuda_mem_index;
static int ide0_mem_index = -1;
static int ide1_mem_index = -1;
static int openpic_mem_index = -1;
static int heathrow_pic_mem_index = -1;
static int macio_nvram_mem_index = -1;
/* DBDMA: currently no op - should suffice right now */
static void dbdma_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
printf("%s: 0x%08x <= 0x%08x\n", __func__, addr, value);
}
static void dbdma_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
{
}
static void dbdma_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
}
static uint32_t dbdma_readb (void *opaque, target_phys_addr_t addr)
{
printf("%s: 0x%08x => 0x00000000\n", __func__, addr);
return 0;
}
static uint32_t dbdma_readw (void *opaque, target_phys_addr_t addr)
{
return 0;
}
static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr)
{
return 0;
}
static CPUWriteMemoryFunc *dbdma_write[] = {
&dbdma_writeb,
&dbdma_writew,
&dbdma_writel,
};
static CPUReadMemoryFunc *dbdma_read[] = {
&dbdma_readb,
&dbdma_readw,
&dbdma_readl,
};
/* macio style NVRAM device */
typedef struct MacIONVRAMState {
uint8_t data[0x2000];
} MacIONVRAMState;
static void macio_nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
MacIONVRAMState *s = opaque;
addr = (addr >> 4) & 0x1fff;
s->data[addr] = value;
// printf("macio_nvram_writeb %04x = %02x\n", addr, value);
}
static uint32_t macio_nvram_readb (void *opaque, target_phys_addr_t addr)
{
MacIONVRAMState *s = opaque;
uint32_t value;
addr = (addr >> 4) & 0x1fff;
value = s->data[addr];
// printf("macio_nvram_readb %04x = %02x\n", addr, value);
return value;
}
static CPUWriteMemoryFunc *macio_nvram_write[] = {
&macio_nvram_writeb,
&macio_nvram_writeb,
&macio_nvram_writeb,
};
static CPUReadMemoryFunc *macio_nvram_read[] = {
&macio_nvram_readb,
&macio_nvram_readb,
&macio_nvram_readb,
};
static MacIONVRAMState *macio_nvram_init(void)
{
MacIONVRAMState *s;
s = qemu_mallocz(sizeof(MacIONVRAMState));
if (!s)
return NULL;
macio_nvram_mem_index = cpu_register_io_memory(0, macio_nvram_read,
macio_nvram_write, s);
return s;
}
static void macio_map(PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type)
{
if (heathrow_pic_mem_index >= 0) {
cpu_register_physical_memory(addr + 0x00000, 0x1000,
heathrow_pic_mem_index);
}
cpu_register_physical_memory(addr + 0x08000, 0x1000, dbdma_mem_index);
cpu_register_physical_memory(addr + 0x16000, 0x2000, cuda_mem_index);
if (ide0_mem_index >= 0)
cpu_register_physical_memory(addr + 0x1f000, 0x1000, ide0_mem_index);
if (ide1_mem_index >= 0)
cpu_register_physical_memory(addr + 0x20000, 0x1000, ide1_mem_index);
if (openpic_mem_index >= 0) {
cpu_register_physical_memory(addr + 0x40000, 0x40000,
openpic_mem_index);
}
if (macio_nvram_mem_index >= 0)
cpu_register_physical_memory(addr + 0x60000, 0x20000, macio_nvram_mem_index);
}
static void macio_init(PCIBus *bus, int device_id)
{
PCIDevice *d;
d = pci_register_device(bus, "macio", sizeof(PCIDevice),
-1, NULL, NULL);
/* Note: this code is strongly inspirated from the corresponding code
in PearPC */
d->config[0x00] = 0x6b; // vendor_id
d->config[0x01] = 0x10;
d->config[0x02] = device_id;
d->config[0x03] = device_id >> 8;
d->config[0x0a] = 0x00; // class_sub = pci2pci
d->config[0x0b] = 0xff; // class_base = bridge
d->config[0x0e] = 0x00; // header_type
d->config[0x3d] = 0x01; // interrupt on pin 1
dbdma_mem_index = cpu_register_io_memory(0, dbdma_read, dbdma_write, NULL);
pci_register_io_region(d, 0, 0x80000,
PCI_ADDRESS_SPACE_MEM, macio_map);
}
/* UniN device */
static void unin_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
}
static uint32_t unin_readl (void *opaque, target_phys_addr_t addr)
{
return 0;
}
static CPUWriteMemoryFunc *unin_write[] = {
&unin_writel,
&unin_writel,
&unin_writel,
};
static CPUReadMemoryFunc *unin_read[] = {
&unin_readl,
&unin_readl,
&unin_readl,
};
/* temporary frame buffer OSI calls for the video.x driver. The right
solution is to modify the driver to use VGA PCI I/Os */
static int vga_osi_call(CPUState *env)
{
static int vga_vbl_enabled;
int linesize;
// printf("osi_call R5=%d\n", env->gpr[5]);
/* same handler as PearPC, coming from the original MOL video
driver. */
switch(env->gpr[5]) {
case 4:
break;
case 28: /* set_vmode */
if (env->gpr[6] != 1 || env->gpr[7] != 0)
env->gpr[3] = 1;
else
env->gpr[3] = 0;
break;
case 29: /* get_vmode_info */
if (env->gpr[6] != 0) {
if (env->gpr[6] != 1 || env->gpr[7] != 0) {
env->gpr[3] = 1;
break;
}
}
env->gpr[3] = 0;
env->gpr[4] = (1 << 16) | 1; /* num_vmodes, cur_vmode */
env->gpr[5] = (1 << 16) | 0; /* num_depths, cur_depth_mode */
env->gpr[6] = (graphic_width << 16) | graphic_height; /* w, h */
env->gpr[7] = 85 << 16; /* refresh rate */
env->gpr[8] = (graphic_depth + 7) & ~7; /* depth (round to byte) */
linesize = ((graphic_depth + 7) >> 3) * graphic_width;
linesize = (linesize + 3) & ~3;
env->gpr[9] = (linesize << 16) | 0; /* row_bytes, offset */
break;
case 31: /* set_video power */
env->gpr[3] = 0;
break;
case 39: /* video_ctrl */
if (env->gpr[6] == 0 || env->gpr[6] == 1)
vga_vbl_enabled = env->gpr[6];
env->gpr[3] = 0;
break;
case 47:
break;
case 59: /* set_color */
/* R6 = index, R7 = RGB */
env->gpr[3] = 0;
break;
case 64: /* get color */
/* R6 = index */
env->gpr[3] = 0;
break;
case 116: /* set hwcursor */
/* R6 = x, R7 = y, R8 = visible, R9 = data */
break;
default:
fprintf(stderr, "unsupported OSI call R5=%08x\n", env->gpr[5]);
break;
}
return 1; /* osi_call handled */
}
/* XXX: suppress that */
static void pic_irq_request(void *opaque, int level)
{
}
static uint8_t nvram_chksum(const uint8_t *buf, int n)
{
int sum, i;
sum = 0;
for(i = 0; i < n; i++)
sum += buf[i];
return (sum & 0xff) + (sum >> 8);
}
/* set a free Mac OS NVRAM partition */
void pmac_format_nvram_partition(uint8_t *buf, int len)
{
char partition_name[12] = "wwwwwwwwwwww";
buf[0] = 0x7f; /* free partition magic */
buf[1] = 0; /* checksum */
buf[2] = len >> 8;
buf[3] = len;
memcpy(buf + 4, partition_name, 12);
buf[1] = nvram_chksum(buf, 16);
}
/* PowerPC CHRP hardware initialisation */
static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename,
int snapshot,
const char *kernel_filename,
const char *kernel_cmdline,
const char *initrd_filename,
int is_heathrow)
{
char buf[1024];
SetIRQFunc *set_irq;
void *pic;
m48t59_t *nvram;
int PPC_io_memory, unin_memory;
int linux_boot, i;
unsigned long bios_offset, vga_bios_offset;
uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
ppc_def_t *def;
PCIBus *pci_bus;
const char *arch_name;
int vga_bios_size, bios_size;
linux_boot = (kernel_filename != NULL);
/* allocate RAM */
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
/* allocate and load BIOS */
bios_offset = ram_size + vga_ram_size;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
bios_size = load_image(buf, phys_ram_base + bios_offset);
if (bios_size < 0 || bios_size > BIOS_SIZE) {
fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf);
exit(1);
}
bios_size = (bios_size + 0xfff) & ~0xfff;
cpu_register_physical_memory((uint32_t)(-bios_size),
bios_size, bios_offset | IO_MEM_ROM);
/* allocate and load VGA BIOS */
vga_bios_offset = bios_offset + bios_size;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
vga_bios_size = load_image(buf, phys_ram_base + vga_bios_offset + 8);
if (vga_bios_size < 0) {
/* if no bios is present, we can still work */
fprintf(stderr, "qemu: warning: could not load VGA bios '%s'\n", buf);
vga_bios_size = 0;
} else {
/* set a specific header (XXX: find real Apple format for NDRV
drivers) */
phys_ram_base[vga_bios_offset] = 'N';
phys_ram_base[vga_bios_offset + 1] = 'D';
phys_ram_base[vga_bios_offset + 2] = 'R';
phys_ram_base[vga_bios_offset + 3] = 'V';
cpu_to_be32w((uint32_t *)(phys_ram_base + vga_bios_offset + 4),
vga_bios_size);
vga_bios_size += 8;
}
vga_bios_size = (vga_bios_size + 0xfff) & ~0xfff;
if (linux_boot) {
kernel_base = KERNEL_LOAD_ADDR;
/* now we can load the kernel */
kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
kernel_filename);
exit(1);
}
/* load initrd */
if (initrd_filename) {
initrd_base = INITRD_LOAD_ADDR;
initrd_size = load_image(initrd_filename,
phys_ram_base + initrd_base);
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
exit(1);
}
} else {
initrd_base = 0;
initrd_size = 0;
}
boot_device = 'm';
} else {
kernel_base = 0;
kernel_size = 0;
initrd_base = 0;
initrd_size = 0;
}
/* Register CPU as a 74x/75x */
/* XXX: CPU model (or PVR) should be provided on command line */
// ppc_find_by_name("750gx", &def); // Linux boot OK
// ppc_find_by_name("750fx", &def); // Linux boot OK
/* Linux does not boot on 750cxe (and probably other 750cx based)
* because it assumes it has 8 IBAT & DBAT pairs as it only have 4.
*/
// ppc_find_by_name("750cxe", &def);
// ppc_find_by_name("750p", &def);
// ppc_find_by_name("740p", &def);
ppc_find_by_name("750", &def);
// ppc_find_by_name("740", &def);
// ppc_find_by_name("G3", &def);
// ppc_find_by_name("604r", &def);
// ppc_find_by_name("604e", &def);
// ppc_find_by_name("604", &def);
if (def == NULL) {
cpu_abort(cpu_single_env, "Unable to find PowerPC CPU definition\n");
}
cpu_ppc_register(cpu_single_env, def);
/* Set time-base frequency to 100 Mhz */
cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL);
cpu_single_env->osi_call = vga_osi_call;
if (is_heathrow) {
isa_mem_base = 0x80000000;
pci_bus = pci_grackle_init(0xfec00000);
/* Register 2 MB of ISA IO space */
PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
cpu_register_physical_memory(0xfe000000, 0x00200000, PPC_io_memory);
/* init basic PC hardware */
vga_initialize(pci_bus, ds, phys_ram_base + ram_size,
ram_size, vga_ram_size,
vga_bios_offset, vga_bios_size);
pic = heathrow_pic_init(&heathrow_pic_mem_index);
set_irq = heathrow_pic_set_irq;
pci_set_pic(pci_bus, set_irq, pic);
/* XXX: suppress that */
isa_pic = pic_init(pic_irq_request, NULL);
/* XXX: use Mac Serial port */
serial_init(0x3f8, 4, serial_hds[0]);
for(i = 0; i < nb_nics; i++) {
pci_ne2000_init(pci_bus, &nd_table[i]);
}
pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
/* cuda also initialize ADB */
cuda_mem_index = cuda_init(set_irq, pic, 0x12);
adb_kbd_init(&adb_bus);
adb_mouse_init(&adb_bus);
{
MacIONVRAMState *nvr;
nvr = macio_nvram_init();
pmac_format_nvram_partition(nvr->data, 0x2000);
}
macio_init(pci_bus, 0x0017);
nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE);
arch_name = "HEATHROW";
} else {
isa_mem_base = 0x80000000;
pci_bus = pci_pmac_init();
/* Register 8 MB of ISA IO space */
PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
cpu_register_physical_memory(0xF2000000, 0x00800000, PPC_io_memory);
/* UniN init */
unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL);
cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory);
/* init basic PC hardware */
vga_initialize(pci_bus, ds, phys_ram_base + ram_size,
ram_size, vga_ram_size,
vga_bios_offset, vga_bios_size);
pic = openpic_init(NULL, &openpic_mem_index, 1);
set_irq = openpic_set_irq;
pci_set_pic(pci_bus, set_irq, pic);
/* XXX: suppress that */
isa_pic = pic_init(pic_irq_request, NULL);
/* XXX: use Mac Serial port */
serial_init(0x3f8, 4, serial_hds[0]);
for(i = 0; i < nb_nics; i++) {
pci_ne2000_init(pci_bus, &nd_table[i]);
}
#if 1
ide0_mem_index = pmac_ide_init(&bs_table[0], set_irq, pic, 0x13);
ide1_mem_index = pmac_ide_init(&bs_table[2], set_irq, pic, 0x14);
#else
pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
#endif
/* cuda also initialize ADB */
cuda_mem_index = cuda_init(set_irq, pic, 0x19);
adb_kbd_init(&adb_bus);
adb_mouse_init(&adb_bus);
macio_init(pci_bus, 0x0022);
nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE);
arch_name = "MAC99";
}
if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
graphic_depth = 15;
PPC_NVRAM_set_params(nvram, NVRAM_SIZE, arch_name, ram_size, boot_device,
kernel_base, kernel_size,
kernel_cmdline,
initrd_base, initrd_size,
/* XXX: need an option to load a NVRAM image */
0,
graphic_width, graphic_height, graphic_depth);
/* No PCI init: the BIOS will do it */
/* Special port to get debug messages from Open-Firmware */
register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
}
static void ppc_core99_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename,
int snapshot,
const char *kernel_filename,
const char *kernel_cmdline,
const char *initrd_filename)
{
ppc_chrp_init(ram_size, vga_ram_size, boot_device,
ds, fd_filename, snapshot,
kernel_filename, kernel_cmdline,
initrd_filename, 0);
}
static void ppc_heathrow_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename,
int snapshot,
const char *kernel_filename,
const char *kernel_cmdline,
const char *initrd_filename)
{
ppc_chrp_init(ram_size, vga_ram_size, boot_device,
ds, fd_filename, snapshot,
kernel_filename, kernel_cmdline,
initrd_filename, 1);
}
QEMUMachine core99_machine = {
"mac99",
"Mac99 based PowerMAC",
ppc_core99_init,
};
QEMUMachine heathrow_machine = {
"g3bw",
"Heathrow based PowerMAC",
ppc_heathrow_init,
};
-677
View File
@@ -1,677 +0,0 @@
/*
* QEMU PPC PREP hardware System Emulator
*
* Copyright (c) 2003-2004 Jocelyn Mayer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
//#define HARD_DEBUG_PPC_IO
//#define DEBUG_PPC_IO
#define BIOS_FILENAME "ppc_rom.bin"
#define KERNEL_LOAD_ADDR 0x01000000
#define INITRD_LOAD_ADDR 0x01800000
extern int loglevel;
extern FILE *logfile;
#if defined (HARD_DEBUG_PPC_IO) && !defined (DEBUG_PPC_IO)
#define DEBUG_PPC_IO
#endif
#if defined (HARD_DEBUG_PPC_IO)
#define PPC_IO_DPRINTF(fmt, args...) \
do { \
if (loglevel & CPU_LOG_IOPORT) { \
fprintf(logfile, "%s: " fmt, __func__ , ##args); \
} else { \
printf("%s : " fmt, __func__ , ##args); \
} \
} while (0)
#elif defined (DEBUG_PPC_IO)
#define PPC_IO_DPRINTF(fmt, args...) \
do { \
if (loglevel & CPU_LOG_IOPORT) { \
fprintf(logfile, "%s: " fmt, __func__ , ##args); \
} \
} while (0)
#else
#define PPC_IO_DPRINTF(fmt, args...) do { } while (0)
#endif
/* Constants for devices init */
static const int ide_iobase[2] = { 0x1f0, 0x170 };
static const int ide_iobase2[2] = { 0x3f6, 0x376 };
static const int ide_irq[2] = { 13, 13 };
#define NE2000_NB_MAX 6
static uint32_t ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };
static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
//static PITState *pit;
/* ISA IO ports bridge */
#define PPC_IO_BASE 0x80000000
/* Speaker port 0x61 */
int speaker_data_on;
int dummy_refresh_clock;
static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
#if 0
speaker_data_on = (val >> 1) & 1;
pit_set_gate(pit, 2, val & 1);
#endif
}
static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
{
#if 0
int out;
out = pit_get_out(pit, 2, qemu_get_clock(vm_clock));
dummy_refresh_clock ^= 1;
return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) |
(dummy_refresh_clock << 4);
#endif
return 0;
}
static void pic_irq_request(void *opaque, int level)
{
if (level)
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
else
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
/* PCI intack register */
/* Read-only register (?) */
static void _PPC_intack_write (void *opaque, target_phys_addr_t addr, uint32_t value)
{
// printf("%s: 0x%08x => 0x%08x\n", __func__, addr, value);
}
static inline uint32_t _PPC_intack_read (target_phys_addr_t addr)
{
uint32_t retval = 0;
if (addr == 0xBFFFFFF0)
retval = pic_intack_read(isa_pic);
// printf("%s: 0x%08x <= %d\n", __func__, addr, retval);
return retval;
}
static uint32_t PPC_intack_readb (void *opaque, target_phys_addr_t addr)
{
return _PPC_intack_read(addr);
}
static uint32_t PPC_intack_readw (void *opaque, target_phys_addr_t addr)
{
#ifdef TARGET_WORDS_BIGENDIAN
return bswap16(_PPC_intack_read(addr));
#else
return _PPC_intack_read(addr);
#endif
}
static uint32_t PPC_intack_readl (void *opaque, target_phys_addr_t addr)
{
#ifdef TARGET_WORDS_BIGENDIAN
return bswap32(_PPC_intack_read(addr));
#else
return _PPC_intack_read(addr);
#endif
}
static CPUWriteMemoryFunc *PPC_intack_write[] = {
&_PPC_intack_write,
&_PPC_intack_write,
&_PPC_intack_write,
};
static CPUReadMemoryFunc *PPC_intack_read[] = {
&PPC_intack_readb,
&PPC_intack_readw,
&PPC_intack_readl,
};
/* PowerPC control and status registers */
#if 0 // Not used
static struct {
/* IDs */
uint32_t veni_devi;
uint32_t revi;
/* Control and status */
uint32_t gcsr;
uint32_t xcfr;
uint32_t ct32;
uint32_t mcsr;
/* General purpose registers */
uint32_t gprg[6];
/* Exceptions */
uint32_t feen;
uint32_t fest;
uint32_t fema;
uint32_t fecl;
uint32_t eeen;
uint32_t eest;
uint32_t eecl;
uint32_t eeint;
uint32_t eemck0;
uint32_t eemck1;
/* Error diagnostic */
} XCSR;
static void PPC_XCSR_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value);
}
static void PPC_XCSR_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
{
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap16(value);
#endif
printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value);
}
static void PPC_XCSR_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap32(value);
#endif
printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value);
}
static uint32_t PPC_XCSR_readb (void *opaque, target_phys_addr_t addr)
{
uint32_t retval = 0;
printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval);
return retval;
}
static uint32_t PPC_XCSR_readw (void *opaque, target_phys_addr_t addr)
{
uint32_t retval = 0;
printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval);
#ifdef TARGET_WORDS_BIGENDIAN
retval = bswap16(retval);
#endif
return retval;
}
static uint32_t PPC_XCSR_readl (void *opaque, target_phys_addr_t addr)
{
uint32_t retval = 0;
printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval);
#ifdef TARGET_WORDS_BIGENDIAN
retval = bswap32(retval);
#endif
return retval;
}
static CPUWriteMemoryFunc *PPC_XCSR_write[] = {
&PPC_XCSR_writeb,
&PPC_XCSR_writew,
&PPC_XCSR_writel,
};
static CPUReadMemoryFunc *PPC_XCSR_read[] = {
&PPC_XCSR_readb,
&PPC_XCSR_readw,
&PPC_XCSR_readl,
};
#endif
/* Fake super-io ports for PREP platform (Intel 82378ZB) */
typedef struct sysctrl_t {
m48t59_t *nvram;
uint8_t state;
uint8_t syscontrol;
uint8_t fake_io[2];
int contiguous_map;
int endian;
} sysctrl_t;
enum {
STATE_HARDFILE = 0x01,
};
static sysctrl_t *sysctrl;
static void PREP_io_write (void *opaque, uint32_t addr, uint32_t val)
{
sysctrl_t *sysctrl = opaque;
PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr - PPC_IO_BASE, val);
sysctrl->fake_io[addr - 0x0398] = val;
}
static uint32_t PREP_io_read (void *opaque, uint32_t addr)
{
sysctrl_t *sysctrl = opaque;
PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr - PPC_IO_BASE,
sysctrl->fake_io[addr - 0x0398]);
return sysctrl->fake_io[addr - 0x0398];
}
static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val)
{
sysctrl_t *sysctrl = opaque;
PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr - PPC_IO_BASE, val);
switch (addr) {
case 0x0092:
/* Special port 92 */
/* Check soft reset asked */
if (val & 0x01) {
// cpu_interrupt(cpu_single_env, CPU_INTERRUPT_RESET);
}
/* Check LE mode */
if (val & 0x02) {
sysctrl->endian = 1;
} else {
sysctrl->endian = 0;
}
break;
case 0x0800:
/* Motorola CPU configuration register : read-only */
break;
case 0x0802:
/* Motorola base module feature register : read-only */
break;
case 0x0803:
/* Motorola base module status register : read-only */
break;
case 0x0808:
/* Hardfile light register */
if (val & 1)
sysctrl->state |= STATE_HARDFILE;
else
sysctrl->state &= ~STATE_HARDFILE;
break;
case 0x0810:
/* Password protect 1 register */
if (sysctrl->nvram != NULL)
m48t59_toggle_lock(sysctrl->nvram, 1);
break;
case 0x0812:
/* Password protect 2 register */
if (sysctrl->nvram != NULL)
m48t59_toggle_lock(sysctrl->nvram, 2);
break;
case 0x0814:
/* L2 invalidate register */
// tlb_flush(cpu_single_env, 1);
break;
case 0x081C:
/* system control register */
sysctrl->syscontrol = val & 0x0F;
break;
case 0x0850:
/* I/O map type register */
sysctrl->contiguous_map = val & 0x01;
break;
default:
printf("ERROR: unaffected IO port write: %04lx => %02x\n",
(long)addr, val);
break;
}
}
static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr)
{
sysctrl_t *sysctrl = opaque;
uint32_t retval = 0xFF;
switch (addr) {
case 0x0092:
/* Special port 92 */
retval = 0x00;
break;
case 0x0800:
/* Motorola CPU configuration register */
retval = 0xEF; /* MPC750 */
break;
case 0x0802:
/* Motorola Base module feature register */
retval = 0xAD; /* No ESCC, PMC slot neither ethernet */
break;
case 0x0803:
/* Motorola base module status register */
retval = 0xE0; /* Standard MPC750 */
break;
case 0x080C:
/* Equipment present register:
* no L2 cache
* no upgrade processor
* no cards in PCI slots
* SCSI fuse is bad
*/
retval = 0x3C;
break;
case 0x0810:
/* Motorola base module extended feature register */
retval = 0x39; /* No USB, CF and PCI bridge. NVRAM present */
break;
case 0x0814:
/* L2 invalidate: don't care */
break;
case 0x0818:
/* Keylock */
retval = 0x00;
break;
case 0x081C:
/* system control register
* 7 - 6 / 1 - 0: L2 cache enable
*/
retval = sysctrl->syscontrol;
break;
case 0x0823:
/* */
retval = 0x03; /* no L2 cache */
break;
case 0x0850:
/* I/O map type register */
retval = sysctrl->contiguous_map;
break;
default:
printf("ERROR: unaffected IO port: %04lx read\n", (long)addr);
break;
}
PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr - PPC_IO_BASE, retval);
return retval;
}
static inline target_phys_addr_t prep_IO_address (sysctrl_t *sysctrl,
target_phys_addr_t addr)
{
if (sysctrl->contiguous_map == 0) {
/* 64 KB contiguous space for IOs */
addr &= 0xFFFF;
} else {
/* 8 MB non-contiguous space for IOs */
addr = (addr & 0x1F) | ((addr & 0x007FFF000) >> 7);
}
return addr;
}
static void PPC_prep_io_writeb (void *opaque, target_phys_addr_t addr,
uint32_t value)
{
sysctrl_t *sysctrl = opaque;
addr = prep_IO_address(sysctrl, addr);
cpu_outb(NULL, addr, value);
}
static uint32_t PPC_prep_io_readb (void *opaque, target_phys_addr_t addr)
{
sysctrl_t *sysctrl = opaque;
uint32_t ret;
addr = prep_IO_address(sysctrl, addr);
ret = cpu_inb(NULL, addr);
return ret;
}
static void PPC_prep_io_writew (void *opaque, target_phys_addr_t addr,
uint32_t value)
{
sysctrl_t *sysctrl = opaque;
addr = prep_IO_address(sysctrl, addr);
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap16(value);
#endif
PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr, value);
cpu_outw(NULL, addr, value);
}
static uint32_t PPC_prep_io_readw (void *opaque, target_phys_addr_t addr)
{
sysctrl_t *sysctrl = opaque;
uint32_t ret;
addr = prep_IO_address(sysctrl, addr);
ret = cpu_inw(NULL, addr);
#ifdef TARGET_WORDS_BIGENDIAN
ret = bswap16(ret);
#endif
PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr, ret);
return ret;
}
static void PPC_prep_io_writel (void *opaque, target_phys_addr_t addr,
uint32_t value)
{
sysctrl_t *sysctrl = opaque;
addr = prep_IO_address(sysctrl, addr);
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap32(value);
#endif
PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr, value);
cpu_outl(NULL, addr, value);
}
static uint32_t PPC_prep_io_readl (void *opaque, target_phys_addr_t addr)
{
sysctrl_t *sysctrl = opaque;
uint32_t ret;
addr = prep_IO_address(sysctrl, addr);
ret = cpu_inl(NULL, addr);
#ifdef TARGET_WORDS_BIGENDIAN
ret = bswap32(ret);
#endif
PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr, ret);
return ret;
}
CPUWriteMemoryFunc *PPC_prep_io_write[] = {
&PPC_prep_io_writeb,
&PPC_prep_io_writew,
&PPC_prep_io_writel,
};
CPUReadMemoryFunc *PPC_prep_io_read[] = {
&PPC_prep_io_readb,
&PPC_prep_io_readw,
&PPC_prep_io_readl,
};
#define NVRAM_SIZE 0x2000
/* PowerPC PREP hardware initialisation */
static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
char buf[1024];
m48t59_t *nvram;
int PPC_io_memory;
int linux_boot, i, nb_nics1, bios_size;
unsigned long bios_offset;
uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
ppc_def_t *def;
PCIBus *pci_bus;
sysctrl = qemu_mallocz(sizeof(sysctrl_t));
if (sysctrl == NULL)
return;
linux_boot = (kernel_filename != NULL);
/* allocate RAM */
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
/* allocate and load BIOS */
bios_offset = ram_size + vga_ram_size;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
bios_size = load_image(buf, phys_ram_base + bios_offset);
if (bios_size < 0 || bios_size > BIOS_SIZE) {
fprintf(stderr, "qemu: could not load PPC PREP bios '%s'\n", buf);
exit(1);
}
bios_size = (bios_size + 0xfff) & ~0xfff;
cpu_register_physical_memory((uint32_t)(-bios_size),
bios_size, bios_offset | IO_MEM_ROM);
if (linux_boot) {
kernel_base = KERNEL_LOAD_ADDR;
/* now we can load the kernel */
kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
kernel_filename);
exit(1);
}
/* load initrd */
if (initrd_filename) {
initrd_base = INITRD_LOAD_ADDR;
initrd_size = load_image(initrd_filename,
phys_ram_base + initrd_base);
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
exit(1);
}
} else {
initrd_base = 0;
initrd_size = 0;
}
boot_device = 'm';
} else {
kernel_base = 0;
kernel_size = 0;
initrd_base = 0;
initrd_size = 0;
}
/* Register CPU as a 604 */
/* XXX: CPU model (or PVR) should be provided on command line */
// ppc_find_by_name("604r", &def);
// ppc_find_by_name("604e", &def);
ppc_find_by_name("604", &def);
if (def == NULL) {
cpu_abort(cpu_single_env, "Unable to find PowerPC CPU definition\n");
}
cpu_ppc_register(cpu_single_env, def);
/* Set time-base frequency to 100 Mhz */
cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL);
isa_mem_base = 0xc0000000;
pci_bus = pci_prep_init();
// pci_bus = i440fx_init();
/* Register 8 MB of ISA IO space (needed for non-contiguous map) */
PPC_io_memory = cpu_register_io_memory(0, PPC_prep_io_read,
PPC_prep_io_write, sysctrl);
cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory);
/* init basic PC hardware */
vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
vga_ram_size, 0, 0);
rtc_init(0x70, 8);
// openpic = openpic_init(0x00000000, 0xF0000000, 1);
isa_pic = pic_init(pic_irq_request, cpu_single_env);
// pit = pit_init(0x40, 0);
serial_init(0x3f8, 4, serial_hds[0]);
nb_nics1 = nb_nics;
if (nb_nics1 > NE2000_NB_MAX)
nb_nics1 = NE2000_NB_MAX;
for(i = 0; i < nb_nics1; i++) {
isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]);
}
for(i = 0; i < 2; i++) {
isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
bs_table[2 * i], bs_table[2 * i + 1]);
}
kbd_init();
DMA_init(1);
// AUD_init();
// SB16_init();
fdctrl_init(6, 2, 0, 0x3f0, fd_table);
/* Register speaker port */
register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL);
register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL);
/* Register fake IO ports for PREP */
register_ioport_read(0x398, 2, 1, &PREP_io_read, sysctrl);
register_ioport_write(0x398, 2, 1, &PREP_io_write, sysctrl);
/* System control ports */
register_ioport_read(0x0092, 0x01, 1, &PREP_io_800_readb, sysctrl);
register_ioport_write(0x0092, 0x01, 1, &PREP_io_800_writeb, sysctrl);
register_ioport_read(0x0800, 0x52, 1, &PREP_io_800_readb, sysctrl);
register_ioport_write(0x0800, 0x52, 1, &PREP_io_800_writeb, sysctrl);
/* PCI intack location */
PPC_io_memory = cpu_register_io_memory(0, PPC_intack_read,
PPC_intack_write, NULL);
cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory);
/* PowerPC control and status register group */
#if 0
PPC_io_memory = cpu_register_io_memory(0, PPC_XCSR_read, PPC_XCSR_write, NULL);
cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory);
#endif
nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE);
if (nvram == NULL)
return;
sysctrl->nvram = nvram;
/* Initialise NVRAM */
PPC_NVRAM_set_params(nvram, NVRAM_SIZE, "PREP", ram_size, boot_device,
kernel_base, kernel_size,
kernel_cmdline,
initrd_base, initrd_size,
/* XXX: need an option to load a NVRAM image */
0,
graphic_width, graphic_height, graphic_depth);
/* Special port to get debug messages from Open-Firmware */
register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
}
QEMUMachine prep_machine = {
"prep",
"PowerPC PREP platform",
ppc_prep_init,
};
-1268
View File
File diff suppressed because it is too large. Load diff
Loaded 100 of 342 files, more files were not shown because too many files have changed in this diff. Show more