r1639 - trunk/src/host/qemu-neo1973
andrew at sita.openmoko.org
andrew at sita.openmoko.org
Mon Apr 2 22:51:48 CEST 2007
Author: andrew
Date: 2007-04-02 22:50:31 +0200 (Mon, 02 Apr 2007)
New Revision: 1639
Added:
trunk/src/host/qemu-neo1973/COPYING
trunk/src/host/qemu-neo1973/COPYING.LIB
trunk/src/host/qemu-neo1973/Changelog
trunk/src/host/qemu-neo1973/LICENSE
trunk/src/host/qemu-neo1973/Makefile
trunk/src/host/qemu-neo1973/Makefile.target
trunk/src/host/qemu-neo1973/README
trunk/src/host/qemu-neo1973/README.distrib
trunk/src/host/qemu-neo1973/TODO
trunk/src/host/qemu-neo1973/VERSION
trunk/src/host/qemu-neo1973/a.out.h
trunk/src/host/qemu-neo1973/aes.c
trunk/src/host/qemu-neo1973/aes.h
trunk/src/host/qemu-neo1973/alpha-dis.c
trunk/src/host/qemu-neo1973/alpha.ld
trunk/src/host/qemu-neo1973/arm-dis.c
trunk/src/host/qemu-neo1973/arm.ld
trunk/src/host/qemu-neo1973/block-bochs.c
trunk/src/host/qemu-neo1973/block-cloop.c
trunk/src/host/qemu-neo1973/block-cow.c
trunk/src/host/qemu-neo1973/block-dmg.c
trunk/src/host/qemu-neo1973/block-qcow.c
trunk/src/host/qemu-neo1973/block-qcow2.c
trunk/src/host/qemu-neo1973/block-raw.c
trunk/src/host/qemu-neo1973/block-vmdk.c
trunk/src/host/qemu-neo1973/block-vpc.c
trunk/src/host/qemu-neo1973/block-vvfat.c
trunk/src/host/qemu-neo1973/block.c
trunk/src/host/qemu-neo1973/block_int.h
trunk/src/host/qemu-neo1973/bswap.h
trunk/src/host/qemu-neo1973/check_ops.sh
trunk/src/host/qemu-neo1973/cocoa.m
trunk/src/host/qemu-neo1973/configure
trunk/src/host/qemu-neo1973/console.c
trunk/src/host/qemu-neo1973/cpu-all.h
trunk/src/host/qemu-neo1973/cpu-defs.h
trunk/src/host/qemu-neo1973/cpu-exec.c
trunk/src/host/qemu-neo1973/cutils.c
trunk/src/host/qemu-neo1973/dis-asm.h
trunk/src/host/qemu-neo1973/disas.c
trunk/src/host/qemu-neo1973/disas.h
trunk/src/host/qemu-neo1973/dyngen-exec.h
trunk/src/host/qemu-neo1973/dyngen-op.h
trunk/src/host/qemu-neo1973/dyngen.c
trunk/src/host/qemu-neo1973/dyngen.h
trunk/src/host/qemu-neo1973/ecc.h
trunk/src/host/qemu-neo1973/elf.h
trunk/src/host/qemu-neo1973/elf_ops.h
trunk/src/host/qemu-neo1973/exec-all.h
trunk/src/host/qemu-neo1973/exec.c
trunk/src/host/qemu-neo1973/gdbstub.c
trunk/src/host/qemu-neo1973/gdbstub.h
trunk/src/host/qemu-neo1973/i386-dis.c
trunk/src/host/qemu-neo1973/i386-vl.ld
trunk/src/host/qemu-neo1973/i386.ld
trunk/src/host/qemu-neo1973/ia64.ld
trunk/src/host/qemu-neo1973/keymaps.c
trunk/src/host/qemu-neo1973/kqemu.c
trunk/src/host/qemu-neo1973/kqemu.h
trunk/src/host/qemu-neo1973/linux-2.6.9-qemu-fast.patch
trunk/src/host/qemu-neo1973/loader.c
trunk/src/host/qemu-neo1973/m68k-dis.c
trunk/src/host/qemu-neo1973/m68k.ld
trunk/src/host/qemu-neo1973/mips-dis.c
trunk/src/host/qemu-neo1973/monitor.c
trunk/src/host/qemu-neo1973/osdep.c
trunk/src/host/qemu-neo1973/osdep.h
trunk/src/host/qemu-neo1973/ppc-dis.c
trunk/src/host/qemu-neo1973/ppc.ld
trunk/src/host/qemu-neo1973/qemu-binfmt-conf.sh
trunk/src/host/qemu-neo1973/qemu-doc.texi
trunk/src/host/qemu-neo1973/qemu-img.c
trunk/src/host/qemu-neo1973/qemu-img.texi
trunk/src/host/qemu-neo1973/qemu-tech.texi
trunk/src/host/qemu-neo1973/qemu_socket.h
trunk/src/host/qemu-neo1973/raw2flash.c
trunk/src/host/qemu-neo1973/readline.c
trunk/src/host/qemu-neo1973/s390.ld
trunk/src/host/qemu-neo1973/sdl.c
trunk/src/host/qemu-neo1973/sdl_keysym.h
trunk/src/host/qemu-neo1973/sh4-dis.c
trunk/src/host/qemu-neo1973/softmmu_exec.h
trunk/src/host/qemu-neo1973/softmmu_header.h
trunk/src/host/qemu-neo1973/softmmu_template.h
trunk/src/host/qemu-neo1973/sparc-dis.c
trunk/src/host/qemu-neo1973/sparc.ld
trunk/src/host/qemu-neo1973/sparc64.ld
trunk/src/host/qemu-neo1973/tap-win32.c
trunk/src/host/qemu-neo1973/texi2pod.pl
trunk/src/host/qemu-neo1973/thunk.c
trunk/src/host/qemu-neo1973/thunk.h
trunk/src/host/qemu-neo1973/translate-all.c
trunk/src/host/qemu-neo1973/translate-op.c
trunk/src/host/qemu-neo1973/usb-linux.c
trunk/src/host/qemu-neo1973/vgafont.h
trunk/src/host/qemu-neo1973/vl.c
trunk/src/host/qemu-neo1973/vl.h
trunk/src/host/qemu-neo1973/vnc.c
trunk/src/host/qemu-neo1973/vnc_keysym.h
trunk/src/host/qemu-neo1973/vnchextile.h
trunk/src/host/qemu-neo1973/x86_64.ld
Log:
Populate qemu-neo1973 main directory.
Added: trunk/src/host/qemu-neo1973/COPYING
===================================================================
--- trunk/src/host/qemu-neo1973/COPYING 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/COPYING 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,339 @@
+ 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.
Added: trunk/src/host/qemu-neo1973/COPYING.LIB
===================================================================
--- trunk/src/host/qemu-neo1973/COPYING.LIB 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/COPYING.LIB 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
Added: trunk/src/host/qemu-neo1973/Changelog
===================================================================
--- trunk/src/host/qemu-neo1973/Changelog 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/Changelog 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,405 @@
+version 0.8.3:
+
+ - Support for relative paths in backing files for disk images
+ - Async file I/O API
+ - New qcow2 disk image format
+ - Support of multiple VM snapshots
+ - Linux: specific host CDROM and floppy support
+ - SMM support
+ - Moved PCI init, MP table init and ACPI table init to Bochs BIOS
+
+version 0.8.2:
+
+ - ACPI support
+ - PC VGA BIOS fixes
+ - switch to OpenBios for SPARC targets (Blue Swirl)
+ - VNC server fixes
+ - MIPS FPU support (Marius Groeger)
+ - Solaris/SPARC host support (Ben Taylor)
+ - PPC breakpoints and single stepping (Jason Wessel)
+ - USB updates (Paul Brook)
+ - UDP/TCP/telnet character devices (Jason Wessel)
+ - Windows sparse file support (Frediano Ziglio)
+ - RTL8139 NIC TCP segmentation offloading (Igor Kovalenko)
+ - PCNET NIC support (Antony T Curtis)
+ - Support for variable frequency host CPUs
+ - Workaround for win32 SMP hosts
+ - Support for AMD Flash memories (Jocelyn Mayer)
+ - Audio capture to WAV files support (malc)
+
+version 0.8.1:
+
+ - USB tablet support (Brad Campbell, Anthony Liguori)
+ - win32 host serial support (Kazu)
+ - PC speaker support (Joachim Henke)
+ - IDE LBA48 support (Jens Axboe)
+ - SSE3 support
+ - Solaris port (Ben Taylor)
+ - Preliminary SH4 target (Samuel Tardieu)
+ - VNC server (Anthony Liguori)
+ - slirp fixes (Ed Swierk et al.)
+ - USB fixes
+ - ARM Versatile Platform Baseboard emulation (Paul Brook)
+
+version 0.8.0:
+
+ - ARM system emulation: Arm Integrator/CP board with an arm1026ej-s
+ cpu (Paul Brook)
+ - SMP support
+ - Mac OS X cocoa improvements (Mike Kronenberg)
+ - Mac OS X CoreAudio driver (Mike Kronenberg)
+ - DirectSound driver (malc)
+ - ALSA audio driver (malc)
+ - new audio options: '-soundhw' and '-audio-help' (malc)
+ - ES1370 PCI audio device (malc)
+ - Initial USB support
+ - Linux host serial port access
+ - Linux host low level parallel port access
+ - New network emulation code supporting VLANs.
+ - MIPS and MIPSel User Linux emulation
+ - MIPS fixes to boot Linux (Daniel Jacobowitz)
+ - NX bit support
+ - Initial SPARC SMP support (Blue Swirl)
+ - Major overhaul of the virtual FAT driver for read/write support
+ (Johannes Schindelin)
+
+version 0.7.2:
+
+ - x86_64 fixes (Win2000 and Linux 2.6 boot in 32 bit)
+ - merge self modifying code handling in dirty ram page mecanism.
+ - MIPS fixes (Ralf Baechle)
+ - better user net performances
+
+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)
+ - IOAPIC support (Filip Navara)
+
+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.
Added: trunk/src/host/qemu-neo1973/LICENSE
===================================================================
--- trunk/src/host/qemu-neo1973/LICENSE 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/LICENSE 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,12 @@
+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.
\ No newline at end of file
Added: trunk/src/host/qemu-neo1973/Makefile
===================================================================
--- trunk/src/host/qemu-neo1973/Makefile 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/Makefile 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,178 @@
+# Makefile for QEMU.
+
+include config-host.mak
+
+.PHONY: all clean distclean dvi info install install-doc tar tarbin \
+ speed test test2 html dvi info
+
+BASE_CFLAGS=
+BASE_LDFLAGS=
+
+BASE_CFLAGS += $(OS_CFLAGS)
+ifeq ($(ARCH),sparc)
+BASE_CFLAGS += -mcpu=ultrasparc
+endif
+CPPFLAGS += -I. -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+LIBS=
+TOOLS=qemu-img$(EXESUF) raw2flash$(EXESUF) flash2raw$(EXESUF)
+ifdef CONFIG_STATIC
+BASE_LDFLAGS += -static
+endif
+ifdef BUILD_DOCS
+DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1
+else
+DOCS=
+endif
+MODELS=spitz akita borzoi terrier neo
+
+LIBS+=$(AIOLIBS)
+
+all: $(TOOLS) $(DOCS) recurse-all
+
+subdir-%: dyngen$(EXESUF)
+ $(MAKE) -C $(subst subdir-,,$@) all
+
+recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS))
+
+qemu-img$(EXESUF): qemu-img.c cutils.c block.c block-raw.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 block-qcow2.c
+ $(CC) -DQEMU_TOOL $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $(LDFLAGS) $(BASE_LDFLAGS) -o $@ $^ -lz $(LIBS)
+
+dyngen$(EXESUF): dyngen.c
+ $(HOST_CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -o $@ $^
+
+raw2flash$(EXESUF) flash2raw$(EXESUF): raw2flash.c
+ $(CC) -D$@ $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^
+ for m in $(MODELS); do \
+ [ -e $@.$$m$(EXESUF) ] || \
+ ln -s $@ $@.$$m$(EXESUF) ; \
+ done
+
+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
+
+distclean: clean
+ rm -f config-host.mak config-host.h $(DOCS)
+ rm -f qemu-{doc,tech}.{info,aux,cp,dvi,fn,info,ky,log,pg,toc,tp,vr}
+ for d in $(TARGET_DIRS); do \
+ rm -rf $$d || exit 1 ; \
+ done
+
+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
+
+install-doc: $(DOCS)
+ mkdir -p "$(DESTDIR)$(docdir)"
+ $(INSTALL) -m 644 qemu-doc.html qemu-tech.html "$(DESTDIR)$(docdir)"
+ifndef CONFIG_WIN32
+ mkdir -p "$(DESTDIR)$(mandir)/man1"
+ $(INSTALL) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
+endif
+
+install: all $(if $(BUILD_DOCS),install-doc)
+ mkdir -p "$(DESTDIR)$(bindir)"
+ $(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)"
+ mkdir -p "$(DESTDIR)$(datadir)"
+ for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
+ video.x openbios-sparc32 linux_boot.bin pxe-ne2k_pci.bin \
+ pxe-rtl8139.bin pxe-pcnet.bin; do \
+ $(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
+ done
+ifndef CONFIG_WIN32
+ mkdir -p "$(DESTDIR)$(datadir)/keymaps"
+ for x in $(KEYMAPS); do \
+ $(INSTALL) -m 644 $(SRC_PATH)/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \
+ done
+endif
+ for d in $(TARGET_DIRS); do \
+ $(MAKE) -C $$d $@ || exit 1 ; \
+ done
+ for m in $(MODELS); do \
+ for n in *.$$m; do \
+ $(INSTALL) $$n "$(DESTDIR)$(bindir)"; \
+ done; \
+ done
+
+# various test targets
+test speed test2: all
+ $(MAKE) -C tests $@
+
+TAGS:
+ etags *.[ch] tests/*.[ch]
+
+cscope:
+ rm -f ./cscope.*
+ find . -name "*.[ch]" -print > ./cscope.files
+ cscope -b
+
+# documentation
+%.html: %.texi
+ texi2html -monolithic -number $<
+
+%.info: %.texi
+ makeinfo $< -o $@
+
+%.dvi: %.texi
+ texi2dvi $<
+
+qemu.1: qemu-doc.texi
+ $(SRC_PATH)/texi2pod.pl $< qemu.pod
+ pod2man --section=1 --center=" " --release=" " qemu.pod > $@
+
+qemu-img.1: qemu-img.texi
+ $(SRC_PATH)/texi2pod.pl $< qemu-img.pod
+ pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@
+
+info: qemu-doc.info qemu-tech.info
+
+dvi: qemu-doc.dvi qemu-tech.dvi
+
+html: qemu-doc.html qemu-tech.html
+
+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-system-mipsel \
+ $(bindir)/qemu-system-arm \
+ $(bindir)/qemu-i386 \
+ $(bindir)/qemu-arm \
+ $(bindir)/qemu-armeb \
+ $(bindir)/qemu-sparc \
+ $(bindir)/qemu-ppc \
+ $(bindir)/qemu-mips \
+ $(bindir)/qemu-mipsel \
+ $(bindir)/qemu-img \
+ $(datadir)/bios.bin \
+ $(datadir)/vgabios.bin \
+ $(datadir)/vgabios-cirrus.bin \
+ $(datadir)/ppc_rom.bin \
+ $(datadir)/video.x \
+ $(datadir)/openbios-sparc32 \
+ $(datadir)/linux_boot.bin \
+ $(docdir)/qemu-doc.html \
+ $(docdir)/qemu-tech.html \
+ $(mandir)/man1/qemu.1 $(mandir)/man1/qemu-img.1 )
+
+ifneq ($(wildcard .depend),)
+include .depend
+endif
Added: trunk/src/host/qemu-neo1973/Makefile.target
===================================================================
--- trunk/src/host/qemu-neo1973/Makefile.target 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/Makefile.target 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,571 @@
+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
+CPPFLAGS=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH)
+ifdef CONFIG_USER_ONLY
+VPATH+=:$(SRC_PATH)/linux-user
+CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH)
+endif
+BASE_CFLAGS=
+BASE_LDFLAGS=
+#CFLAGS+=-Werror
+LIBS=
+HELPER_CFLAGS=$(CFLAGS)
+DYNGEN=../dyngen$(EXESUF)
+# user emulator name
+TARGET_ARCH2=$(TARGET_ARCH)
+ifeq ($(TARGET_ARCH),arm)
+ ifeq ($(TARGET_WORDS_BIGENDIAN),yes)
+ TARGET_ARCH2=armeb
+ endif
+endif
+ifeq ($(TARGET_ARCH),sh4)
+ ifeq ($(TARGET_WORDS_BIGENDIAN),yes)
+ TARGET_ARCH2=sh4eb
+ endif
+endif
+ifeq ($(TARGET_ARCH),mips)
+ ifneq ($(TARGET_WORDS_BIGENDIAN),yes)
+ TARGET_ARCH2=mipsel
+ endif
+endif
+QEMU_USER=qemu-$(TARGET_ARCH2)
+# system emulator name
+ifdef CONFIG_SOFTMMU
+ifeq ($(TARGET_ARCH), i386)
+QEMU_SYSTEM=qemu$(EXESUF)
+else
+QEMU_SYSTEM=qemu-system-$(TARGET_ARCH2)$(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
+
+# We require -O2 to avoid the stack setup prologue in EXIT_TB
+OP_CFLAGS = -Wall -O2 -g -fno-strict-aliasing
+
+ifeq ($(ARCH),i386)
+HELPER_CFLAGS+=-fomit-frame-pointer
+OP_CFLAGS+=-mpreferred-stack-boundary=2 -fomit-frame-pointer
+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
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).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!
+BASE_LDFLAGS+=-Wl,-shared
+endif
+endif
+
+ifeq ($(ARCH),x86_64)
+HELPER_CFLAGS+=-fomit-frame-pointer
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
+endif
+
+ifeq ($(ARCH),ppc)
+CPPFLAGS+= -D__powerpc__
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
+endif
+
+ifeq ($(ARCH),s390)
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
+endif
+
+ifeq ($(ARCH),sparc)
+ifeq ($(CONFIG_SOLARIS),yes)
+BASE_CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3
+BASE_LDFLAGS+=-m32
+OP_CFLAGS+=-fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0
+else
+BASE_CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
+BASE_LDFLAGS+=-m32
+OP_CFLAGS+=-fno-delayed-branch -ffixed-i0
+HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
+# -static is used to avoid g1/g3 usage by the dynamic linker
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -static
+endif
+endif
+
+ifeq ($(ARCH),sparc64)
+BASE_CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
+BASE_LDFLAGS+=-m64
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
+OP_CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7 -fno-delayed-branch -ffixed-i0
+endif
+
+ifeq ($(ARCH),alpha)
+# -msmall-data is not used for OP_CFLAGS because we want two-instruction
+# relocations for the constant constructions
+# Ensure there's only a single GP
+BASE_CFLAGS+=-msmall-data
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
+endif
+
+ifeq ($(ARCH),ia64)
+BASE_CFLAGS+=-mno-sdata
+OP_CFLAGS+=-mno-sdata
+BASE_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/$(ARCH).ld
+endif
+
+ifeq ($(ARCH),arm)
+OP_CFLAGS+=-mno-sched-prolog -fno-omit-frame-pointer
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
+endif
+
+ifeq ($(ARCH),m68k)
+OP_CFLAGS+=-fomit-frame-pointer
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
+endif
+
+ifeq ($(ARCH),mips)
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).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)
+LIBS+=-lmx
+endif
+
+OP_CFLAGS+=$(OS_CFLAGS)
+
+#########################################################
+
+CPPFLAGS+=-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
+ifdef CONFIG_SOLARIS
+LIBS+=-lsocket -lnsl -lresolv
+endif
+
+# profiling code
+ifdef TARGET_GPROF
+BASE_LDFLAGS+=-p
+main.o: BASE_CFLAGS+=-p
+endif
+
+OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \
+ elfload.o linuxload.o
+ifdef TARGET_HAS_BFLT
+OBJS+= flatload.o
+endif
+
+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
+ifeq ($(TARGET_ARCH), m68k)
+OBJS+= m68k-sim.o m68k-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
+CPPFLAGS+=-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 helper.o
+endif
+
+ifeq ($(TARGET_BASE_ARCH), sh4)
+LIBOBJS+= op_helper.o helper.o
+endif
+
+ifeq ($(TARGET_BASE_ARCH), m68k)
+LIBOBJS+= 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 ($(findstring m68k, $(TARGET_ARCH) $(ARCH)),m68k)
+LIBOBJS+=m68k-dis.o
+endif
+ifeq ($(findstring sh4, $(TARGET_ARCH) $(ARCH)),sh4)
+LIBOBJS+=sh4-dis.o
+endif
+
+ifdef CONFIG_GDBSTUB
+OBJS+=gdbstub.o
+endif
+
+all: $(PROGS)
+
+$(QEMU_USER): $(OBJS)
+ $(CC) $(LDFLAGS) $(BASE_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 readline.o monitor.o pci.o console.o loader.o isa_mmio.o
+VL_OBJS+=cutils.o
+VL_OBJS+=block.o block-raw.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 block-qcow2.o
+ifdef CONFIG_WIN32
+VL_OBJS+=tap-win32.o
+endif
+
+SOUND_HW = sb16.o es1370.o
+AUDIODRV = audio.o noaudio.o wavaudio.o mixeng.o
+ifdef CONFIG_SDL
+AUDIODRV += sdlaudio.o
+endif
+ifdef CONFIG_OSS
+AUDIODRV += ossaudio.o
+endif
+ifdef CONFIG_COREAUDIO
+AUDIODRV += coreaudio.o
+endif
+ifdef CONFIG_ALSA
+AUDIODRV += alsaaudio.o
+LIBS += -lasound
+endif
+ifdef CONFIG_DSOUND
+AUDIODRV += dsoundaudio.o
+LIBS += -lole32 -ldxguid
+endif
+ifdef CONFIG_FMOD
+AUDIODRV += fmodaudio.o
+audio.o fmodaudio.o: CPPFLAGS := -I$(CONFIG_FMOD_INC) $(CPPFLAGS)
+LIBS += $(CONFIG_FMOD_LIB)
+endif
+ifdef CONFIG_ADLIB
+SOUND_HW += fmopl.o adlib.o
+endif
+AUDIODRV+= wavcapture.o
+
+# SCSI layer
+VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o
+
+# USB layer
+VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o usb-net.o
+
+# PCI network cards
+VL_OBJS+= ne2000.o rtl8139.o pcnet.o
+
+ifeq ($(TARGET_BASE_ARCH), i386)
+# Hardware support
+VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
+VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
+VL_OBJS+= cirrus_vga.o apic.o parallel.o acpi.o piix_pci.o
+VL_OBJS+= usb-uhci.o
+CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
+endif
+ifeq ($(TARGET_BASE_ARCH), ppc)
+VL_OBJS+= ppc.o ide.o pckbd.o ps2.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
+VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o
+CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
+endif
+ifeq ($(TARGET_ARCH), mips)
+VL_OBJS+= mips_r4k.o mips_timer.o dma.o vga.o serial.o i8254.o i8259.o ide.o
+VL_OBJS+= mc146818rtc.o #pckbd.o fdc.o m48t59.o
+endif
+ifeq ($(TARGET_BASE_ARCH), sparc)
+ifeq ($(TARGET_ARCH), sparc64)
+VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o apb_pci.o
+VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o
+VL_OBJS+= cirrus_vga.o parallel.o
+else
+VL_OBJS+= sun4m.o tcx.o pcnet.o iommu.o m48t59.o slavio_intctl.o
+VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o sparc32_dma.o
+VL_OBJS+= cs4231.o
+endif
+endif
+ifeq ($(TARGET_BASE_ARCH), arm)
+VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o
+VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl190.o
+VL_OBJS+= versatile_pci.o
+VL_OBJS+= arm_gic.o realview.o arm_sysctl.o
+VL_OBJS+= pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o spitz.o
+VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o max7310.o
+VL_OBJS+= ads7846.o sd.o ide.o serial.o nand.o $(AUDIODRV) wm8750.o wm8753.o
+VL_OBJS+= s3c2410.o s3c24xx_gpio.o s3c24xx_lcd.o s3c24xx_mmci.o s3c24xx_rtc.o
+VL_OBJS+= neo1973.o pcf5060x.o jbt6k74.o
+CPPFLAGS += -DHAS_AUDIO -DHIGH_LATENCY
+endif
+ifeq ($(TARGET_BASE_ARCH), sh4)
+VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o
+endif
+ifdef CONFIG_GDBSTUB
+VL_OBJS+=gdbstub.o
+endif
+ifdef CONFIG_SDL
+VL_OBJS+=sdl.o
+endif
+VL_OBJS+=vnc.o
+ifdef CONFIG_COCOA
+VL_OBJS+=cocoa.o
+COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit
+ifdef CONFIG_COREAUDIO
+COCOA_LIBS+=-framework CoreAudio
+endif
+endif
+ifdef CONFIG_SLIRP
+CPPFLAGS+=-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=
+VL_LIBS=$(AIOLIBS)
+# 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
+ifndef CONFIG_SOLARIS
+VL_LIBS+=-lutil
+endif
+endif
+endif
+ifdef TARGET_GPROF
+vl.o: BASE_CFLAGS+=-p
+VL_LDFLAGS+=-p
+endif
+
+ifeq ($(ARCH),ia64)
+VL_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
+endif
+
+ifeq ($(ARCH),sparc64)
+VL_LDFLAGS+=-m64
+VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld
+endif
+
+ifdef CONFIG_WIN32
+SDL_LIBS := $(filter-out -mwindows, $(SDL_LIBS)) -mconsole
+endif
+
+$(QEMU_SYSTEM): $(VL_OBJS) libqemu.a
+ $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS)
+
+cocoa.o: cocoa.m
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
+
+sdl.o: sdl.c keymaps.c sdl_keysym.h
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $<
+
+vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
+
+sdlaudio.o: sdlaudio.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $<
+
+depend: $(SRCS)
+ $(CC) -MM $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $^ 1>.depend
+
+vldepend: $(VL_OBJS:.o=.c)
+ $(CC) -MM $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $^ 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) $(CPPFLAGS) -c -o $@ $<
+
+# HELPER_CFLAGS is used for all the code compiled with static register
+# variables
+ifeq ($(TARGET_BASE_ARCH), i386)
+# XXX: rename helper.c to op_helper.c
+helper.o: helper.c
+ $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
+else
+op_helper.o: op_helper.c
+ $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
+endif
+
+cpu-exec.o: cpu-exec.c
+ $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
+
+# Note: this is a workaround. The real fix is to avoid compiling
+# cpu_signal_handler() in cpu-exec.c.
+signal.o: signal.c
+ $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -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
+pl110.o: pl110_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
+
+loader.o: loader.c elf_ops.h
+
+ifeq ($(TARGET_ARCH), sh4)
+op.o: op.c op_mem.c cpu.h
+op_helper.o: op_helper.c exec.h cpu.h
+helper.o: helper.c exec.h cpu.h
+sh7750.o: sh7750.c sh7750_regs.h sh7750_regnames.h cpu.h
+shix.o: shix.c sh7750_regs.h sh7750_regnames.h
+sh7750_regnames.o: sh7750_regnames.c sh7750_regnames.h sh7750_regs.h
+tc58128.o: tc58128.c
+endif
+
+$(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h
+
+%.o: %.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
+
+%.o: %.S
+ $(CC) $(CPPFLAGS) -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) "$(DESTDIR)$(bindir)"
+endif
+
+ifneq ($(wildcard .depend),)
+include .depend
+endif
+
+ifeq (1, 0)
+audio.o sdlaudio.o dsoundaudio.o ossaudio.o wavaudio.o noaudio.o \
+fmodaudio.o alsaaudio.o mixeng.o sb16.o es1370.o gus.o adlib.o: \
+CFLAGS := $(CFLAGS) -Wall -Werror -W -Wsign-compare
+endif
Added: trunk/src/host/qemu-neo1973/README
===================================================================
--- trunk/src/host/qemu-neo1973/README 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/README 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,3 @@
+Read the documentation in qemu-doc.html.
+
+Fabrice Bellard.
\ No newline at end of file
Added: trunk/src/host/qemu-neo1973/README.distrib
===================================================================
--- trunk/src/host/qemu-neo1973/README.distrib 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/README.distrib 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,16 @@
+Information about the various packages used to build the current qemu
+x86 binary distribution:
+
+* gcc 2.95.2 was used for the build. A glibc 2.1.3 Debian distribution
+ was used to get most of the binary packages.
+
+* wine-20020411 tarball
+
+ ./configure --prefix=/usr/local/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
Added: trunk/src/host/qemu-neo1973/TODO
===================================================================
--- trunk/src/host/qemu-neo1973/TODO 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/TODO 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,55 @@
+short term:
+----------
+- cycle counter for all archs
+- cpu_interrupt() win32/SMP fix
+- support variable tsc freq
+- USB host async
+- IDE async
+- debug option in 'configure' script + disable -fomit-frame-pointer
+- Precise VGA timings for old games/demos (malc patch)
+- merge PIC spurious interrupt patch
+- warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?)
+- config file (at least for windows/Mac OS X)
+- update doc: PCI infos.
+- basic VGA optimizations
+- better code fetch (different exception handling + CS.limit support)
+- do not resize vga if invalid size.
+- avoid looping if only exceptions
+- 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()).
+
+ppc specific:
+------------
+- TLB invalidate not needed if msr_pr changes
+- enable shift optimizations ?
+
+linux-user specific:
+-------------------
+- add IPC syscalls
+- handle rare page fault cases (in particular if page fault in helpers or
+ in syscall emulation code).
+- 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.
+- fix thread stack freeing (use kernel 2.5.x CLONE_CHILD_CLEARTID)
+- use kernel traps for unaligned accesses on ARM ?
+
+
+lower priority:
+--------------
+- 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)
+- use -msoft-float on ARM
Added: trunk/src/host/qemu-neo1973/VERSION
===================================================================
--- trunk/src/host/qemu-neo1973/VERSION 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/VERSION 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1 @@
+0.8.2
\ No newline at end of file
Added: trunk/src/host/qemu-neo1973/a.out.h
===================================================================
--- trunk/src/host/qemu-neo1973/a.out.h 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/a.out.h 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,431 @@
+/* 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_ */
+
Added: trunk/src/host/qemu-neo1973/aes.c
===================================================================
--- trunk/src/host/qemu-neo1973/aes.c 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/aes.c 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,1317 @@
+/**
+ *
+ * aes.c - integrated in QEMU by Fabrice Bellard from the OpenSSL project.
+ */
+/*
+ * rijndael-alg-fst.c
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen at esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers at esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto at terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "vl.h"
+#include "aes.h"
+
+#define NDEBUG
+#include <assert.h>
+
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+
+#define MAXKC (256/32)
+#define MAXKB (256/8)
+#define MAXNR 14
+
+/* This controls loop-unrolling in aes_core.c */
+#undef FULL_UNROLL
+# define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
+# define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); }
+
+/*
+Te0[x] = S [x].[02, 01, 01, 03];
+Te1[x] = S [x].[03, 02, 01, 01];
+Te2[x] = S [x].[01, 03, 02, 01];
+Te3[x] = S [x].[01, 01, 03, 02];
+Te4[x] = S [x].[01, 01, 01, 01];
+
+Td0[x] = Si[x].[0e, 09, 0d, 0b];
+Td1[x] = Si[x].[0b, 0e, 09, 0d];
+Td2[x] = Si[x].[0d, 0b, 0e, 09];
+Td3[x] = Si[x].[09, 0d, 0b, 0e];
+Td4[x] = Si[x].[01, 01, 01, 01];
+*/
+
+static const u32 Te0[256] = {
+ 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
+ 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
+ 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
+ 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
+ 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
+ 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
+ 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
+ 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
+ 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
+ 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
+ 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
+ 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
+ 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
+ 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
+ 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
+ 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
+ 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
+ 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
+ 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
+ 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
+ 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
+ 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
+ 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
+ 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
+ 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
+ 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
+ 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
+ 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
+ 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
+ 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
+ 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
+ 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
+ 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
+ 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
+ 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
+ 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
+ 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
+ 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
+ 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
+ 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
+ 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
+ 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
+ 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
+ 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
+ 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
+ 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
+ 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
+ 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
+ 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
+ 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
+ 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
+ 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
+ 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
+ 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
+ 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
+ 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
+ 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
+ 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
+ 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
+ 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
+ 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
+ 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
+ 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
+ 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
+};
+static const u32 Te1[256] = {
+ 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
+ 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
+ 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
+ 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
+ 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
+ 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
+ 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
+ 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
+ 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
+ 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
+ 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
+ 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
+ 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
+ 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
+ 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
+ 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
+ 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
+ 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
+ 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
+ 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
+ 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
+ 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
+ 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
+ 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
+ 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
+ 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
+ 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
+ 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
+ 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
+ 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
+ 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
+ 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
+ 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
+ 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
+ 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
+ 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
+ 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
+ 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
+ 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
+ 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
+ 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
+ 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
+ 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
+ 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
+ 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
+ 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
+ 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
+ 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
+ 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
+ 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
+ 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
+ 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
+ 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
+ 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
+ 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
+ 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
+ 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
+ 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
+ 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
+ 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
+ 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
+ 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
+ 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
+ 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
+};
+static const u32 Te2[256] = {
+ 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
+ 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
+ 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
+ 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
+ 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
+ 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
+ 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
+ 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
+ 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
+ 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
+ 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
+ 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
+ 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
+ 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
+ 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
+ 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
+ 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
+ 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
+ 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
+ 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
+ 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
+ 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
+ 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
+ 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
+ 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
+ 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
+ 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
+ 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
+ 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
+ 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
+ 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
+ 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
+ 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
+ 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
+ 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
+ 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
+ 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
+ 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
+ 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
+ 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
+ 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
+ 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
+ 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
+ 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
+ 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
+ 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
+ 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
+ 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
+ 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
+ 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
+ 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
+ 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
+ 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
+ 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
+ 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
+ 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
+ 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
+ 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
+ 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
+ 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
+ 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
+ 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
+ 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
+ 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
+};
+static const u32 Te3[256] = {
+
+ 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
+ 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
+ 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
+ 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
+ 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
+ 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
+ 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
+ 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
+ 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
+ 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
+ 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
+ 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
+ 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
+ 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
+ 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
+ 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
+ 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
+ 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
+ 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
+ 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
+ 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
+ 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
+ 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
+ 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
+ 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
+ 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
+ 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
+ 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
+ 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
+ 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
+ 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
+ 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
+ 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
+ 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
+ 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
+ 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
+ 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
+ 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
+ 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
+ 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
+ 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
+ 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
+ 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
+ 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
+ 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
+ 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
+ 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
+ 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
+ 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
+ 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
+ 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
+ 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
+ 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
+ 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
+ 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
+ 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
+ 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
+ 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
+ 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
+ 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
+ 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
+ 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
+ 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
+ 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
+};
+static const u32 Te4[256] = {
+ 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
+ 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
+ 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
+ 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
+ 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
+ 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
+ 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
+ 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
+ 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
+ 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
+ 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
+ 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
+ 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
+ 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
+ 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
+ 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
+ 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
+ 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
+ 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
+ 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
+ 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
+ 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
+ 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
+ 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
+ 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
+ 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
+ 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
+ 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
+ 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
+ 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
+ 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
+ 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
+ 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
+ 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
+ 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
+ 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
+ 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
+ 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
+ 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
+ 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
+ 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
+ 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
+ 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
+ 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
+ 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
+ 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
+ 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
+ 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
+ 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
+ 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
+ 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
+ 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
+ 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
+ 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
+ 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
+ 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
+ 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
+ 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
+ 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
+ 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
+ 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
+ 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
+ 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
+ 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
+};
+static const u32 Td0[256] = {
+ 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
+ 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
+ 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
+ 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
+ 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
+ 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
+ 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
+ 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
+ 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
+ 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
+ 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
+ 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
+ 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
+ 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
+ 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
+ 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
+ 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
+ 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
+ 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
+ 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
+ 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
+ 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
+ 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
+ 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
+ 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
+ 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
+ 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
+ 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
+ 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
+ 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
+ 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
+ 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
+ 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
+ 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
+ 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
+ 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
+ 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
+ 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
+ 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
+ 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
+ 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
+ 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
+ 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
+ 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
+ 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
+ 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
+ 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
+ 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
+ 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
+ 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
+ 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
+ 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
+ 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
+ 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
+ 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
+ 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
+ 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
+ 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
+ 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
+ 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
+ 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
+ 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
+ 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
+ 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
+};
+static const u32 Td1[256] = {
+ 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
+ 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
+ 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
+ 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
+ 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
+ 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
+ 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
+ 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
+ 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
+ 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
+ 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
+ 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
+ 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
+ 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
+ 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
+ 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
+ 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
+ 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
+ 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
+ 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
+ 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
+ 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
+ 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
+ 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
+ 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
+ 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
+ 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
+ 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
+ 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
+ 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
+ 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
+ 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
+ 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
+ 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
+ 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
+ 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
+ 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
+ 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
+ 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
+ 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
+ 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
+ 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
+ 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
+ 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
+ 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
+ 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
+ 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
+ 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
+ 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
+ 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
+ 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
+ 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
+ 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
+ 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
+ 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
+ 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
+ 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
+ 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
+ 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
+ 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
+ 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
+ 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
+ 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
+ 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
+};
+static const u32 Td2[256] = {
+ 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
+ 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
+ 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
+ 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
+ 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
+ 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
+ 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
+ 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
+ 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
+ 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
+ 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
+ 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
+ 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
+ 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
+ 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
+ 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
+ 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
+ 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
+ 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
+ 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
+
+ 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
+ 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
+ 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
+ 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
+ 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
+ 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
+ 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
+ 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
+ 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
+ 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
+ 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
+ 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
+ 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
+ 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
+ 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
+ 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
+ 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
+ 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
+ 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
+ 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
+ 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
+ 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
+ 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
+ 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
+ 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
+ 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
+ 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
+ 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
+ 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
+ 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
+ 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
+ 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
+ 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
+ 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
+ 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
+ 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
+ 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
+ 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
+ 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
+ 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
+ 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
+ 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
+ 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
+ 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
+};
+static const u32 Td3[256] = {
+ 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
+ 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
+ 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
+ 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
+ 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
+ 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
+ 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
+ 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
+ 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
+ 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
+ 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
+ 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
+ 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
+ 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
+ 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
+ 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
+ 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
+ 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
+ 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
+ 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
+ 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
+ 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
+ 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
+ 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
+ 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
+ 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
+ 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
+ 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
+ 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
+ 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
+ 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
+ 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
+ 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
+ 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
+ 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
+ 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
+ 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
+ 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
+ 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
+ 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
+ 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
+ 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
+ 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
+ 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
+ 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
+ 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
+ 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
+ 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
+ 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
+ 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
+ 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
+ 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
+ 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
+ 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
+ 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
+ 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
+ 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
+ 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
+ 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
+ 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
+ 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
+ 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
+ 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
+ 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
+};
+static const u32 Td4[256] = {
+ 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
+ 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
+ 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
+ 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU,
+ 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U,
+ 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U,
+ 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U,
+ 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU,
+ 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U,
+ 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU,
+ 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU,
+ 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU,
+ 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U,
+ 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U,
+ 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U,
+ 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U,
+ 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U,
+ 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U,
+ 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU,
+ 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U,
+ 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U,
+ 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU,
+ 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U,
+ 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U,
+ 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U,
+ 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU,
+ 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U,
+ 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U,
+ 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU,
+ 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U,
+ 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U,
+ 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU,
+ 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U,
+ 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU,
+ 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU,
+ 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U,
+ 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U,
+ 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U,
+ 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U,
+ 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU,
+ 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U,
+ 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U,
+ 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU,
+ 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU,
+ 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU,
+ 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U,
+ 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU,
+ 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U,
+ 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U,
+ 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U,
+ 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U,
+ 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU,
+ 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U,
+ 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU,
+ 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU,
+ 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU,
+ 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU,
+ 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U,
+ 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU,
+ 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U,
+ 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU,
+ 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U,
+ 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
+ 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU,
+};
+static const u32 rcon[] = {
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000,
+ 0x10000000, 0x20000000, 0x40000000, 0x80000000,
+ 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+
+/**
+ * Expand the cipher key into the encryption key schedule.
+ */
+int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
+ AES_KEY *key) {
+
+ u32 *rk;
+ int i = 0;
+ u32 temp;
+
+ if (!userKey || !key)
+ return -1;
+ if (bits != 128 && bits != 192 && bits != 256)
+ return -2;
+
+ rk = key->rd_key;
+
+ if (bits==128)
+ key->rounds = 10;
+ else if (bits==192)
+ key->rounds = 12;
+ else
+ key->rounds = 14;
+
+ rk[0] = GETU32(userKey );
+ rk[1] = GETU32(userKey + 4);
+ rk[2] = GETU32(userKey + 8);
+ rk[3] = GETU32(userKey + 12);
+ if (bits == 128) {
+ while (1) {
+ temp = rk[3];
+ rk[4] = rk[0] ^
+ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
+ (Te4[(temp ) & 0xff] & 0x0000ff00) ^
+ (Te4[(temp >> 24) ] & 0x000000ff) ^
+ rcon[i];
+ rk[5] = rk[1] ^ rk[4];
+ rk[6] = rk[2] ^ rk[5];
+ rk[7] = rk[3] ^ rk[6];
+ if (++i == 10) {
+ return 0;
+ }
+ rk += 4;
+ }
+ }
+ rk[4] = GETU32(userKey + 16);
+ rk[5] = GETU32(userKey + 20);
+ if (bits == 192) {
+ while (1) {
+ temp = rk[ 5];
+ rk[ 6] = rk[ 0] ^
+ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
+ (Te4[(temp ) & 0xff] & 0x0000ff00) ^
+ (Te4[(temp >> 24) ] & 0x000000ff) ^
+ rcon[i];
+ rk[ 7] = rk[ 1] ^ rk[ 6];
+ rk[ 8] = rk[ 2] ^ rk[ 7];
+ rk[ 9] = rk[ 3] ^ rk[ 8];
+ if (++i == 8) {
+ return 0;
+ }
+ rk[10] = rk[ 4] ^ rk[ 9];
+ rk[11] = rk[ 5] ^ rk[10];
+ rk += 6;
+ }
+ }
+ rk[6] = GETU32(userKey + 24);
+ rk[7] = GETU32(userKey + 28);
+ if (bits == 256) {
+ while (1) {
+ temp = rk[ 7];
+ rk[ 8] = rk[ 0] ^
+ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
+ (Te4[(temp ) & 0xff] & 0x0000ff00) ^
+ (Te4[(temp >> 24) ] & 0x000000ff) ^
+ rcon[i];
+ rk[ 9] = rk[ 1] ^ rk[ 8];
+ rk[10] = rk[ 2] ^ rk[ 9];
+ rk[11] = rk[ 3] ^ rk[10];
+ if (++i == 7) {
+ return 0;
+ }
+ temp = rk[11];
+ rk[12] = rk[ 4] ^
+ (Te4[(temp >> 24) ] & 0xff000000) ^
+ (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(temp ) & 0xff] & 0x000000ff);
+ rk[13] = rk[ 5] ^ rk[12];
+ rk[14] = rk[ 6] ^ rk[13];
+ rk[15] = rk[ 7] ^ rk[14];
+
+ rk += 8;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Expand the cipher key into the decryption key schedule.
+ */
+int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
+ AES_KEY *key) {
+
+ u32 *rk;
+ int i, j, status;
+ u32 temp;
+
+ /* first, start with an encryption schedule */
+ status = AES_set_encrypt_key(userKey, bits, key);
+ if (status < 0)
+ return status;
+
+ rk = key->rd_key;
+
+ /* invert the order of the round keys: */
+ for (i = 0, j = 4*(key->rounds); i < j; i += 4, j -= 4) {
+ temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp;
+ temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
+ temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
+ temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
+ }
+ /* apply the inverse MixColumn transform to all round keys but the first and the last: */
+ for (i = 1; i < (key->rounds); i++) {
+ rk += 4;
+ rk[0] =
+ Td0[Te4[(rk[0] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[0] ) & 0xff] & 0xff];
+ rk[1] =
+ Td0[Te4[(rk[1] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[1] ) & 0xff] & 0xff];
+ rk[2] =
+ Td0[Te4[(rk[2] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[2] ) & 0xff] & 0xff];
+ rk[3] =
+ Td0[Te4[(rk[3] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[3] ) & 0xff] & 0xff];
+ }
+ return 0;
+}
+
+#ifndef AES_ASM
+/*
+ * Encrypt a single block
+ * in and out can overlap
+ */
+void AES_encrypt(const unsigned char *in, unsigned char *out,
+ const AES_KEY *key) {
+
+ const u32 *rk;
+ u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+ int r;
+#endif /* ?FULL_UNROLL */
+
+ assert(in && out && key);
+ rk = key->rd_key;
+
+ /*
+ * map byte array block to cipher state
+ * and add initial round key:
+ */
+ s0 = GETU32(in ) ^ rk[0];
+ s1 = GETU32(in + 4) ^ rk[1];
+ s2 = GETU32(in + 8) ^ rk[2];
+ s3 = GETU32(in + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+ /* round 1: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
+ /* round 2: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
+ /* round 3: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
+ /* round 4: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
+ /* round 5: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
+ /* round 6: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
+ /* round 7: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
+ /* round 8: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
+ /* round 9: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
+ if (key->rounds > 10) {
+ /* round 10: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43];
+ /* round 11: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47];
+ if (key->rounds > 12) {
+ /* round 12: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51];
+ /* round 13: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55];
+ }
+ }
+ rk += key->rounds << 2;
+#else /* !FULL_UNROLL */
+ /*
+ * Nr - 1 full rounds:
+ */
+ r = key->rounds >> 1;
+ for (;;) {
+ t0 =
+ Te0[(s0 >> 24) ] ^
+ Te1[(s1 >> 16) & 0xff] ^
+ Te2[(s2 >> 8) & 0xff] ^
+ Te3[(s3 ) & 0xff] ^
+ rk[4];
+ t1 =
+ Te0[(s1 >> 24) ] ^
+ Te1[(s2 >> 16) & 0xff] ^
+ Te2[(s3 >> 8) & 0xff] ^
+ Te3[(s0 ) & 0xff] ^
+ rk[5];
+ t2 =
+ Te0[(s2 >> 24) ] ^
+ Te1[(s3 >> 16) & 0xff] ^
+ Te2[(s0 >> 8) & 0xff] ^
+ Te3[(s1 ) & 0xff] ^
+ rk[6];
+ t3 =
+ Te0[(s3 >> 24) ] ^
+ Te1[(s0 >> 16) & 0xff] ^
+ Te2[(s1 >> 8) & 0xff] ^
+ Te3[(s2 ) & 0xff] ^
+ rk[7];
+
+ rk += 8;
+ if (--r == 0) {
+ break;
+ }
+
+ s0 =
+ Te0[(t0 >> 24) ] ^
+ Te1[(t1 >> 16) & 0xff] ^
+ Te2[(t2 >> 8) & 0xff] ^
+ Te3[(t3 ) & 0xff] ^
+ rk[0];
+ s1 =
+ Te0[(t1 >> 24) ] ^
+ Te1[(t2 >> 16) & 0xff] ^
+ Te2[(t3 >> 8) & 0xff] ^
+ Te3[(t0 ) & 0xff] ^
+ rk[1];
+ s2 =
+ Te0[(t2 >> 24) ] ^
+ Te1[(t3 >> 16) & 0xff] ^
+ Te2[(t0 >> 8) & 0xff] ^
+ Te3[(t1 ) & 0xff] ^
+ rk[2];
+ s3 =
+ Te0[(t3 >> 24) ] ^
+ Te1[(t0 >> 16) & 0xff] ^
+ Te2[(t1 >> 8) & 0xff] ^
+ Te3[(t2 ) & 0xff] ^
+ rk[3];
+ }
+#endif /* ?FULL_UNROLL */
+ /*
+ * apply last round and
+ * map cipher state to byte array block:
+ */
+ s0 =
+ (Te4[(t0 >> 24) ] & 0xff000000) ^
+ (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t3 ) & 0xff] & 0x000000ff) ^
+ rk[0];
+ PUTU32(out , s0);
+ s1 =
+ (Te4[(t1 >> 24) ] & 0xff000000) ^
+ (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t0 ) & 0xff] & 0x000000ff) ^
+ rk[1];
+ PUTU32(out + 4, s1);
+ s2 =
+ (Te4[(t2 >> 24) ] & 0xff000000) ^
+ (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t1 ) & 0xff] & 0x000000ff) ^
+ rk[2];
+ PUTU32(out + 8, s2);
+ s3 =
+ (Te4[(t3 >> 24) ] & 0xff000000) ^
+ (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t2 ) & 0xff] & 0x000000ff) ^
+ rk[3];
+ PUTU32(out + 12, s3);
+}
+
+/*
+ * Decrypt a single block
+ * in and out can overlap
+ */
+void AES_decrypt(const unsigned char *in, unsigned char *out,
+ const AES_KEY *key) {
+
+ const u32 *rk;
+ u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+ int r;
+#endif /* ?FULL_UNROLL */
+
+ assert(in && out && key);
+ rk = key->rd_key;
+
+ /*
+ * map byte array block to cipher state
+ * and add initial round key:
+ */
+ s0 = GETU32(in ) ^ rk[0];
+ s1 = GETU32(in + 4) ^ rk[1];
+ s2 = GETU32(in + 8) ^ rk[2];
+ s3 = GETU32(in + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+ /* round 1: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7];
+ /* round 2: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11];
+ /* round 3: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15];
+ /* round 4: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19];
+ /* round 5: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23];
+ /* round 6: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27];
+ /* round 7: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31];
+ /* round 8: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35];
+ /* round 9: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39];
+ if (key->rounds > 10) {
+ /* round 10: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43];
+ /* round 11: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47];
+ if (key->rounds > 12) {
+ /* round 12: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51];
+ /* round 13: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55];
+ }
+ }
+ rk += key->rounds << 2;
+#else /* !FULL_UNROLL */
+ /*
+ * Nr - 1 full rounds:
+ */
+ r = key->rounds >> 1;
+ for (;;) {
+ t0 =
+ Td0[(s0 >> 24) ] ^
+ Td1[(s3 >> 16) & 0xff] ^
+ Td2[(s2 >> 8) & 0xff] ^
+ Td3[(s1 ) & 0xff] ^
+ rk[4];
+ t1 =
+ Td0[(s1 >> 24) ] ^
+ Td1[(s0 >> 16) & 0xff] ^
+ Td2[(s3 >> 8) & 0xff] ^
+ Td3[(s2 ) & 0xff] ^
+ rk[5];
+ t2 =
+ Td0[(s2 >> 24) ] ^
+ Td1[(s1 >> 16) & 0xff] ^
+ Td2[(s0 >> 8) & 0xff] ^
+ Td3[(s3 ) & 0xff] ^
+ rk[6];
+ t3 =
+ Td0[(s3 >> 24) ] ^
+ Td1[(s2 >> 16) & 0xff] ^
+ Td2[(s1 >> 8) & 0xff] ^
+ Td3[(s0 ) & 0xff] ^
+ rk[7];
+
+ rk += 8;
+ if (--r == 0) {
+ break;
+ }
+
+ s0 =
+ Td0[(t0 >> 24) ] ^
+ Td1[(t3 >> 16) & 0xff] ^
+ Td2[(t2 >> 8) & 0xff] ^
+ Td3[(t1 ) & 0xff] ^
+ rk[0];
+ s1 =
+ Td0[(t1 >> 24) ] ^
+ Td1[(t0 >> 16) & 0xff] ^
+ Td2[(t3 >> 8) & 0xff] ^
+ Td3[(t2 ) & 0xff] ^
+ rk[1];
+ s2 =
+ Td0[(t2 >> 24) ] ^
+ Td1[(t1 >> 16) & 0xff] ^
+ Td2[(t0 >> 8) & 0xff] ^
+ Td3[(t3 ) & 0xff] ^
+ rk[2];
+ s3 =
+ Td0[(t3 >> 24) ] ^
+ Td1[(t2 >> 16) & 0xff] ^
+ Td2[(t1 >> 8) & 0xff] ^
+ Td3[(t0 ) & 0xff] ^
+ rk[3];
+ }
+#endif /* ?FULL_UNROLL */
+ /*
+ * apply last round and
+ * map cipher state to byte array block:
+ */
+ s0 =
+ (Td4[(t0 >> 24) ] & 0xff000000) ^
+ (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t1 ) & 0xff] & 0x000000ff) ^
+ rk[0];
+ PUTU32(out , s0);
+ s1 =
+ (Td4[(t1 >> 24) ] & 0xff000000) ^
+ (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t2 ) & 0xff] & 0x000000ff) ^
+ rk[1];
+ PUTU32(out + 4, s1);
+ s2 =
+ (Td4[(t2 >> 24) ] & 0xff000000) ^
+ (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t3 ) & 0xff] & 0x000000ff) ^
+ rk[2];
+ PUTU32(out + 8, s2);
+ s3 =
+ (Td4[(t3 >> 24) ] & 0xff000000) ^
+ (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t0 ) & 0xff] & 0x000000ff) ^
+ rk[3];
+ PUTU32(out + 12, s3);
+}
+
+#endif /* AES_ASM */
+
+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)
+{
+
+ unsigned long n;
+ unsigned long len = length;
+ unsigned char tmp[AES_BLOCK_SIZE];
+
+ assert(in && out && key && ivec);
+
+ if (enc) {
+ while (len >= AES_BLOCK_SIZE) {
+ for(n=0; n < AES_BLOCK_SIZE; ++n)
+ tmp[n] = in[n] ^ ivec[n];
+ AES_encrypt(tmp, out, key);
+ memcpy(ivec, out, AES_BLOCK_SIZE);
+ len -= AES_BLOCK_SIZE;
+ in += AES_BLOCK_SIZE;
+ out += AES_BLOCK_SIZE;
+ }
+ if (len) {
+ for(n=0; n < len; ++n)
+ tmp[n] = in[n] ^ ivec[n];
+ for(n=len; n < AES_BLOCK_SIZE; ++n)
+ tmp[n] = ivec[n];
+ AES_encrypt(tmp, tmp, key);
+ memcpy(out, tmp, AES_BLOCK_SIZE);
+ memcpy(ivec, tmp, AES_BLOCK_SIZE);
+ }
+ } else {
+ while (len >= AES_BLOCK_SIZE) {
+ memcpy(tmp, in, AES_BLOCK_SIZE);
+ AES_decrypt(in, out, key);
+ for(n=0; n < AES_BLOCK_SIZE; ++n)
+ out[n] ^= ivec[n];
+ memcpy(ivec, tmp, AES_BLOCK_SIZE);
+ len -= AES_BLOCK_SIZE;
+ in += AES_BLOCK_SIZE;
+ out += AES_BLOCK_SIZE;
+ }
+ if (len) {
+ memcpy(tmp, in, AES_BLOCK_SIZE);
+ AES_decrypt(tmp, tmp, key);
+ for(n=0; n < len; ++n)
+ out[n] = tmp[n] ^ ivec[n];
+ memcpy(ivec, tmp, AES_BLOCK_SIZE);
+ }
+ }
+}
Added: trunk/src/host/qemu-neo1973/aes.h
===================================================================
--- trunk/src/host/qemu-neo1973/aes.h 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/aes.h 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,26 @@
+#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
Added: trunk/src/host/qemu-neo1973/alpha-dis.c
===================================================================
--- trunk/src/host/qemu-neo1973/alpha-dis.c 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/alpha-dis.c 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,1960 @@
+/* alpha-dis.c -- Disassemble Alpha AXP instructions
+ Copyright 1996, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ Contributed by Richard Henderson <rth at tamu.edu>,
+ patterned after the PPC opcode handling written by Ian Lance Taylor.
+
+This file is part of GDB, GAS, and the GNU binutils.
+
+GDB, GAS, and the GNU binutils are free software; you can redistribute
+them and/or modify them under the terms of the GNU General Public
+License as published by the Free Software Foundation; either version
+2, or (at your option) any later version.
+
+GDB, GAS, and the GNU binutils are distributed in the hope that they
+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 file; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include <stdio.h>
+#include "dis-asm.h"
+
+/* The opcode table is an array of struct alpha_opcode. */
+
+struct alpha_opcode
+{
+ /* The opcode name. */
+ const char *name;
+
+ /* The opcode itself. Those bits which will be filled in with
+ operands are zeroes. */
+ unsigned opcode;
+
+ /* The opcode mask. This is used by the disassembler. This is a
+ mask containing ones indicating those bits which must match the
+ opcode field, and zeroes indicating those bits which need not
+ match (and are presumably filled in by operands). */
+ unsigned mask;
+
+ /* One bit flags for the opcode. These are primarily used to
+ indicate specific processors and environments support the
+ instructions. The defined values are listed below. */
+ unsigned flags;
+
+ /* An array of operand codes. Each code is an index into the
+ operand table. They appear in the order which the operands must
+ appear in assembly code, and are terminated by a zero. */
+ unsigned char operands[4];
+};
+
+/* The table itself is sorted by major opcode number, and is otherwise
+ in the order in which the disassembler should consider
+ instructions. */
+extern const struct alpha_opcode alpha_opcodes[];
+extern const unsigned alpha_num_opcodes;
+
+/* Values defined for the flags field of a struct alpha_opcode. */
+
+/* CPU Availability */
+#define AXP_OPCODE_BASE 0x0001 /* Base architecture -- all cpus. */
+#define AXP_OPCODE_EV4 0x0002 /* EV4 specific PALcode insns. */
+#define AXP_OPCODE_EV5 0x0004 /* EV5 specific PALcode insns. */
+#define AXP_OPCODE_EV6 0x0008 /* EV6 specific PALcode insns. */
+#define AXP_OPCODE_BWX 0x0100 /* Byte/word extension (amask bit 0). */
+#define AXP_OPCODE_CIX 0x0200 /* "Count" extension (amask bit 1). */
+#define AXP_OPCODE_MAX 0x0400 /* Multimedia extension (amask bit 8). */
+
+#define AXP_OPCODE_NOPAL (~(AXP_OPCODE_EV4|AXP_OPCODE_EV5|AXP_OPCODE_EV6))
+
+/* A macro to extract the major opcode from an instruction. */
+#define AXP_OP(i) (((i) >> 26) & 0x3F)
+
+/* The total number of major opcodes. */
+#define AXP_NOPS 0x40
+
+
+/* The operands table is an array of struct alpha_operand. */
+
+struct alpha_operand
+{
+ /* The number of bits in the operand. */
+ unsigned int bits : 5;
+
+ /* How far the operand is left shifted in the instruction. */
+ unsigned int shift : 5;
+
+ /* The default relocation type for this operand. */
+ signed int default_reloc : 16;
+
+ /* One bit syntax flags. */
+ unsigned int flags : 16;
+
+ /* Insertion function. This is used by the assembler. To insert an
+ operand value into an instruction, check this field.
+
+ If it is NULL, execute
+ i |= (op & ((1 << o->bits) - 1)) << o->shift;
+ (i is the instruction which we are filling in, o is a pointer to
+ this structure, and op is the opcode value; this assumes twos
+ complement arithmetic).
+
+ If this field is not NULL, then simply call it with the
+ instruction and the operand value. It will return the new value
+ of the instruction. If the ERRMSG argument is not NULL, then if
+ the operand value is illegal, *ERRMSG will be set to a warning
+ string (the operand will be inserted in any case). If the
+ operand value is legal, *ERRMSG will be unchanged (most operands
+ can accept any value). */
+ unsigned (*insert) PARAMS ((unsigned instruction, int op,
+ const char **errmsg));
+
+ /* Extraction function. This is used by the disassembler. To
+ extract this operand type from an instruction, check this field.
+
+ If it is NULL, compute
+ op = ((i) >> o->shift) & ((1 << o->bits) - 1);
+ if ((o->flags & AXP_OPERAND_SIGNED) != 0
+ && (op & (1 << (o->bits - 1))) != 0)
+ op -= 1 << o->bits;
+ (i is the instruction, o is a pointer to this structure, and op
+ is the result; this assumes twos complement arithmetic).
+
+ If this field is not NULL, then simply call it with the
+ instruction value. It will return the value of the operand. If
+ the INVALID argument is not NULL, *INVALID will be set to
+ non-zero if this operand type can not actually be extracted from
+ this operand (i.e., the instruction does not match). If the
+ operand is valid, *INVALID will not be changed. */
+ int (*extract) PARAMS ((unsigned instruction, int *invalid));
+};
+
+/* Elements in the table are retrieved by indexing with values from
+ the operands field of the alpha_opcodes table. */
+
+extern const struct alpha_operand alpha_operands[];
+extern const unsigned alpha_num_operands;
+
+/* Values defined for the flags field of a struct alpha_operand. */
+
+/* Mask for selecting the type for typecheck purposes */
+#define AXP_OPERAND_TYPECHECK_MASK \
+ (AXP_OPERAND_PARENS | AXP_OPERAND_COMMA | AXP_OPERAND_IR | \
+ AXP_OPERAND_FPR | AXP_OPERAND_RELATIVE | AXP_OPERAND_SIGNED | \
+ AXP_OPERAND_UNSIGNED)
+
+/* This operand does not actually exist in the assembler input. This
+ is used to support extended mnemonics, for which two operands fields
+ are identical. The assembler should call the insert function with
+ any op value. The disassembler should call the extract function,
+ ignore the return value, and check the value placed in the invalid
+ argument. */
+#define AXP_OPERAND_FAKE 01
+
+/* The operand should be wrapped in parentheses rather than separated
+ from the previous by a comma. This is used for the load and store
+ instructions which want their operands to look like "Ra,disp(Rb)". */
+#define AXP_OPERAND_PARENS 02
+
+/* Used in combination with PARENS, this supresses the supression of
+ the comma. This is used for "jmp Ra,(Rb),hint". */
+#define AXP_OPERAND_COMMA 04
+
+/* This operand names an integer register. */
+#define AXP_OPERAND_IR 010
+
+/* This operand names a floating point register. */
+#define AXP_OPERAND_FPR 020
+
+/* This operand is a relative branch displacement. The disassembler
+ prints these symbolically if possible. */
+#define AXP_OPERAND_RELATIVE 040
+
+/* This operand takes signed values. */
+#define AXP_OPERAND_SIGNED 0100
+
+/* This operand takes unsigned values. This exists primarily so that
+ a flags value of 0 can be treated as end-of-arguments. */
+#define AXP_OPERAND_UNSIGNED 0200
+
+/* Supress overflow detection on this field. This is used for hints. */
+#define AXP_OPERAND_NOOVERFLOW 0400
+
+/* Mask for optional argument default value. */
+#define AXP_OPERAND_OPTIONAL_MASK 07000
+
+/* This operand defaults to zero. This is used for jump hints. */
+#define AXP_OPERAND_DEFAULT_ZERO 01000
+
+/* This operand should default to the first (real) operand and is used
+ in conjunction with AXP_OPERAND_OPTIONAL. This allows
+ "and $0,3,$0" to be written as "and $0,3", etc. I don't like
+ it, but it's what DEC does. */
+#define AXP_OPERAND_DEFAULT_FIRST 02000
+
+/* Similarly, this operand should default to the second (real) operand.
+ This allows "negl $0" instead of "negl $0,$0". */
+#define AXP_OPERAND_DEFAULT_SECOND 04000
+
+
+/* Register common names */
+
+#define AXP_REG_V0 0
+#define AXP_REG_T0 1
+#define AXP_REG_T1 2
+#define AXP_REG_T2 3
+#define AXP_REG_T3 4
+#define AXP_REG_T4 5
+#define AXP_REG_T5 6
+#define AXP_REG_T6 7
+#define AXP_REG_T7 8
+#define AXP_REG_S0 9
+#define AXP_REG_S1 10
+#define AXP_REG_S2 11
+#define AXP_REG_S3 12
+#define AXP_REG_S4 13
+#define AXP_REG_S5 14
+#define AXP_REG_FP 15
+#define AXP_REG_A0 16
+#define AXP_REG_A1 17
+#define AXP_REG_A2 18
+#define AXP_REG_A3 19
+#define AXP_REG_A4 20
+#define AXP_REG_A5 21
+#define AXP_REG_T8 22
+#define AXP_REG_T9 23
+#define AXP_REG_T10 24
+#define AXP_REG_T11 25
+#define AXP_REG_RA 26
+#define AXP_REG_PV 27
+#define AXP_REG_T12 27
+#define AXP_REG_AT 28
+#define AXP_REG_GP 29
+#define AXP_REG_SP 30
+#define AXP_REG_ZERO 31
+
+#define bfd_mach_alpha_ev4 0x10
+#define bfd_mach_alpha_ev5 0x20
+#define bfd_mach_alpha_ev6 0x30
+
+enum bfd_reloc_code_real {
+ BFD_RELOC_23_PCREL_S2,
+ BFD_RELOC_ALPHA_HINT
+};
+
+/* This file holds the Alpha AXP opcode table. The opcode table includes
+ almost all of the extended instruction mnemonics. This permits the
+ disassembler to use them, and simplifies the assembler logic, at the
+ cost of increasing the table size. The table is strictly constant
+ data, so the compiler should be able to put it in the text segment.
+
+ This file also holds the operand table. All knowledge about inserting
+ and extracting operands from instructions is kept in this file.
+
+ The information for the base instruction set was compiled from the
+ _Alpha Architecture Handbook_, Digital Order Number EC-QD2KB-TE,
+ version 2.
+
+ The information for the post-ev5 architecture extensions BWX, CIX and
+ MAX came from version 3 of this same document, which is also available
+ on-line at http://ftp.digital.com/pub/Digital/info/semiconductor
+ /literature/alphahb2.pdf
+
+ The information for the EV4 PALcode instructions was compiled from
+ _DECchip 21064 and DECchip 21064A Alpha AXP Microprocessors Hardware
+ Reference Manual_, Digital Order Number EC-Q9ZUA-TE, preliminary
+ revision dated June 1994.
+
+ The information for the EV5 PALcode instructions was compiled from
+ _Alpha 21164 Microprocessor Hardware Reference Manual_, Digital
+ Order Number EC-QAEQB-TE, preliminary revision dated April 1995. */
+
+/* Local insertion and extraction functions */
+
+static unsigned insert_rba PARAMS((unsigned, int, const char **));
+static unsigned insert_rca PARAMS((unsigned, int, const char **));
+static unsigned insert_za PARAMS((unsigned, int, const char **));
+static unsigned insert_zb PARAMS((unsigned, int, const char **));
+static unsigned insert_zc PARAMS((unsigned, int, const char **));
+static unsigned insert_bdisp PARAMS((unsigned, int, const char **));
+static unsigned insert_jhint PARAMS((unsigned, int, const char **));
+static unsigned insert_ev6hwjhint PARAMS((unsigned, int, const char **));
+
+static int extract_rba PARAMS((unsigned, int *));
+static int extract_rca PARAMS((unsigned, int *));
+static int extract_za PARAMS((unsigned, int *));
+static int extract_zb PARAMS((unsigned, int *));
+static int extract_zc PARAMS((unsigned, int *));
+static int extract_bdisp PARAMS((unsigned, int *));
+static int extract_jhint PARAMS((unsigned, int *));
+static int extract_ev6hwjhint PARAMS((unsigned, int *));
+
+
+/* The operands table */
+
+const struct alpha_operand alpha_operands[] =
+{
+ /* The fields are bits, shift, insert, extract, flags */
+ /* The zero index is used to indicate end-of-list */
+#define UNUSED 0
+ { 0, 0, 0, 0, 0, 0 },
+
+ /* The plain integer register fields */
+#define RA (UNUSED + 1)
+ { 5, 21, 0, AXP_OPERAND_IR, 0, 0 },
+#define RB (RA + 1)
+ { 5, 16, 0, AXP_OPERAND_IR, 0, 0 },
+#define RC (RB + 1)
+ { 5, 0, 0, AXP_OPERAND_IR, 0, 0 },
+
+ /* The plain fp register fields */
+#define FA (RC + 1)
+ { 5, 21, 0, AXP_OPERAND_FPR, 0, 0 },
+#define FB (FA + 1)
+ { 5, 16, 0, AXP_OPERAND_FPR, 0, 0 },
+#define FC (FB + 1)
+ { 5, 0, 0, AXP_OPERAND_FPR, 0, 0 },
+
+ /* The integer registers when they are ZERO */
+#define ZA (FC + 1)
+ { 5, 21, 0, AXP_OPERAND_FAKE, insert_za, extract_za },
+#define ZB (ZA + 1)
+ { 5, 16, 0, AXP_OPERAND_FAKE, insert_zb, extract_zb },
+#define ZC (ZB + 1)
+ { 5, 0, 0, AXP_OPERAND_FAKE, insert_zc, extract_zc },
+
+ /* The RB field when it needs parentheses */
+#define PRB (ZC + 1)
+ { 5, 16, 0, AXP_OPERAND_IR|AXP_OPERAND_PARENS, 0, 0 },
+
+ /* The RB field when it needs parentheses _and_ a preceding comma */
+#define CPRB (PRB + 1)
+ { 5, 16, 0,
+ AXP_OPERAND_IR|AXP_OPERAND_PARENS|AXP_OPERAND_COMMA, 0, 0 },
+
+ /* The RB field when it must be the same as the RA field */
+#define RBA (CPRB + 1)
+ { 5, 16, 0, AXP_OPERAND_FAKE, insert_rba, extract_rba },
+
+ /* The RC field when it must be the same as the RB field */
+#define RCA (RBA + 1)
+ { 5, 0, 0, AXP_OPERAND_FAKE, insert_rca, extract_rca },
+
+ /* The RC field when it can *default* to RA */
+#define DRC1 (RCA + 1)
+ { 5, 0, 0,
+ AXP_OPERAND_IR|AXP_OPERAND_DEFAULT_FIRST, 0, 0 },
+
+ /* The RC field when it can *default* to RB */
+#define DRC2 (DRC1 + 1)
+ { 5, 0, 0,
+ AXP_OPERAND_IR|AXP_OPERAND_DEFAULT_SECOND, 0, 0 },
+
+ /* The FC field when it can *default* to RA */
+#define DFC1 (DRC2 + 1)
+ { 5, 0, 0,
+ AXP_OPERAND_FPR|AXP_OPERAND_DEFAULT_FIRST, 0, 0 },
+
+ /* The FC field when it can *default* to RB */
+#define DFC2 (DFC1 + 1)
+ { 5, 0, 0,
+ AXP_OPERAND_FPR|AXP_OPERAND_DEFAULT_SECOND, 0, 0 },
+
+ /* The unsigned 8-bit literal of Operate format insns */
+#define LIT (DFC2 + 1)
+ { 8, 13, -LIT, AXP_OPERAND_UNSIGNED, 0, 0 },
+
+ /* The signed 16-bit displacement of Memory format insns. From here
+ we can't tell what relocation should be used, so don't use a default. */
+#define MDISP (LIT + 1)
+ { 16, 0, -MDISP, AXP_OPERAND_SIGNED, 0, 0 },
+
+ /* The signed "23-bit" aligned displacement of Branch format insns */
+#define BDISP (MDISP + 1)
+ { 21, 0, BFD_RELOC_23_PCREL_S2,
+ AXP_OPERAND_RELATIVE, insert_bdisp, extract_bdisp },
+
+ /* The 26-bit PALcode function */
+#define PALFN (BDISP + 1)
+ { 26, 0, -PALFN, AXP_OPERAND_UNSIGNED, 0, 0 },
+
+ /* The optional signed "16-bit" aligned displacement of the JMP/JSR hint */
+#define JMPHINT (PALFN + 1)
+ { 14, 0, BFD_RELOC_ALPHA_HINT,
+ AXP_OPERAND_RELATIVE|AXP_OPERAND_DEFAULT_ZERO|AXP_OPERAND_NOOVERFLOW,
+ insert_jhint, extract_jhint },
+
+ /* The optional hint to RET/JSR_COROUTINE */
+#define RETHINT (JMPHINT + 1)
+ { 14, 0, -RETHINT,
+ AXP_OPERAND_UNSIGNED|AXP_OPERAND_DEFAULT_ZERO, 0, 0 },
+
+ /* The 12-bit displacement for the ev[46] hw_{ld,st} (pal1b/pal1f) insns */
+#define EV4HWDISP (RETHINT + 1)
+#define EV6HWDISP (EV4HWDISP)
+ { 12, 0, -EV4HWDISP, AXP_OPERAND_SIGNED, 0, 0 },
+
+ /* The 5-bit index for the ev4 hw_m[ft]pr (pal19/pal1d) insns */
+#define EV4HWINDEX (EV4HWDISP + 1)
+ { 5, 0, -EV4HWINDEX, AXP_OPERAND_UNSIGNED, 0, 0 },
+
+ /* The 8-bit index for the oddly unqualified hw_m[tf]pr insns
+ that occur in DEC PALcode. */
+#define EV4EXTHWINDEX (EV4HWINDEX + 1)
+ { 8, 0, -EV4EXTHWINDEX, AXP_OPERAND_UNSIGNED, 0, 0 },
+
+ /* The 10-bit displacement for the ev5 hw_{ld,st} (pal1b/pal1f) insns */
+#define EV5HWDISP (EV4EXTHWINDEX + 1)
+ { 10, 0, -EV5HWDISP, AXP_OPERAND_SIGNED, 0, 0 },
+
+ /* The 16-bit index for the ev5 hw_m[ft]pr (pal19/pal1d) insns */
+#define EV5HWINDEX (EV5HWDISP + 1)
+ { 16, 0, -EV5HWINDEX, AXP_OPERAND_UNSIGNED, 0, 0 },
+
+ /* The 16-bit combined index/scoreboard mask for the ev6
+ hw_m[ft]pr (pal19/pal1d) insns */
+#define EV6HWINDEX (EV5HWINDEX + 1)
+ { 16, 0, -EV6HWINDEX, AXP_OPERAND_UNSIGNED, 0, 0 },
+
+ /* The 13-bit branch hint for the ev6 hw_jmp/jsr (pal1e) insn */
+#define EV6HWJMPHINT (EV6HWINDEX+ 1)
+ { 8, 0, -EV6HWJMPHINT,
+ AXP_OPERAND_RELATIVE|AXP_OPERAND_DEFAULT_ZERO|AXP_OPERAND_NOOVERFLOW,
+ insert_ev6hwjhint, extract_ev6hwjhint }
+};
+
+const unsigned alpha_num_operands = sizeof(alpha_operands)/sizeof(*alpha_operands);
+
+/* The RB field when it is the same as the RA field in the same insn.
+ This operand is marked fake. The insertion function just copies
+ the RA field into the RB field, and the extraction function just
+ checks that the fields are the same. */
+
+/*ARGSUSED*/
+static unsigned
+insert_rba(insn, value, errmsg)
+ unsigned insn;
+ int value ATTRIBUTE_UNUSED;
+ const char **errmsg ATTRIBUTE_UNUSED;
+{
+ return insn | (((insn >> 21) & 0x1f) << 16);
+}
+
+static int
+extract_rba(insn, invalid)
+ unsigned insn;
+ int *invalid;
+{
+ if (invalid != (int *) NULL
+ && ((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f))
+ *invalid = 1;
+ return 0;
+}
+
+
+/* The same for the RC field */
+
+/*ARGSUSED*/
+static unsigned
+insert_rca(insn, value, errmsg)
+ unsigned insn;
+ int value ATTRIBUTE_UNUSED;
+ const char **errmsg ATTRIBUTE_UNUSED;
+{
+ return insn | ((insn >> 21) & 0x1f);
+}
+
+static int
+extract_rca(insn, invalid)
+ unsigned insn;
+ int *invalid;
+{
+ if (invalid != (int *) NULL
+ && ((insn >> 21) & 0x1f) != (insn & 0x1f))
+ *invalid = 1;
+ return 0;
+}
+
+
+/* Fake arguments in which the registers must be set to ZERO */
+
+/*ARGSUSED*/
+static unsigned
+insert_za(insn, value, errmsg)
+ unsigned insn;
+ int value ATTRIBUTE_UNUSED;
+ const char **errmsg ATTRIBUTE_UNUSED;
+{
+ return insn | (31 << 21);
+}
+
+static int
+extract_za(insn, invalid)
+ unsigned insn;
+ int *invalid;
+{
+ if (invalid != (int *) NULL && ((insn >> 21) & 0x1f) != 31)
+ *invalid = 1;
+ return 0;
+}
+
+/*ARGSUSED*/
+static unsigned
+insert_zb(insn, value, errmsg)
+ unsigned insn;
+ int value ATTRIBUTE_UNUSED;
+ const char **errmsg ATTRIBUTE_UNUSED;
+{
+ return insn | (31 << 16);
+}
+
+static int
+extract_zb(insn, invalid)
+ unsigned insn;
+ int *invalid;
+{
+ if (invalid != (int *) NULL && ((insn >> 16) & 0x1f) != 31)
+ *invalid = 1;
+ return 0;
+}
+
+/*ARGSUSED*/
+static unsigned
+insert_zc(insn, value, errmsg)
+ unsigned insn;
+ int value ATTRIBUTE_UNUSED;
+ const char **errmsg ATTRIBUTE_UNUSED;
+{
+ return insn | 31;
+}
+
+static int
+extract_zc(insn, invalid)
+ unsigned insn;
+ int *invalid;
+{
+ if (invalid != (int *) NULL && (insn & 0x1f) != 31)
+ *invalid = 1;
+ return 0;
+}
+
+
+/* The displacement field of a Branch format insn. */
+
+static unsigned
+insert_bdisp(insn, value, errmsg)
+ unsigned insn;
+ int value;
+ const char **errmsg;
+{
+ if (errmsg != (const char **)NULL && (value & 3))
+ *errmsg = _("branch operand unaligned");
+ return insn | ((value / 4) & 0x1FFFFF);
+}
+
+/*ARGSUSED*/
+static int
+extract_bdisp(insn, invalid)
+ unsigned insn;
+ int *invalid ATTRIBUTE_UNUSED;
+{
+ return 4 * (((insn & 0x1FFFFF) ^ 0x100000) - 0x100000);
+}
+
+
+/* The hint field of a JMP/JSR insn. */
+
+static unsigned
+insert_jhint(insn, value, errmsg)
+ unsigned insn;
+ int value;
+ const char **errmsg;
+{
+ if (errmsg != (const char **)NULL && (value & 3))
+ *errmsg = _("jump hint unaligned");
+ return insn | ((value / 4) & 0x3FFF);
+}
+
+/*ARGSUSED*/
+static int
+extract_jhint(insn, invalid)
+ unsigned insn;
+ int *invalid ATTRIBUTE_UNUSED;
+{
+ return 4 * (((insn & 0x3FFF) ^ 0x2000) - 0x2000);
+}
+
+/* The hint field of an EV6 HW_JMP/JSR insn. */
+
+static unsigned
+insert_ev6hwjhint(insn, value, errmsg)
+ unsigned insn;
+ int value;
+ const char **errmsg;
+{
+ if (errmsg != (const char **)NULL && (value & 3))
+ *errmsg = _("jump hint unaligned");
+ return insn | ((value / 4) & 0x1FFF);
+}
+
+/*ARGSUSED*/
+static int
+extract_ev6hwjhint(insn, invalid)
+ unsigned insn;
+ int *invalid ATTRIBUTE_UNUSED;
+{
+ return 4 * (((insn & 0x1FFF) ^ 0x1000) - 0x1000);
+}
+
+
+/* Macros used to form opcodes */
+
+/* The main opcode */
+#define OP(x) (((x) & 0x3F) << 26)
+#define OP_MASK 0xFC000000
+
+/* Branch format instructions */
+#define BRA_(oo) OP(oo)
+#define BRA_MASK OP_MASK
+#define BRA(oo) BRA_(oo), BRA_MASK
+
+/* Floating point format instructions */
+#define FP_(oo,fff) (OP(oo) | (((fff) & 0x7FF) << 5))
+#define FP_MASK (OP_MASK | 0xFFE0)
+#define FP(oo,fff) FP_(oo,fff), FP_MASK
+
+/* Memory format instructions */
+#define MEM_(oo) OP(oo)
+#define MEM_MASK OP_MASK
+#define MEM(oo) MEM_(oo), MEM_MASK
+
+/* Memory/Func Code format instructions */
+#define MFC_(oo,ffff) (OP(oo) | ((ffff) & 0xFFFF))
+#define MFC_MASK (OP_MASK | 0xFFFF)
+#define MFC(oo,ffff) MFC_(oo,ffff), MFC_MASK
+
+/* Memory/Branch format instructions */
+#define MBR_(oo,h) (OP(oo) | (((h) & 3) << 14))
+#define MBR_MASK (OP_MASK | 0xC000)
+#define MBR(oo,h) MBR_(oo,h), MBR_MASK
+
+/* Operate format instructions. The OPRL variant specifies a
+ literal second argument. */
+#define OPR_(oo,ff) (OP(oo) | (((ff) & 0x7F) << 5))
+#define OPRL_(oo,ff) (OPR_((oo),(ff)) | 0x1000)
+#define OPR_MASK (OP_MASK | 0x1FE0)
+#define OPR(oo,ff) OPR_(oo,ff), OPR_MASK
+#define OPRL(oo,ff) OPRL_(oo,ff), OPR_MASK
+
+/* Generic PALcode format instructions */
+#define PCD_(oo) OP(oo)
+#define PCD_MASK OP_MASK
+#define PCD(oo) PCD_(oo), PCD_MASK
+
+/* Specific PALcode instructions */
+#define SPCD_(oo,ffff) (OP(oo) | ((ffff) & 0x3FFFFFF))
+#define SPCD_MASK 0xFFFFFFFF
+#define SPCD(oo,ffff) SPCD_(oo,ffff), SPCD_MASK
+
+/* Hardware memory (hw_{ld,st}) instructions */
+#define EV4HWMEM_(oo,f) (OP(oo) | (((f) & 0xF) << 12))
+#define EV4HWMEM_MASK (OP_MASK | 0xF000)
+#define EV4HWMEM(oo,f) EV4HWMEM_(oo,f), EV4HWMEM_MASK
+
+#define EV5HWMEM_(oo,f) (OP(oo) | (((f) & 0x3F) << 10))
+#define EV5HWMEM_MASK (OP_MASK | 0xF800)
+#define EV5HWMEM(oo,f) EV5HWMEM_(oo,f), EV5HWMEM_MASK
+
+#define EV6HWMEM_(oo,f) (OP(oo) | (((f) & 0xF) << 12))
+#define EV6HWMEM_MASK (OP_MASK | 0xF000)
+#define EV6HWMEM(oo,f) EV6HWMEM_(oo,f), EV6HWMEM_MASK
+
+#define EV6HWMBR_(oo,h) (OP(oo) | (((h) & 7) << 13))
+#define EV6HWMBR_MASK (OP_MASK | 0xE000)
+#define EV6HWMBR(oo,h) EV6HWMBR_(oo,h), EV6HWMBR_MASK
+
+/* Abbreviations for instruction subsets. */
+#define BASE AXP_OPCODE_BASE
+#define EV4 AXP_OPCODE_EV4
+#define EV5 AXP_OPCODE_EV5
+#define EV6 AXP_OPCODE_EV6
+#define BWX AXP_OPCODE_BWX
+#define CIX AXP_OPCODE_CIX
+#define MAX AXP_OPCODE_MAX
+
+/* Common combinations of arguments */
+#define ARG_NONE { 0 }
+#define ARG_BRA { RA, BDISP }
+#define ARG_FBRA { FA, BDISP }
+#define ARG_FP { FA, FB, DFC1 }
+#define ARG_FPZ1 { ZA, FB, DFC1 }
+#define ARG_MEM { RA, MDISP, PRB }
+#define ARG_FMEM { FA, MDISP, PRB }
+#define ARG_OPR { RA, RB, DRC1 }
+#define ARG_OPRL { RA, LIT, DRC1 }
+#define ARG_OPRZ1 { ZA, RB, DRC1 }
+#define ARG_OPRLZ1 { ZA, LIT, RC }
+#define ARG_PCD { PALFN }
+#define ARG_EV4HWMEM { RA, EV4HWDISP, PRB }
+#define ARG_EV4HWMPR { RA, RBA, EV4HWINDEX }
+#define ARG_EV5HWMEM { RA, EV5HWDISP, PRB }
+#define ARG_EV6HWMEM { RA, EV6HWDISP, PRB }
+
+/* The opcode table.
+
+ The format of the opcode table is:
+
+ NAME OPCODE MASK { OPERANDS }
+
+ NAME is the name of the instruction.
+
+ OPCODE is the instruction opcode.
+
+ MASK is the opcode mask; this is used to tell the disassembler
+ which bits in the actual opcode must match OPCODE.
+
+ OPERANDS is the list of operands.
+
+ The preceding macros merge the text of the OPCODE and MASK fields.
+
+ The disassembler reads the table in order and prints the first
+ instruction which matches, so this table is sorted to put more
+ specific instructions before more general instructions.
+
+ Otherwise, it is sorted by major opcode and minor function code.
+
+ There are three classes of not-really-instructions in this table:
+
+ ALIAS is another name for another instruction. Some of
+ these come from the Architecture Handbook, some
+ come from the original gas opcode tables. In all
+ cases, the functionality of the opcode is unchanged.
+
+ PSEUDO a stylized code form endorsed by Chapter A.4 of the
+ Architecture Handbook.
+
+ EXTRA a stylized code form found in the original gas tables.
+
+ And two annotations:
+
+ EV56 BUT opcodes that are officially introduced as of the ev56,
+ but with defined results on previous implementations.
+
+ EV56 UNA opcodes that were introduced as of the ev56 with
+ presumably undefined results on previous implementations
+ that were not assigned to a particular extension.
+*/
+
+const struct alpha_opcode alpha_opcodes[] = {
+ { "halt", SPCD(0x00,0x0000), BASE, ARG_NONE },
+ { "draina", SPCD(0x00,0x0002), BASE, ARG_NONE },
+ { "bpt", SPCD(0x00,0x0080), BASE, ARG_NONE },
+ { "bugchk", SPCD(0x00,0x0081), BASE, ARG_NONE },
+ { "callsys", SPCD(0x00,0x0083), BASE, ARG_NONE },
+ { "chmk", SPCD(0x00,0x0083), BASE, ARG_NONE },
+ { "imb", SPCD(0x00,0x0086), BASE, ARG_NONE },
+ { "rduniq", SPCD(0x00,0x009e), BASE, ARG_NONE },
+ { "wruniq", SPCD(0x00,0x009f), BASE, ARG_NONE },
+ { "gentrap", SPCD(0x00,0x00aa), BASE, ARG_NONE },
+ { "call_pal", PCD(0x00), BASE, ARG_PCD },
+ { "pal", PCD(0x00), BASE, ARG_PCD }, /* alias */
+
+ { "lda", MEM(0x08), BASE, { RA, MDISP, ZB } }, /* pseudo */
+ { "lda", MEM(0x08), BASE, ARG_MEM },
+ { "ldah", MEM(0x09), BASE, { RA, MDISP, ZB } }, /* pseudo */
+ { "ldah", MEM(0x09), BASE, ARG_MEM },
+ { "ldbu", MEM(0x0A), BWX, ARG_MEM },
+ { "unop", MEM_(0x0B) | (30 << 16),
+ MEM_MASK, BASE, { ZA } }, /* pseudo */
+ { "ldq_u", MEM(0x0B), BASE, ARG_MEM },
+ { "ldwu", MEM(0x0C), BWX, ARG_MEM },
+ { "stw", MEM(0x0D), BWX, ARG_MEM },
+ { "stb", MEM(0x0E), BWX, ARG_MEM },
+ { "stq_u", MEM(0x0F), BASE, ARG_MEM },
+
+ { "sextl", OPR(0x10,0x00), BASE, ARG_OPRZ1 }, /* pseudo */
+ { "sextl", OPRL(0x10,0x00), BASE, ARG_OPRLZ1 }, /* pseudo */
+ { "addl", OPR(0x10,0x00), BASE, ARG_OPR },
+ { "addl", OPRL(0x10,0x00), BASE, ARG_OPRL },
+ { "s4addl", OPR(0x10,0x02), BASE, ARG_OPR },
+ { "s4addl", OPRL(0x10,0x02), BASE, ARG_OPRL },
+ { "negl", OPR(0x10,0x09), BASE, ARG_OPRZ1 }, /* pseudo */
+ { "negl", OPRL(0x10,0x09), BASE, ARG_OPRLZ1 }, /* pseudo */
+ { "subl", OPR(0x10,0x09), BASE, ARG_OPR },
+ { "subl", OPRL(0x10,0x09), BASE, ARG_OPRL },
+ { "s4subl", OPR(0x10,0x0B), BASE, ARG_OPR },
+ { "s4subl", OPRL(0x10,0x0B), BASE, ARG_OPRL },
+ { "cmpbge", OPR(0x10,0x0F), BASE, ARG_OPR },
+ { "cmpbge", OPRL(0x10,0x0F), BASE, ARG_OPRL },
+ { "s8addl", OPR(0x10,0x12), BASE, ARG_OPR },
+ { "s8addl", OPRL(0x10,0x12), BASE, ARG_OPRL },
+ { "s8subl", OPR(0x10,0x1B), BASE, ARG_OPR },
+ { "s8subl", OPRL(0x10,0x1B), BASE, ARG_OPRL },
+ { "cmpult", OPR(0x10,0x1D), BASE, ARG_OPR },
+ { "cmpult", OPRL(0x10,0x1D), BASE, ARG_OPRL },
+ { "addq", OPR(0x10,0x20), BASE, ARG_OPR },
+ { "addq", OPRL(0x10,0x20), BASE, ARG_OPRL },
+ { "s4addq", OPR(0x10,0x22), BASE, ARG_OPR },
+ { "s4addq", OPRL(0x10,0x22), BASE, ARG_OPRL },
+ { "negq", OPR(0x10,0x29), BASE, ARG_OPRZ1 }, /* pseudo */
+ { "negq", OPRL(0x10,0x29), BASE, ARG_OPRLZ1 }, /* pseudo */
+ { "subq", OPR(0x10,0x29), BASE, ARG_OPR },
+ { "subq", OPRL(0x10,0x29), BASE, ARG_OPRL },
+ { "s4subq", OPR(0x10,0x2B), BASE, ARG_OPR },
+ { "s4subq", OPRL(0x10,0x2B), BASE, ARG_OPRL },
+ { "cmpeq", OPR(0x10,0x2D), BASE, ARG_OPR },
+ { "cmpeq", OPRL(0x10,0x2D), BASE, ARG_OPRL },
+ { "s8addq", OPR(0x10,0x32), BASE, ARG_OPR },
+ { "s8addq", OPRL(0x10,0x32), BASE, ARG_OPRL },
+ { "s8subq", OPR(0x10,0x3B), BASE, ARG_OPR },
+ { "s8subq", OPRL(0x10,0x3B), BASE, ARG_OPRL },
+ { "cmpule", OPR(0x10,0x3D), BASE, ARG_OPR },
+ { "cmpule", OPRL(0x10,0x3D), BASE, ARG_OPRL },
+ { "addl/v", OPR(0x10,0x40), BASE, ARG_OPR },
+ { "addl/v", OPRL(0x10,0x40), BASE, ARG_OPRL },
+ { "negl/v", OPR(0x10,0x49), BASE, ARG_OPRZ1 }, /* pseudo */
+ { "negl/v", OPRL(0x10,0x49), BASE, ARG_OPRLZ1 }, /* pseudo */
+ { "subl/v", OPR(0x10,0x49), BASE, ARG_OPR },
+ { "subl/v", OPRL(0x10,0x49), BASE, ARG_OPRL },
+ { "cmplt", OPR(0x10,0x4D), BASE, ARG_OPR },
+ { "cmplt", OPRL(0x10,0x4D), BASE, ARG_OPRL },
+ { "addq/v", OPR(0x10,0x60), BASE, ARG_OPR },
+ { "addq/v", OPRL(0x10,0x60), BASE, ARG_OPRL },
+ { "negq/v", OPR(0x10,0x69), BASE, ARG_OPRZ1 }, /* pseudo */
+ { "negq/v", OPRL(0x10,0x69), BASE, ARG_OPRLZ1 }, /* pseudo */
+ { "subq/v", OPR(0x10,0x69), BASE, ARG_OPR },
+ { "subq/v", OPRL(0x10,0x69), BASE, ARG_OPRL },
+ { "cmple", OPR(0x10,0x6D), BASE, ARG_OPR },
+ { "cmple", OPRL(0x10,0x6D), BASE, ARG_OPRL },
+
+ { "and", OPR(0x11,0x00), BASE, ARG_OPR },
+ { "and", OPRL(0x11,0x00), BASE, ARG_OPRL },
+ { "andnot", OPR(0x11,0x08), BASE, ARG_OPR }, /* alias */
+ { "andnot", OPRL(0x11,0x08), BASE, ARG_OPRL }, /* alias */
+ { "bic", OPR(0x11,0x08), BASE, ARG_OPR },
+ { "bic", OPRL(0x11,0x08), BASE, ARG_OPRL },
+ { "cmovlbs", OPR(0x11,0x14), BASE, ARG_OPR },
+ { "cmovlbs", OPRL(0x11,0x14), BASE, ARG_OPRL },
+ { "cmovlbc", OPR(0x11,0x16), BASE, ARG_OPR },
+ { "cmovlbc", OPRL(0x11,0x16), BASE, ARG_OPRL },
+ { "nop", OPR(0x11,0x20), BASE, { ZA, ZB, ZC } }, /* pseudo */
+ { "clr", OPR(0x11,0x20), BASE, { ZA, ZB, RC } }, /* pseudo */
+ { "mov", OPR(0x11,0x20), BASE, { ZA, RB, RC } }, /* pseudo */
+ { "mov", OPR(0x11,0x20), BASE, { RA, RBA, RC } }, /* pseudo */
+ { "mov", OPRL(0x11,0x20), BASE, { ZA, LIT, RC } }, /* pseudo */
+ { "or", OPR(0x11,0x20), BASE, ARG_OPR }, /* alias */
+ { "or", OPRL(0x11,0x20), BASE, ARG_OPRL }, /* alias */
+ { "bis", OPR(0x11,0x20), BASE, ARG_OPR },
+ { "bis", OPRL(0x11,0x20), BASE, ARG_OPRL },
+ { "cmoveq", OPR(0x11,0x24), BASE, ARG_OPR },
+ { "cmoveq", OPRL(0x11,0x24), BASE, ARG_OPRL },
+ { "cmovne", OPR(0x11,0x26), BASE, ARG_OPR },
+ { "cmovne", OPRL(0x11,0x26), BASE, ARG_OPRL },
+ { "not", OPR(0x11,0x28), BASE, ARG_OPRZ1 }, /* pseudo */
+ { "not", OPRL(0x11,0x28), BASE, ARG_OPRLZ1 }, /* pseudo */
+ { "ornot", OPR(0x11,0x28), BASE, ARG_OPR },
+ { "ornot", OPRL(0x11,0x28), BASE, ARG_OPRL },
+ { "xor", OPR(0x11,0x40), BASE, ARG_OPR },
+ { "xor", OPRL(0x11,0x40), BASE, ARG_OPRL },
+ { "cmovlt", OPR(0x11,0x44), BASE, ARG_OPR },
+ { "cmovlt", OPRL(0x11,0x44), BASE, ARG_OPRL },
+ { "cmovge", OPR(0x11,0x46), BASE, ARG_OPR },
+ { "cmovge", OPRL(0x11,0x46), BASE, ARG_OPRL },
+ { "eqv", OPR(0x11,0x48), BASE, ARG_OPR },
+ { "eqv", OPRL(0x11,0x48), BASE, ARG_OPRL },
+ { "xornot", OPR(0x11,0x48), BASE, ARG_OPR }, /* alias */
+ { "xornot", OPRL(0x11,0x48), BASE, ARG_OPRL }, /* alias */
+ { "amask", OPR(0x11,0x61), BASE, ARG_OPRZ1 }, /* ev56 but */
+ { "amask", OPRL(0x11,0x61), BASE, ARG_OPRLZ1 }, /* ev56 but */
+ { "cmovle", OPR(0x11,0x64), BASE, ARG_OPR },
+ { "cmovle", OPRL(0x11,0x64), BASE, ARG_OPRL },
+ { "cmovgt", OPR(0x11,0x66), BASE, ARG_OPR },
+ { "cmovgt", OPRL(0x11,0x66), BASE, ARG_OPRL },
+ { "implver", OPRL_(0x11,0x6C)|(31<<21)|(1<<13),
+ 0xFFFFFFE0, BASE, { RC } }, /* ev56 but */
+
+ { "mskbl", OPR(0x12,0x02), BASE, ARG_OPR },
+ { "mskbl", OPRL(0x12,0x02), BASE, ARG_OPRL },
+ { "extbl", OPR(0x12,0x06), BASE, ARG_OPR },
+ { "extbl", OPRL(0x12,0x06), BASE, ARG_OPRL },
+ { "insbl", OPR(0x12,0x0B), BASE, ARG_OPR },
+ { "insbl", OPRL(0x12,0x0B), BASE, ARG_OPRL },
+ { "mskwl", OPR(0x12,0x12), BASE, ARG_OPR },
+ { "mskwl", OPRL(0x12,0x12), BASE, ARG_OPRL },
+ { "extwl", OPR(0x12,0x16), BASE, ARG_OPR },
+ { "extwl", OPRL(0x12,0x16), BASE, ARG_OPRL },
+ { "inswl", OPR(0x12,0x1B), BASE, ARG_OPR },
+ { "inswl", OPRL(0x12,0x1B), BASE, ARG_OPRL },
+ { "mskll", OPR(0x12,0x22), BASE, ARG_OPR },
+ { "mskll", OPRL(0x12,0x22), BASE, ARG_OPRL },
+ { "extll", OPR(0x12,0x26), BASE, ARG_OPR },
+ { "extll", OPRL(0x12,0x26), BASE, ARG_OPRL },
+ { "insll", OPR(0x12,0x2B), BASE, ARG_OPR },
+ { "insll", OPRL(0x12,0x2B), BASE, ARG_OPRL },
+ { "zap", OPR(0x12,0x30), BASE, ARG_OPR },
+ { "zap", OPRL(0x12,0x30), BASE, ARG_OPRL },
+ { "zapnot", OPR(0x12,0x31), BASE, ARG_OPR },
+ { "zapnot", OPRL(0x12,0x31), BASE, ARG_OPRL },
+ { "mskql", OPR(0x12,0x32), BASE, ARG_OPR },
+ { "mskql", OPRL(0x12,0x32), BASE, ARG_OPRL },
+ { "srl", OPR(0x12,0x34), BASE, ARG_OPR },
+ { "srl", OPRL(0x12,0x34), BASE, ARG_OPRL },
+ { "extql", OPR(0x12,0x36), BASE, ARG_OPR },
+ { "extql", OPRL(0x12,0x36), BASE, ARG_OPRL },
+ { "sll", OPR(0x12,0x39), BASE, ARG_OPR },
+ { "sll", OPRL(0x12,0x39), BASE, ARG_OPRL },
+ { "insql", OPR(0x12,0x3B), BASE, ARG_OPR },
+ { "insql", OPRL(0x12,0x3B), BASE, ARG_OPRL },
+ { "sra", OPR(0x12,0x3C), BASE, ARG_OPR },
+ { "sra", OPRL(0x12,0x3C), BASE, ARG_OPRL },
+ { "mskwh", OPR(0x12,0x52), BASE, ARG_OPR },
+ { "mskwh", OPRL(0x12,0x52), BASE, ARG_OPRL },
+ { "inswh", OPR(0x12,0x57), BASE, ARG_OPR },
+ { "inswh", OPRL(0x12,0x57), BASE, ARG_OPRL },
+ { "extwh", OPR(0x12,0x5A), BASE, ARG_OPR },
+ { "extwh", OPRL(0x12,0x5A), BASE, ARG_OPRL },
+ { "msklh", OPR(0x12,0x62), BASE, ARG_OPR },
+ { "msklh", OPRL(0x12,0x62), BASE, ARG_OPRL },
+ { "inslh", OPR(0x12,0x67), BASE, ARG_OPR },
+ { "inslh", OPRL(0x12,0x67), BASE, ARG_OPRL },
+ { "extlh", OPR(0x12,0x6A), BASE, ARG_OPR },
+ { "extlh", OPRL(0x12,0x6A), BASE, ARG_OPRL },
+ { "mskqh", OPR(0x12,0x72), BASE, ARG_OPR },
+ { "mskqh", OPRL(0x12,0x72), BASE, ARG_OPRL },
+ { "insqh", OPR(0x12,0x77), BASE, ARG_OPR },
+ { "insqh", OPRL(0x12,0x77), BASE, ARG_OPRL },
+ { "extqh", OPR(0x12,0x7A), BASE, ARG_OPR },
+ { "extqh", OPRL(0x12,0x7A), BASE, ARG_OPRL },
+
+ { "mull", OPR(0x13,0x00), BASE, ARG_OPR },
+ { "mull", OPRL(0x13,0x00), BASE, ARG_OPRL },
+ { "mulq", OPR(0x13,0x20), BASE, ARG_OPR },
+ { "mulq", OPRL(0x13,0x20), BASE, ARG_OPRL },
+ { "umulh", OPR(0x13,0x30), BASE, ARG_OPR },
+ { "umulh", OPRL(0x13,0x30), BASE, ARG_OPRL },
+ { "mull/v", OPR(0x13,0x40), BASE, ARG_OPR },
+ { "mull/v", OPRL(0x13,0x40), BASE, ARG_OPRL },
+ { "mulq/v", OPR(0x13,0x60), BASE, ARG_OPR },
+ { "mulq/v", OPRL(0x13,0x60), BASE, ARG_OPRL },
+
+ { "itofs", FP(0x14,0x004), CIX, { RA, ZB, FC } },
+ { "sqrtf/c", FP(0x14,0x00A), CIX, ARG_FPZ1 },
+ { "sqrts/c", FP(0x14,0x00B), CIX, ARG_FPZ1 },
+ { "itoff", FP(0x14,0x014), CIX, { RA, ZB, FC } },
+ { "itoft", FP(0x14,0x024), CIX, { RA, ZB, FC } },
+ { "sqrtg/c", FP(0x14,0x02A), CIX, ARG_FPZ1 },
+ { "sqrtt/c", FP(0x14,0x02B), CIX, ARG_FPZ1 },
+ { "sqrts/m", FP(0x14,0x04B), CIX, ARG_FPZ1 },
+ { "sqrtt/m", FP(0x14,0x06B), CIX, ARG_FPZ1 },
+ { "sqrtf", FP(0x14,0x08A), CIX, ARG_FPZ1 },
+ { "sqrts", FP(0x14,0x08B), CIX, ARG_FPZ1 },
+ { "sqrtg", FP(0x14,0x0AA), CIX, ARG_FPZ1 },
+ { "sqrtt", FP(0x14,0x0AB), CIX, ARG_FPZ1 },
+ { "sqrts/d", FP(0x14,0x0CB), CIX, ARG_FPZ1 },
+ { "sqrtt/d", FP(0x14,0x0EB), CIX, ARG_FPZ1 },
+ { "sqrtf/uc", FP(0x14,0x10A), CIX, ARG_FPZ1 },
+ { "sqrts/uc", FP(0x14,0x10B), CIX, ARG_FPZ1 },
+ { "sqrtg/uc", FP(0x14,0x12A), CIX, ARG_FPZ1 },
+ { "sqrtt/uc", FP(0x14,0x12B), CIX, ARG_FPZ1 },
+ { "sqrts/um", FP(0x14,0x14B), CIX, ARG_FPZ1 },
+ { "sqrtt/um", FP(0x14,0x16B), CIX, ARG_FPZ1 },
+ { "sqrtf/u", FP(0x14,0x18A), CIX, ARG_FPZ1 },
+ { "sqrts/u", FP(0x14,0x18B), CIX, ARG_FPZ1 },
+ { "sqrtg/u", FP(0x14,0x1AA), CIX, ARG_FPZ1 },
+ { "sqrtt/u", FP(0x14,0x1AB), CIX, ARG_FPZ1 },
+ { "sqrts/ud", FP(0x14,0x1CB), CIX, ARG_FPZ1 },
+ { "sqrtt/ud", FP(0x14,0x1EB), CIX, ARG_FPZ1 },
+ { "sqrtf/sc", FP(0x14,0x40A), CIX, ARG_FPZ1 },
+ { "sqrtg/sc", FP(0x14,0x42A), CIX, ARG_FPZ1 },
+ { "sqrtf/s", FP(0x14,0x48A), CIX, ARG_FPZ1 },
+ { "sqrtg/s", FP(0x14,0x4AA), CIX, ARG_FPZ1 },
+ { "sqrtf/suc", FP(0x14,0x50A), CIX, ARG_FPZ1 },
+ { "sqrts/suc", FP(0x14,0x50B), CIX, ARG_FPZ1 },
+ { "sqrtg/suc", FP(0x14,0x52A), CIX, ARG_FPZ1 },
+ { "sqrtt/suc", FP(0x14,0x52B), CIX, ARG_FPZ1 },
+ { "sqrts/sum", FP(0x14,0x54B), CIX, ARG_FPZ1 },
+ { "sqrtt/sum", FP(0x14,0x56B), CIX, ARG_FPZ1 },
+ { "sqrtf/su", FP(0x14,0x58A), CIX, ARG_FPZ1 },
+ { "sqrts/su", FP(0x14,0x58B), CIX, ARG_FPZ1 },
+ { "sqrtg/su", FP(0x14,0x5AA), CIX, ARG_FPZ1 },
+ { "sqrtt/su", FP(0x14,0x5AB), CIX, ARG_FPZ1 },
+ { "sqrts/sud", FP(0x14,0x5CB), CIX, ARG_FPZ1 },
+ { "sqrtt/sud", FP(0x14,0x5EB), CIX, ARG_FPZ1 },
+ { "sqrts/suic", FP(0x14,0x70B), CIX, ARG_FPZ1 },
+ { "sqrtt/suic", FP(0x14,0x72B), CIX, ARG_FPZ1 },
+ { "sqrts/suim", FP(0x14,0x74B), CIX, ARG_FPZ1 },
+ { "sqrtt/suim", FP(0x14,0x76B), CIX, ARG_FPZ1 },
+ { "sqrts/sui", FP(0x14,0x78B), CIX, ARG_FPZ1 },
+ { "sqrtt/sui", FP(0x14,0x7AB), CIX, ARG_FPZ1 },
+ { "sqrts/suid", FP(0x14,0x7CB), CIX, ARG_FPZ1 },
+ { "sqrtt/suid", FP(0x14,0x7EB), CIX, ARG_FPZ1 },
+
+ { "addf/c", FP(0x15,0x000), BASE, ARG_FP },
+ { "subf/c", FP(0x15,0x001), BASE, ARG_FP },
+ { "mulf/c", FP(0x15,0x002), BASE, ARG_FP },
+ { "divf/c", FP(0x15,0x003), BASE, ARG_FP },
+ { "cvtdg/c", FP(0x15,0x01E), BASE, ARG_FPZ1 },
+ { "addg/c", FP(0x15,0x020), BASE, ARG_FP },
+ { "subg/c", FP(0x15,0x021), BASE, ARG_FP },
+ { "mulg/c", FP(0x15,0x022), BASE, ARG_FP },
+ { "divg/c", FP(0x15,0x023), BASE, ARG_FP },
+ { "cvtgf/c", FP(0x15,0x02C), BASE, ARG_FPZ1 },
+ { "cvtgd/c", FP(0x15,0x02D), BASE, ARG_FPZ1 },
+ { "cvtgq/c", FP(0x15,0x02F), BASE, ARG_FPZ1 },
+ { "cvtqf/c", FP(0x15,0x03C), BASE, ARG_FPZ1 },
+ { "cvtqg/c", FP(0x15,0x03E), BASE, ARG_FPZ1 },
+ { "addf", FP(0x15,0x080), BASE, ARG_FP },
+ { "negf", FP(0x15,0x081), BASE, ARG_FPZ1 }, /* pseudo */
+ { "subf", FP(0x15,0x081), BASE, ARG_FP },
+ { "mulf", FP(0x15,0x082), BASE, ARG_FP },
+ { "divf", FP(0x15,0x083), BASE, ARG_FP },
+ { "cvtdg", FP(0x15,0x09E), BASE, ARG_FPZ1 },
+ { "addg", FP(0x15,0x0A0), BASE, ARG_FP },
+ { "negg", FP(0x15,0x0A1), BASE, ARG_FPZ1 }, /* pseudo */
+ { "subg", FP(0x15,0x0A1), BASE, ARG_FP },
+ { "mulg", FP(0x15,0x0A2), BASE, ARG_FP },
+ { "divg", FP(0x15,0x0A3), BASE, ARG_FP },
+ { "cmpgeq", FP(0x15,0x0A5), BASE, ARG_FP },
+ { "cmpglt", FP(0x15,0x0A6), BASE, ARG_FP },
+ { "cmpgle", FP(0x15,0x0A7), BASE, ARG_FP },
+ { "cvtgf", FP(0x15,0x0AC), BASE, ARG_FPZ1 },
+ { "cvtgd", FP(0x15,0x0AD), BASE, ARG_FPZ1 },
+ { "cvtgq", FP(0x15,0x0AF), BASE, ARG_FPZ1 },
+ { "cvtqf", FP(0x15,0x0BC), BASE, ARG_FPZ1 },
+ { "cvtqg", FP(0x15,0x0BE), BASE, ARG_FPZ1 },
+ { "addf/uc", FP(0x15,0x100), BASE, ARG_FP },
+ { "subf/uc", FP(0x15,0x101), BASE, ARG_FP },
+ { "mulf/uc", FP(0x15,0x102), BASE, ARG_FP },
+ { "divf/uc", FP(0x15,0x103), BASE, ARG_FP },
+ { "cvtdg/uc", FP(0x15,0x11E), BASE, ARG_FPZ1 },
+ { "addg/uc", FP(0x15,0x120), BASE, ARG_FP },
+ { "subg/uc", FP(0x15,0x121), BASE, ARG_FP },
+ { "mulg/uc", FP(0x15,0x122), BASE, ARG_FP },
+ { "divg/uc", FP(0x15,0x123), BASE, ARG_FP },
+ { "cvtgf/uc", FP(0x15,0x12C), BASE, ARG_FPZ1 },
+ { "cvtgd/uc", FP(0x15,0x12D), BASE, ARG_FPZ1 },
+ { "cvtgq/vc", FP(0x15,0x12F), BASE, ARG_FPZ1 },
+ { "addf/u", FP(0x15,0x180), BASE, ARG_FP },
+ { "subf/u", FP(0x15,0x181), BASE, ARG_FP },
+ { "mulf/u", FP(0x15,0x182), BASE, ARG_FP },
+ { "divf/u", FP(0x15,0x183), BASE, ARG_FP },
+ { "cvtdg/u", FP(0x15,0x19E), BASE, ARG_FPZ1 },
+ { "addg/u", FP(0x15,0x1A0), BASE, ARG_FP },
+ { "subg/u", FP(0x15,0x1A1), BASE, ARG_FP },
+ { "mulg/u", FP(0x15,0x1A2), BASE, ARG_FP },
+ { "divg/u", FP(0x15,0x1A3), BASE, ARG_FP },
+ { "cvtgf/u", FP(0x15,0x1AC), BASE, ARG_FPZ1 },
+ { "cvtgd/u", FP(0x15,0x1AD), BASE, ARG_FPZ1 },
+ { "cvtgq/v", FP(0x15,0x1AF), BASE, ARG_FPZ1 },
+ { "addf/sc", FP(0x15,0x400), BASE, ARG_FP },
+ { "subf/sc", FP(0x15,0x401), BASE, ARG_FP },
+ { "mulf/sc", FP(0x15,0x402), BASE, ARG_FP },
+ { "divf/sc", FP(0x15,0x403), BASE, ARG_FP },
+ { "cvtdg/sc", FP(0x15,0x41E), BASE, ARG_FPZ1 },
+ { "addg/sc", FP(0x15,0x420), BASE, ARG_FP },
+ { "subg/sc", FP(0x15,0x421), BASE, ARG_FP },
+ { "mulg/sc", FP(0x15,0x422), BASE, ARG_FP },
+ { "divg/sc", FP(0x15,0x423), BASE, ARG_FP },
+ { "cvtgf/sc", FP(0x15,0x42C), BASE, ARG_FPZ1 },
+ { "cvtgd/sc", FP(0x15,0x42D), BASE, ARG_FPZ1 },
+ { "cvtgq/sc", FP(0x15,0x42F), BASE, ARG_FPZ1 },
+ { "addf/s", FP(0x15,0x480), BASE, ARG_FP },
+ { "negf/s", FP(0x15,0x481), BASE, ARG_FPZ1 }, /* pseudo */
+ { "subf/s", FP(0x15,0x481), BASE, ARG_FP },
+ { "mulf/s", FP(0x15,0x482), BASE, ARG_FP },
+ { "divf/s", FP(0x15,0x483), BASE, ARG_FP },
+ { "cvtdg/s", FP(0x15,0x49E), BASE, ARG_FPZ1 },
+ { "addg/s", FP(0x15,0x4A0), BASE, ARG_FP },
+ { "negg/s", FP(0x15,0x4A1), BASE, ARG_FPZ1 }, /* pseudo */
+ { "subg/s", FP(0x15,0x4A1), BASE, ARG_FP },
+ { "mulg/s", FP(0x15,0x4A2), BASE, ARG_FP },
+ { "divg/s", FP(0x15,0x4A3), BASE, ARG_FP },
+ { "cmpgeq/s", FP(0x15,0x4A5), BASE, ARG_FP },
+ { "cmpglt/s", FP(0x15,0x4A6), BASE, ARG_FP },
+ { "cmpgle/s", FP(0x15,0x4A7), BASE, ARG_FP },
+ { "cvtgf/s", FP(0x15,0x4AC), BASE, ARG_FPZ1 },
+ { "cvtgd/s", FP(0x15,0x4AD), BASE, ARG_FPZ1 },
+ { "cvtgq/s", FP(0x15,0x4AF), BASE, ARG_FPZ1 },
+ { "addf/suc", FP(0x15,0x500), BASE, ARG_FP },
+ { "subf/suc", FP(0x15,0x501), BASE, ARG_FP },
+ { "mulf/suc", FP(0x15,0x502), BASE, ARG_FP },
+ { "divf/suc", FP(0x15,0x503), BASE, ARG_FP },
+ { "cvtdg/suc", FP(0x15,0x51E), BASE, ARG_FPZ1 },
+ { "addg/suc", FP(0x15,0x520), BASE, ARG_FP },
+ { "subg/suc", FP(0x15,0x521), BASE, ARG_FP },
+ { "mulg/suc", FP(0x15,0x522), BASE, ARG_FP },
+ { "divg/suc", FP(0x15,0x523), BASE, ARG_FP },
+ { "cvtgf/suc", FP(0x15,0x52C), BASE, ARG_FPZ1 },
+ { "cvtgd/suc", FP(0x15,0x52D), BASE, ARG_FPZ1 },
+ { "cvtgq/svc", FP(0x15,0x52F), BASE, ARG_FPZ1 },
+ { "addf/su", FP(0x15,0x580), BASE, ARG_FP },
+ { "subf/su", FP(0x15,0x581), BASE, ARG_FP },
+ { "mulf/su", FP(0x15,0x582), BASE, ARG_FP },
+ { "divf/su", FP(0x15,0x583), BASE, ARG_FP },
+ { "cvtdg/su", FP(0x15,0x59E), BASE, ARG_FPZ1 },
+ { "addg/su", FP(0x15,0x5A0), BASE, ARG_FP },
+ { "subg/su", FP(0x15,0x5A1), BASE, ARG_FP },
+ { "mulg/su", FP(0x15,0x5A2), BASE, ARG_FP },
+ { "divg/su", FP(0x15,0x5A3), BASE, ARG_FP },
+ { "cvtgf/su", FP(0x15,0x5AC), BASE, ARG_FPZ1 },
+ { "cvtgd/su", FP(0x15,0x5AD), BASE, ARG_FPZ1 },
+ { "cvtgq/sv", FP(0x15,0x5AF), BASE, ARG_FPZ1 },
+
+ { "adds/c", FP(0x16,0x000), BASE, ARG_FP },
+ { "subs/c", FP(0x16,0x001), BASE, ARG_FP },
+ { "muls/c", FP(0x16,0x002), BASE, ARG_FP },
+ { "divs/c", FP(0x16,0x003), BASE, ARG_FP },
+ { "addt/c", FP(0x16,0x020), BASE, ARG_FP },
+ { "subt/c", FP(0x16,0x021), BASE, ARG_FP },
+ { "mult/c", FP(0x16,0x022), BASE, ARG_FP },
+ { "divt/c", FP(0x16,0x023), BASE, ARG_FP },
+ { "cvtts/c", FP(0x16,0x02C), BASE, ARG_FPZ1 },
+ { "cvttq/c", FP(0x16,0x02F), BASE, ARG_FPZ1 },
+ { "cvtqs/c", FP(0x16,0x03C), BASE, ARG_FPZ1 },
+ { "cvtqt/c", FP(0x16,0x03E), BASE, ARG_FPZ1 },
+ { "adds/m", FP(0x16,0x040), BASE, ARG_FP },
+ { "subs/m", FP(0x16,0x041), BASE, ARG_FP },
+ { "muls/m", FP(0x16,0x042), BASE, ARG_FP },
+ { "divs/m", FP(0x16,0x043), BASE, ARG_FP },
+ { "addt/m", FP(0x16,0x060), BASE, ARG_FP },
+ { "subt/m", FP(0x16,0x061), BASE, ARG_FP },
+ { "mult/m", FP(0x16,0x062), BASE, ARG_FP },
+ { "divt/m", FP(0x16,0x063), BASE, ARG_FP },
+ { "cvtts/m", FP(0x16,0x06C), BASE, ARG_FPZ1 },
+ { "cvttq/m", FP(0x16,0x06F), BASE, ARG_FPZ1 },
+ { "cvtqs/m", FP(0x16,0x07C), BASE, ARG_FPZ1 },
+ { "cvtqt/m", FP(0x16,0x07E), BASE, ARG_FPZ1 },
+ { "adds", FP(0x16,0x080), BASE, ARG_FP },
+ { "negs", FP(0x16,0x081), BASE, ARG_FPZ1 }, /* pseudo */
+ { "subs", FP(0x16,0x081), BASE, ARG_FP },
+ { "muls", FP(0x16,0x082), BASE, ARG_FP },
+ { "divs", FP(0x16,0x083), BASE, ARG_FP },
+ { "addt", FP(0x16,0x0A0), BASE, ARG_FP },
+ { "negt", FP(0x16,0x0A1), BASE, ARG_FPZ1 }, /* pseudo */
+ { "subt", FP(0x16,0x0A1), BASE, ARG_FP },
+ { "mult", FP(0x16,0x0A2), BASE, ARG_FP },
+ { "divt", FP(0x16,0x0A3), BASE, ARG_FP },
+ { "cmptun", FP(0x16,0x0A4), BASE, ARG_FP },
+ { "cmpteq", FP(0x16,0x0A5), BASE, ARG_FP },
+ { "cmptlt", FP(0x16,0x0A6), BASE, ARG_FP },
+ { "cmptle", FP(0x16,0x0A7), BASE, ARG_FP },
+ { "cvtts", FP(0x16,0x0AC), BASE, ARG_FPZ1 },
+ { "cvttq", FP(0x16,0x0AF), BASE, ARG_FPZ1 },
+ { "cvtqs", FP(0x16,0x0BC), BASE, ARG_FPZ1 },
+ { "cvtqt", FP(0x16,0x0BE), BASE, ARG_FPZ1 },
+ { "adds/d", FP(0x16,0x0C0), BASE, ARG_FP },
+ { "subs/d", FP(0x16,0x0C1), BASE, ARG_FP },
+ { "muls/d", FP(0x16,0x0C2), BASE, ARG_FP },
+ { "divs/d", FP(0x16,0x0C3), BASE, ARG_FP },
+ { "addt/d", FP(0x16,0x0E0), BASE, ARG_FP },
+ { "subt/d", FP(0x16,0x0E1), BASE, ARG_FP },
+ { "mult/d", FP(0x16,0x0E2), BASE, ARG_FP },
+ { "divt/d", FP(0x16,0x0E3), BASE, ARG_FP },
+ { "cvtts/d", FP(0x16,0x0EC), BASE, ARG_FPZ1 },
+ { "cvttq/d", FP(0x16,0x0EF), BASE, ARG_FPZ1 },
+ { "cvtqs/d", FP(0x16,0x0FC), BASE, ARG_FPZ1 },
+ { "cvtqt/d", FP(0x16,0x0FE), BASE, ARG_FPZ1 },
+ { "adds/uc", FP(0x16,0x100), BASE, ARG_FP },
+ { "subs/uc", FP(0x16,0x101), BASE, ARG_FP },
+ { "muls/uc", FP(0x16,0x102), BASE, ARG_FP },
+ { "divs/uc", FP(0x16,0x103), BASE, ARG_FP },
+ { "addt/uc", FP(0x16,0x120), BASE, ARG_FP },
+ { "subt/uc", FP(0x16,0x121), BASE, ARG_FP },
+ { "mult/uc", FP(0x16,0x122), BASE, ARG_FP },
+ { "divt/uc", FP(0x16,0x123), BASE, ARG_FP },
+ { "cvtts/uc", FP(0x16,0x12C), BASE, ARG_FPZ1 },
+ { "cvttq/vc", FP(0x16,0x12F), BASE, ARG_FPZ1 },
+ { "adds/um", FP(0x16,0x140), BASE, ARG_FP },
+ { "subs/um", FP(0x16,0x141), BASE, ARG_FP },
+ { "muls/um", FP(0x16,0x142), BASE, ARG_FP },
+ { "divs/um", FP(0x16,0x143), BASE, ARG_FP },
+ { "addt/um", FP(0x16,0x160), BASE, ARG_FP },
+ { "subt/um", FP(0x16,0x161), BASE, ARG_FP },
+ { "mult/um", FP(0x16,0x162), BASE, ARG_FP },
+ { "divt/um", FP(0x16,0x163), BASE, ARG_FP },
+ { "cvtts/um", FP(0x16,0x16C), BASE, ARG_FPZ1 },
+ { "cvttq/vm", FP(0x16,0x16F), BASE, ARG_FPZ1 },
+ { "adds/u", FP(0x16,0x180), BASE, ARG_FP },
+ { "subs/u", FP(0x16,0x181), BASE, ARG_FP },
+ { "muls/u", FP(0x16,0x182), BASE, ARG_FP },
+ { "divs/u", FP(0x16,0x183), BASE, ARG_FP },
+ { "addt/u", FP(0x16,0x1A0), BASE, ARG_FP },
+ { "subt/u", FP(0x16,0x1A1), BASE, ARG_FP },
+ { "mult/u", FP(0x16,0x1A2), BASE, ARG_FP },
+ { "divt/u", FP(0x16,0x1A3), BASE, ARG_FP },
+ { "cvtts/u", FP(0x16,0x1AC), BASE, ARG_FPZ1 },
+ { "cvttq/v", FP(0x16,0x1AF), BASE, ARG_FPZ1 },
+ { "adds/ud", FP(0x16,0x1C0), BASE, ARG_FP },
+ { "subs/ud", FP(0x16,0x1C1), BASE, ARG_FP },
+ { "muls/ud", FP(0x16,0x1C2), BASE, ARG_FP },
+ { "divs/ud", FP(0x16,0x1C3), BASE, ARG_FP },
+ { "addt/ud", FP(0x16,0x1E0), BASE, ARG_FP },
+ { "subt/ud", FP(0x16,0x1E1), BASE, ARG_FP },
+ { "mult/ud", FP(0x16,0x1E2), BASE, ARG_FP },
+ { "divt/ud", FP(0x16,0x1E3), BASE, ARG_FP },
+ { "cvtts/ud", FP(0x16,0x1EC), BASE, ARG_FPZ1 },
+ { "cvttq/vd", FP(0x16,0x1EF), BASE, ARG_FPZ1 },
+ { "cvtst", FP(0x16,0x2AC), BASE, ARG_FPZ1 },
+ { "adds/suc", FP(0x16,0x500), BASE, ARG_FP },
+ { "subs/suc", FP(0x16,0x501), BASE, ARG_FP },
+ { "muls/suc", FP(0x16,0x502), BASE, ARG_FP },
+ { "divs/suc", FP(0x16,0x503), BASE, ARG_FP },
+ { "addt/suc", FP(0x16,0x520), BASE, ARG_FP },
+ { "subt/suc", FP(0x16,0x521), BASE, ARG_FP },
+ { "mult/suc", FP(0x16,0x522), BASE, ARG_FP },
+ { "divt/suc", FP(0x16,0x523), BASE, ARG_FP },
+ { "cvtts/suc", FP(0x16,0x52C), BASE, ARG_FPZ1 },
+ { "cvttq/svc", FP(0x16,0x52F), BASE, ARG_FPZ1 },
+ { "adds/sum", FP(0x16,0x540), BASE, ARG_FP },
+ { "subs/sum", FP(0x16,0x541), BASE, ARG_FP },
+ { "muls/sum", FP(0x16,0x542), BASE, ARG_FP },
+ { "divs/sum", FP(0x16,0x543), BASE, ARG_FP },
+ { "addt/sum", FP(0x16,0x560), BASE, ARG_FP },
+ { "subt/sum", FP(0x16,0x561), BASE, ARG_FP },
+ { "mult/sum", FP(0x16,0x562), BASE, ARG_FP },
+ { "divt/sum", FP(0x16,0x563), BASE, ARG_FP },
+ { "cvtts/sum", FP(0x16,0x56C), BASE, ARG_FPZ1 },
+ { "cvttq/svm", FP(0x16,0x56F), BASE, ARG_FPZ1 },
+ { "adds/su", FP(0x16,0x580), BASE, ARG_FP },
+ { "negs/su", FP(0x16,0x581), BASE, ARG_FPZ1 }, /* pseudo */
+ { "subs/su", FP(0x16,0x581), BASE, ARG_FP },
+ { "muls/su", FP(0x16,0x582), BASE, ARG_FP },
+ { "divs/su", FP(0x16,0x583), BASE, ARG_FP },
+ { "addt/su", FP(0x16,0x5A0), BASE, ARG_FP },
+ { "negt/su", FP(0x16,0x5A1), BASE, ARG_FPZ1 }, /* pseudo */
+ { "subt/su", FP(0x16,0x5A1), BASE, ARG_FP },
+ { "mult/su", FP(0x16,0x5A2), BASE, ARG_FP },
+ { "divt/su", FP(0x16,0x5A3), BASE, ARG_FP },
+ { "cmptun/su", FP(0x16,0x5A4), BASE, ARG_FP },
+ { "cmpteq/su", FP(0x16,0x5A5), BASE, ARG_FP },
+ { "cmptlt/su", FP(0x16,0x5A6), BASE, ARG_FP },
+ { "cmptle/su", FP(0x16,0x5A7), BASE, ARG_FP },
+ { "cvtts/su", FP(0x16,0x5AC), BASE, ARG_FPZ1 },
+ { "cvttq/sv", FP(0x16,0x5AF), BASE, ARG_FPZ1 },
+ { "adds/sud", FP(0x16,0x5C0), BASE, ARG_FP },
+ { "subs/sud", FP(0x16,0x5C1), BASE, ARG_FP },
+ { "muls/sud", FP(0x16,0x5C2), BASE, ARG_FP },
+ { "divs/sud", FP(0x16,0x5C3), BASE, ARG_FP },
+ { "addt/sud", FP(0x16,0x5E0), BASE, ARG_FP },
+ { "subt/sud", FP(0x16,0x5E1), BASE, ARG_FP },
+ { "mult/sud", FP(0x16,0x5E2), BASE, ARG_FP },
+ { "divt/sud", FP(0x16,0x5E3), BASE, ARG_FP },
+ { "cvtts/sud", FP(0x16,0x5EC), BASE, ARG_FPZ1 },
+ { "cvttq/svd", FP(0x16,0x5EF), BASE, ARG_FPZ1 },
+ { "cvtst/s", FP(0x16,0x6AC), BASE, ARG_FPZ1 },
+ { "adds/suic", FP(0x16,0x700), BASE, ARG_FP },
+ { "subs/suic", FP(0x16,0x701), BASE, ARG_FP },
+ { "muls/suic", FP(0x16,0x702), BASE, ARG_FP },
+ { "divs/suic", FP(0x16,0x703), BASE, ARG_FP },
+ { "addt/suic", FP(0x16,0x720), BASE, ARG_FP },
+ { "subt/suic", FP(0x16,0x721), BASE, ARG_FP },
+ { "mult/suic", FP(0x16,0x722), BASE, ARG_FP },
+ { "divt/suic", FP(0x16,0x723), BASE, ARG_FP },
+ { "cvtts/suic", FP(0x16,0x72C), BASE, ARG_FPZ1 },
+ { "cvttq/svic", FP(0x16,0x72F), BASE, ARG_FPZ1 },
+ { "cvtqs/suic", FP(0x16,0x73C), BASE, ARG_FPZ1 },
+ { "cvtqt/suic", FP(0x16,0x73E), BASE, ARG_FPZ1 },
+ { "adds/suim", FP(0x16,0x740), BASE, ARG_FP },
+ { "subs/suim", FP(0x16,0x741), BASE, ARG_FP },
+ { "muls/suim", FP(0x16,0x742), BASE, ARG_FP },
+ { "divs/suim", FP(0x16,0x743), BASE, ARG_FP },
+ { "addt/suim", FP(0x16,0x760), BASE, ARG_FP },
+ { "subt/suim", FP(0x16,0x761), BASE, ARG_FP },
+ { "mult/suim", FP(0x16,0x762), BASE, ARG_FP },
+ { "divt/suim", FP(0x16,0x763), BASE, ARG_FP },
+ { "cvtts/suim", FP(0x16,0x76C), BASE, ARG_FPZ1 },
+ { "cvttq/svim", FP(0x16,0x76F), BASE, ARG_FPZ1 },
+ { "cvtqs/suim", FP(0x16,0x77C), BASE, ARG_FPZ1 },
+ { "cvtqt/suim", FP(0x16,0x77E), BASE, ARG_FPZ1 },
+ { "adds/sui", FP(0x16,0x780), BASE, ARG_FP },
+ { "negs/sui", FP(0x16,0x781), BASE, ARG_FPZ1 }, /* pseudo */
+ { "subs/sui", FP(0x16,0x781), BASE, ARG_FP },
+ { "muls/sui", FP(0x16,0x782), BASE, ARG_FP },
+ { "divs/sui", FP(0x16,0x783), BASE, ARG_FP },
+ { "addt/sui", FP(0x16,0x7A0), BASE, ARG_FP },
+ { "negt/sui", FP(0x16,0x7A1), BASE, ARG_FPZ1 }, /* pseudo */
+ { "subt/sui", FP(0x16,0x7A1), BASE, ARG_FP },
+ { "mult/sui", FP(0x16,0x7A2), BASE, ARG_FP },
+ { "divt/sui", FP(0x16,0x7A3), BASE, ARG_FP },
+ { "cvtts/sui", FP(0x16,0x7AC), BASE, ARG_FPZ1 },
+ { "cvttq/svi", FP(0x16,0x7AF), BASE, ARG_FPZ1 },
+ { "cvtqs/sui", FP(0x16,0x7BC), BASE, ARG_FPZ1 },
+ { "cvtqt/sui", FP(0x16,0x7BE), BASE, ARG_FPZ1 },
+ { "adds/suid", FP(0x16,0x7C0), BASE, ARG_FP },
+ { "subs/suid", FP(0x16,0x7C1), BASE, ARG_FP },
+ { "muls/suid", FP(0x16,0x7C2), BASE, ARG_FP },
+ { "divs/suid", FP(0x16,0x7C3), BASE, ARG_FP },
+ { "addt/suid", FP(0x16,0x7E0), BASE, ARG_FP },
+ { "subt/suid", FP(0x16,0x7E1), BASE, ARG_FP },
+ { "mult/suid", FP(0x16,0x7E2), BASE, ARG_FP },
+ { "divt/suid", FP(0x16,0x7E3), BASE, ARG_FP },
+ { "cvtts/suid", FP(0x16,0x7EC), BASE, ARG_FPZ1 },
+ { "cvttq/svid", FP(0x16,0x7EF), BASE, ARG_FPZ1 },
+ { "cvtqs/suid", FP(0x16,0x7FC), BASE, ARG_FPZ1 },
+ { "cvtqt/suid", FP(0x16,0x7FE), BASE, ARG_FPZ1 },
+
+ { "cvtlq", FP(0x17,0x010), BASE, ARG_FPZ1 },
+ { "fnop", FP(0x17,0x020), BASE, { ZA, ZB, ZC } }, /* pseudo */
+ { "fclr", FP(0x17,0x020), BASE, { ZA, ZB, FC } }, /* pseudo */
+ { "fabs", FP(0x17,0x020), BASE, ARG_FPZ1 }, /* pseudo */
+ { "fmov", FP(0x17,0x020), BASE, { FA, RBA, FC } }, /* pseudo */
+ { "cpys", FP(0x17,0x020), BASE, ARG_FP },
+ { "fneg", FP(0x17,0x021), BASE, { FA, RBA, FC } }, /* pseudo */
+ { "cpysn", FP(0x17,0x021), BASE, ARG_FP },
+ { "cpyse", FP(0x17,0x022), BASE, ARG_FP },
+ { "mt_fpcr", FP(0x17,0x024), BASE, { FA, RBA, RCA } },
+ { "mf_fpcr", FP(0x17,0x025), BASE, { FA, RBA, RCA } },
+ { "fcmoveq", FP(0x17,0x02A), BASE, ARG_FP },
+ { "fcmovne", FP(0x17,0x02B), BASE, ARG_FP },
+ { "fcmovlt", FP(0x17,0x02C), BASE, ARG_FP },
+ { "fcmovge", FP(0x17,0x02D), BASE, ARG_FP },
+ { "fcmovle", FP(0x17,0x02E), BASE, ARG_FP },
+ { "fcmovgt", FP(0x17,0x02F), BASE, ARG_FP },
+ { "cvtql", FP(0x17,0x030), BASE, ARG_FPZ1 },
+ { "cvtql/v", FP(0x17,0x130), BASE, ARG_FPZ1 },
+ { "cvtql/sv", FP(0x17,0x530), BASE, ARG_FPZ1 },
+
+ { "trapb", MFC(0x18,0x0000), BASE, ARG_NONE },
+ { "draint", MFC(0x18,0x0000), BASE, ARG_NONE }, /* alias */
+ { "excb", MFC(0x18,0x0400), BASE, ARG_NONE },
+ { "mb", MFC(0x18,0x4000), BASE, ARG_NONE },
+ { "wmb", MFC(0x18,0x4400), BASE, ARG_NONE },
+ { "fetch", MFC(0x18,0x8000), BASE, { ZA, PRB } },
+ { "fetch_m", MFC(0x18,0xA000), BASE, { ZA, PRB } },
+ { "rpcc", MFC(0x18,0xC000), BASE, { RA } },
+ { "rc", MFC(0x18,0xE000), BASE, { RA } },
+ { "ecb", MFC(0x18,0xE800), BASE, { ZA, PRB } }, /* ev56 una */
+ { "rs", MFC(0x18,0xF000), BASE, { RA } },
+ { "wh64", MFC(0x18,0xF800), BASE, { ZA, PRB } }, /* ev56 una */
+ { "wh64en", MFC(0x18,0xFC00), BASE, { ZA, PRB } }, /* ev7 una */
+
+ { "hw_mfpr", OPR(0x19,0x00), EV4, { RA, RBA, EV4EXTHWINDEX } },
+ { "hw_mfpr", OP(0x19), OP_MASK, EV5, { RA, RBA, EV5HWINDEX } },
+ { "hw_mfpr", OP(0x19), OP_MASK, EV6, { RA, ZB, EV6HWINDEX } },
+ { "hw_mfpr/i", OPR(0x19,0x01), EV4, ARG_EV4HWMPR },
+ { "hw_mfpr/a", OPR(0x19,0x02), EV4, ARG_EV4HWMPR },
+ { "hw_mfpr/ai", OPR(0x19,0x03), EV4, ARG_EV4HWMPR },
+ { "hw_mfpr/p", OPR(0x19,0x04), EV4, ARG_EV4HWMPR },
+ { "hw_mfpr/pi", OPR(0x19,0x05), EV4, ARG_EV4HWMPR },
+ { "hw_mfpr/pa", OPR(0x19,0x06), EV4, ARG_EV4HWMPR },
+ { "hw_mfpr/pai", OPR(0x19,0x07), EV4, ARG_EV4HWMPR },
+ { "pal19", PCD(0x19), BASE, ARG_PCD },
+
+ { "jmp", MBR_(0x1A,0), MBR_MASK | 0x3FFF, /* pseudo */
+ BASE, { ZA, CPRB } },
+ { "jmp", MBR(0x1A,0), BASE, { RA, CPRB, JMPHINT } },
+ { "jsr", MBR(0x1A,1), BASE, { RA, CPRB, JMPHINT } },
+ { "ret", MBR_(0x1A,2) | (31 << 21) | (26 << 16) | 1,/* pseudo */
+ 0xFFFFFFFF, BASE, { 0 } },
+ { "ret", MBR(0x1A,2), BASE, { RA, CPRB, RETHINT } },
+ { "jcr", MBR(0x1A,3), BASE, { RA, CPRB, RETHINT } }, /* alias */
+ { "jsr_coroutine", MBR(0x1A,3), BASE, { RA, CPRB, RETHINT } },
+
+ { "hw_ldl", EV4HWMEM(0x1B,0x0), EV4, ARG_EV4HWMEM },
+ { "hw_ldl", EV5HWMEM(0x1B,0x00), EV5, ARG_EV5HWMEM },
+ { "hw_ldl", EV6HWMEM(0x1B,0x8), EV6, ARG_EV6HWMEM },
+ { "hw_ldl/a", EV4HWMEM(0x1B,0x4), EV4, ARG_EV4HWMEM },
+ { "hw_ldl/a", EV5HWMEM(0x1B,0x10), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/a", EV6HWMEM(0x1B,0xC), EV6, ARG_EV6HWMEM },
+ { "hw_ldl/al", EV5HWMEM(0x1B,0x11), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/ar", EV4HWMEM(0x1B,0x6), EV4, ARG_EV4HWMEM },
+ { "hw_ldl/av", EV5HWMEM(0x1B,0x12), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/avl", EV5HWMEM(0x1B,0x13), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/aw", EV5HWMEM(0x1B,0x18), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/awl", EV5HWMEM(0x1B,0x19), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/awv", EV5HWMEM(0x1B,0x1a), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/awvl", EV5HWMEM(0x1B,0x1b), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/l", EV5HWMEM(0x1B,0x01), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/p", EV4HWMEM(0x1B,0x8), EV4, ARG_EV4HWMEM },
+ { "hw_ldl/p", EV5HWMEM(0x1B,0x20), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/p", EV6HWMEM(0x1B,0x0), EV6, ARG_EV6HWMEM },
+ { "hw_ldl/pa", EV4HWMEM(0x1B,0xC), EV4, ARG_EV4HWMEM },
+ { "hw_ldl/pa", EV5HWMEM(0x1B,0x30), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/pal", EV5HWMEM(0x1B,0x31), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/par", EV4HWMEM(0x1B,0xE), EV4, ARG_EV4HWMEM },
+ { "hw_ldl/pav", EV5HWMEM(0x1B,0x32), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/pavl", EV5HWMEM(0x1B,0x33), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/paw", EV5HWMEM(0x1B,0x38), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/pawl", EV5HWMEM(0x1B,0x39), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/pawv", EV5HWMEM(0x1B,0x3a), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/pawvl", EV5HWMEM(0x1B,0x3b), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/pl", EV5HWMEM(0x1B,0x21), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/pr", EV4HWMEM(0x1B,0xA), EV4, ARG_EV4HWMEM },
+ { "hw_ldl/pv", EV5HWMEM(0x1B,0x22), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/pvl", EV5HWMEM(0x1B,0x23), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/pw", EV5HWMEM(0x1B,0x28), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/pwl", EV5HWMEM(0x1B,0x29), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/pwv", EV5HWMEM(0x1B,0x2a), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/pwvl", EV5HWMEM(0x1B,0x2b), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/r", EV4HWMEM(0x1B,0x2), EV4, ARG_EV4HWMEM },
+ { "hw_ldl/v", EV5HWMEM(0x1B,0x02), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/v", EV6HWMEM(0x1B,0x4), EV6, ARG_EV6HWMEM },
+ { "hw_ldl/vl", EV5HWMEM(0x1B,0x03), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/w", EV5HWMEM(0x1B,0x08), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/w", EV6HWMEM(0x1B,0xA), EV6, ARG_EV6HWMEM },
+ { "hw_ldl/wa", EV6HWMEM(0x1B,0xE), EV6, ARG_EV6HWMEM },
+ { "hw_ldl/wl", EV5HWMEM(0x1B,0x09), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/wv", EV5HWMEM(0x1B,0x0a), EV5, ARG_EV5HWMEM },
+ { "hw_ldl/wvl", EV5HWMEM(0x1B,0x0b), EV5, ARG_EV5HWMEM },
+ { "hw_ldl_l", EV5HWMEM(0x1B,0x01), EV5, ARG_EV5HWMEM },
+ { "hw_ldl_l/a", EV5HWMEM(0x1B,0x11), EV5, ARG_EV5HWMEM },
+ { "hw_ldl_l/av", EV5HWMEM(0x1B,0x13), EV5, ARG_EV5HWMEM },
+ { "hw_ldl_l/aw", EV5HWMEM(0x1B,0x19), EV5, ARG_EV5HWMEM },
+ { "hw_ldl_l/awv", EV5HWMEM(0x1B,0x1b), EV5, ARG_EV5HWMEM },
+ { "hw_ldl_l/p", EV5HWMEM(0x1B,0x21), EV5, ARG_EV5HWMEM },
+ { "hw_ldl_l/p", EV6HWMEM(0x1B,0x2), EV6, ARG_EV6HWMEM },
+ { "hw_ldl_l/pa", EV5HWMEM(0x1B,0x31), EV5, ARG_EV5HWMEM },
+ { "hw_ldl_l/pav", EV5HWMEM(0x1B,0x33), EV5, ARG_EV5HWMEM },
+ { "hw_ldl_l/paw", EV5HWMEM(0x1B,0x39), EV5, ARG_EV5HWMEM },
+ { "hw_ldl_l/pawv", EV5HWMEM(0x1B,0x3b), EV5, ARG_EV5HWMEM },
+ { "hw_ldl_l/pv", EV5HWMEM(0x1B,0x23), EV5, ARG_EV5HWMEM },
+ { "hw_ldl_l/pw", EV5HWMEM(0x1B,0x29), EV5, ARG_EV5HWMEM },
+ { "hw_ldl_l/pwv", EV5HWMEM(0x1B,0x2b), EV5, ARG_EV5HWMEM },
+ { "hw_ldl_l/v", EV5HWMEM(0x1B,0x03), EV5, ARG_EV5HWMEM },
+ { "hw_ldl_l/w", EV5HWMEM(0x1B,0x09), EV5, ARG_EV5HWMEM },
+ { "hw_ldl_l/wv", EV5HWMEM(0x1B,0x0b), EV5, ARG_EV5HWMEM },
+ { "hw_ldq", EV4HWMEM(0x1B,0x1), EV4, ARG_EV4HWMEM },
+ { "hw_ldq", EV5HWMEM(0x1B,0x04), EV5, ARG_EV5HWMEM },
+ { "hw_ldq", EV6HWMEM(0x1B,0x9), EV6, ARG_EV6HWMEM },
+ { "hw_ldq/a", EV4HWMEM(0x1B,0x5), EV4, ARG_EV4HWMEM },
+ { "hw_ldq/a", EV5HWMEM(0x1B,0x14), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/a", EV6HWMEM(0x1B,0xD), EV6, ARG_EV6HWMEM },
+ { "hw_ldq/al", EV5HWMEM(0x1B,0x15), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/ar", EV4HWMEM(0x1B,0x7), EV4, ARG_EV4HWMEM },
+ { "hw_ldq/av", EV5HWMEM(0x1B,0x16), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/avl", EV5HWMEM(0x1B,0x17), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/aw", EV5HWMEM(0x1B,0x1c), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/awl", EV5HWMEM(0x1B,0x1d), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/awv", EV5HWMEM(0x1B,0x1e), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/awvl", EV5HWMEM(0x1B,0x1f), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/l", EV5HWMEM(0x1B,0x05), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/p", EV4HWMEM(0x1B,0x9), EV4, ARG_EV4HWMEM },
+ { "hw_ldq/p", EV5HWMEM(0x1B,0x24), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/p", EV6HWMEM(0x1B,0x1), EV6, ARG_EV6HWMEM },
+ { "hw_ldq/pa", EV4HWMEM(0x1B,0xD), EV4, ARG_EV4HWMEM },
+ { "hw_ldq/pa", EV5HWMEM(0x1B,0x34), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/pal", EV5HWMEM(0x1B,0x35), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/par", EV4HWMEM(0x1B,0xF), EV4, ARG_EV4HWMEM },
+ { "hw_ldq/pav", EV5HWMEM(0x1B,0x36), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/pavl", EV5HWMEM(0x1B,0x37), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/paw", EV5HWMEM(0x1B,0x3c), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/pawl", EV5HWMEM(0x1B,0x3d), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/pawv", EV5HWMEM(0x1B,0x3e), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/pawvl", EV5HWMEM(0x1B,0x3f), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/pl", EV5HWMEM(0x1B,0x25), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/pr", EV4HWMEM(0x1B,0xB), EV4, ARG_EV4HWMEM },
+ { "hw_ldq/pv", EV5HWMEM(0x1B,0x26), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/pvl", EV5HWMEM(0x1B,0x27), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/pw", EV5HWMEM(0x1B,0x2c), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/pwl", EV5HWMEM(0x1B,0x2d), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/pwv", EV5HWMEM(0x1B,0x2e), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/pwvl", EV5HWMEM(0x1B,0x2f), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/r", EV4HWMEM(0x1B,0x3), EV4, ARG_EV4HWMEM },
+ { "hw_ldq/v", EV5HWMEM(0x1B,0x06), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/v", EV6HWMEM(0x1B,0x5), EV6, ARG_EV6HWMEM },
+ { "hw_ldq/vl", EV5HWMEM(0x1B,0x07), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/w", EV5HWMEM(0x1B,0x0c), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/w", EV6HWMEM(0x1B,0xB), EV6, ARG_EV6HWMEM },
+ { "hw_ldq/wa", EV6HWMEM(0x1B,0xF), EV6, ARG_EV6HWMEM },
+ { "hw_ldq/wl", EV5HWMEM(0x1B,0x0d), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/wv", EV5HWMEM(0x1B,0x0e), EV5, ARG_EV5HWMEM },
+ { "hw_ldq/wvl", EV5HWMEM(0x1B,0x0f), EV5, ARG_EV5HWMEM },
+ { "hw_ldq_l", EV5HWMEM(0x1B,0x05), EV5, ARG_EV5HWMEM },
+ { "hw_ldq_l/a", EV5HWMEM(0x1B,0x15), EV5, ARG_EV5HWMEM },
+ { "hw_ldq_l/av", EV5HWMEM(0x1B,0x17), EV5, ARG_EV5HWMEM },
+ { "hw_ldq_l/aw", EV5HWMEM(0x1B,0x1d), EV5, ARG_EV5HWMEM },
+ { "hw_ldq_l/awv", EV5HWMEM(0x1B,0x1f), EV5, ARG_EV5HWMEM },
+ { "hw_ldq_l/p", EV5HWMEM(0x1B,0x25), EV5, ARG_EV5HWMEM },
+ { "hw_ldq_l/p", EV6HWMEM(0x1B,0x3), EV6, ARG_EV6HWMEM },
+ { "hw_ldq_l/pa", EV5HWMEM(0x1B,0x35), EV5, ARG_EV5HWMEM },
+ { "hw_ldq_l/pav", EV5HWMEM(0x1B,0x37), EV5, ARG_EV5HWMEM },
+ { "hw_ldq_l/paw", EV5HWMEM(0x1B,0x3d), EV5, ARG_EV5HWMEM },
+ { "hw_ldq_l/pawv", EV5HWMEM(0x1B,0x3f), EV5, ARG_EV5HWMEM },
+ { "hw_ldq_l/pv", EV5HWMEM(0x1B,0x27), EV5, ARG_EV5HWMEM },
+ { "hw_ldq_l/pw", EV5HWMEM(0x1B,0x2d), EV5, ARG_EV5HWMEM },
+ { "hw_ldq_l/pwv", EV5HWMEM(0x1B,0x2f), EV5, ARG_EV5HWMEM },
+ { "hw_ldq_l/v", EV5HWMEM(0x1B,0x07), EV5, ARG_EV5HWMEM },
+ { "hw_ldq_l/w", EV5HWMEM(0x1B,0x0d), EV5, ARG_EV5HWMEM },
+ { "hw_ldq_l/wv", EV5HWMEM(0x1B,0x0f), EV5, ARG_EV5HWMEM },
+ { "hw_ld", EV4HWMEM(0x1B,0x0), EV4, ARG_EV4HWMEM },
+ { "hw_ld", EV5HWMEM(0x1B,0x00), EV5, ARG_EV5HWMEM },
+ { "hw_ld/a", EV4HWMEM(0x1B,0x4), EV4, ARG_EV4HWMEM },
+ { "hw_ld/a", EV5HWMEM(0x1B,0x10), EV5, ARG_EV5HWMEM },
+ { "hw_ld/al", EV5HWMEM(0x1B,0x11), EV5, ARG_EV5HWMEM },
+ { "hw_ld/aq", EV4HWMEM(0x1B,0x5), EV4, ARG_EV4HWMEM },
+ { "hw_ld/aq", EV5HWMEM(0x1B,0x14), EV5, ARG_EV5HWMEM },
+ { "hw_ld/aql", EV5HWMEM(0x1B,0x15), EV5, ARG_EV5HWMEM },
+ { "hw_ld/aqv", EV5HWMEM(0x1B,0x16), EV5, ARG_EV5HWMEM },
+ { "hw_ld/aqvl", EV5HWMEM(0x1B,0x17), EV5, ARG_EV5HWMEM },
+ { "hw_ld/ar", EV4HWMEM(0x1B,0x6), EV4, ARG_EV4HWMEM },
+ { "hw_ld/arq", EV4HWMEM(0x1B,0x7), EV4, ARG_EV4HWMEM },
+ { "hw_ld/av", EV5HWMEM(0x1B,0x12), EV5, ARG_EV5HWMEM },
+ { "hw_ld/avl", EV5HWMEM(0x1B,0x13), EV5, ARG_EV5HWMEM },
+ { "hw_ld/aw", EV5HWMEM(0x1B,0x18), EV5, ARG_EV5HWMEM },
+ { "hw_ld/awl", EV5HWMEM(0x1B,0x19), EV5, ARG_EV5HWMEM },
+ { "hw_ld/awq", EV5HWMEM(0x1B,0x1c), EV5, ARG_EV5HWMEM },
+ { "hw_ld/awql", EV5HWMEM(0x1B,0x1d), EV5, ARG_EV5HWMEM },
+ { "hw_ld/awqv", EV5HWMEM(0x1B,0x1e), EV5, ARG_EV5HWMEM },
+ { "hw_ld/awqvl", EV5HWMEM(0x1B,0x1f), EV5, ARG_EV5HWMEM },
+ { "hw_ld/awv", EV5HWMEM(0x1B,0x1a), EV5, ARG_EV5HWMEM },
+ { "hw_ld/awvl", EV5HWMEM(0x1B,0x1b), EV5, ARG_EV5HWMEM },
+ { "hw_ld/l", EV5HWMEM(0x1B,0x01), EV5, ARG_EV5HWMEM },
+ { "hw_ld/p", EV4HWMEM(0x1B,0x8), EV4, ARG_EV4HWMEM },
+ { "hw_ld/p", EV5HWMEM(0x1B,0x20), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pa", EV4HWMEM(0x1B,0xC), EV4, ARG_EV4HWMEM },
+ { "hw_ld/pa", EV5HWMEM(0x1B,0x30), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pal", EV5HWMEM(0x1B,0x31), EV5, ARG_EV5HWMEM },
+ { "hw_ld/paq", EV4HWMEM(0x1B,0xD), EV4, ARG_EV4HWMEM },
+ { "hw_ld/paq", EV5HWMEM(0x1B,0x34), EV5, ARG_EV5HWMEM },
+ { "hw_ld/paql", EV5HWMEM(0x1B,0x35), EV5, ARG_EV5HWMEM },
+ { "hw_ld/paqv", EV5HWMEM(0x1B,0x36), EV5, ARG_EV5HWMEM },
+ { "hw_ld/paqvl", EV5HWMEM(0x1B,0x37), EV5, ARG_EV5HWMEM },
+ { "hw_ld/par", EV4HWMEM(0x1B,0xE), EV4, ARG_EV4HWMEM },
+ { "hw_ld/parq", EV4HWMEM(0x1B,0xF), EV4, ARG_EV4HWMEM },
+ { "hw_ld/pav", EV5HWMEM(0x1B,0x32), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pavl", EV5HWMEM(0x1B,0x33), EV5, ARG_EV5HWMEM },
+ { "hw_ld/paw", EV5HWMEM(0x1B,0x38), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pawl", EV5HWMEM(0x1B,0x39), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pawq", EV5HWMEM(0x1B,0x3c), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pawql", EV5HWMEM(0x1B,0x3d), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pawqv", EV5HWMEM(0x1B,0x3e), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pawqvl", EV5HWMEM(0x1B,0x3f), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pawv", EV5HWMEM(0x1B,0x3a), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pawvl", EV5HWMEM(0x1B,0x3b), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pl", EV5HWMEM(0x1B,0x21), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pq", EV4HWMEM(0x1B,0x9), EV4, ARG_EV4HWMEM },
+ { "hw_ld/pq", EV5HWMEM(0x1B,0x24), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pql", EV5HWMEM(0x1B,0x25), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pqv", EV5HWMEM(0x1B,0x26), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pqvl", EV5HWMEM(0x1B,0x27), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pr", EV4HWMEM(0x1B,0xA), EV4, ARG_EV4HWMEM },
+ { "hw_ld/prq", EV4HWMEM(0x1B,0xB), EV4, ARG_EV4HWMEM },
+ { "hw_ld/pv", EV5HWMEM(0x1B,0x22), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pvl", EV5HWMEM(0x1B,0x23), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pw", EV5HWMEM(0x1B,0x28), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pwl", EV5HWMEM(0x1B,0x29), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pwq", EV5HWMEM(0x1B,0x2c), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pwql", EV5HWMEM(0x1B,0x2d), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pwqv", EV5HWMEM(0x1B,0x2e), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pwqvl", EV5HWMEM(0x1B,0x2f), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pwv", EV5HWMEM(0x1B,0x2a), EV5, ARG_EV5HWMEM },
+ { "hw_ld/pwvl", EV5HWMEM(0x1B,0x2b), EV5, ARG_EV5HWMEM },
+ { "hw_ld/q", EV4HWMEM(0x1B,0x1), EV4, ARG_EV4HWMEM },
+ { "hw_ld/q", EV5HWMEM(0x1B,0x04), EV5, ARG_EV5HWMEM },
+ { "hw_ld/ql", EV5HWMEM(0x1B,0x05), EV5, ARG_EV5HWMEM },
+ { "hw_ld/qv", EV5HWMEM(0x1B,0x06), EV5, ARG_EV5HWMEM },
+ { "hw_ld/qvl", EV5HWMEM(0x1B,0x07), EV5, ARG_EV5HWMEM },
+ { "hw_ld/r", EV4HWMEM(0x1B,0x2), EV4, ARG_EV4HWMEM },
+ { "hw_ld/rq", EV4HWMEM(0x1B,0x3), EV4, ARG_EV4HWMEM },
+ { "hw_ld/v", EV5HWMEM(0x1B,0x02), EV5, ARG_EV5HWMEM },
+ { "hw_ld/vl", EV5HWMEM(0x1B,0x03), EV5, ARG_EV5HWMEM },
+ { "hw_ld/w", EV5HWMEM(0x1B,0x08), EV5, ARG_EV5HWMEM },
+ { "hw_ld/wl", EV5HWMEM(0x1B,0x09), EV5, ARG_EV5HWMEM },
+ { "hw_ld/wq", EV5HWMEM(0x1B,0x0c), EV5, ARG_EV5HWMEM },
+ { "hw_ld/wql", EV5HWMEM(0x1B,0x0d), EV5, ARG_EV5HWMEM },
+ { "hw_ld/wqv", EV5HWMEM(0x1B,0x0e), EV5, ARG_EV5HWMEM },
+ { "hw_ld/wqvl", EV5HWMEM(0x1B,0x0f), EV5, ARG_EV5HWMEM },
+ { "hw_ld/wv", EV5HWMEM(0x1B,0x0a), EV5, ARG_EV5HWMEM },
+ { "hw_ld/wvl", EV5HWMEM(0x1B,0x0b), EV5, ARG_EV5HWMEM },
+ { "pal1b", PCD(0x1B), BASE, ARG_PCD },
+
+ { "sextb", OPR(0x1C, 0x00), BWX, ARG_OPRZ1 },
+ { "sextw", OPR(0x1C, 0x01), BWX, ARG_OPRZ1 },
+ { "ctpop", OPR(0x1C, 0x30), CIX, ARG_OPRZ1 },
+ { "perr", OPR(0x1C, 0x31), MAX, ARG_OPR },
+ { "ctlz", OPR(0x1C, 0x32), CIX, ARG_OPRZ1 },
+ { "cttz", OPR(0x1C, 0x33), CIX, ARG_OPRZ1 },
+ { "unpkbw", OPR(0x1C, 0x34), MAX, ARG_OPRZ1 },
+ { "unpkbl", OPR(0x1C, 0x35), MAX, ARG_OPRZ1 },
+ { "pkwb", OPR(0x1C, 0x36), MAX, ARG_OPRZ1 },
+ { "pklb", OPR(0x1C, 0x37), MAX, ARG_OPRZ1 },
+ { "minsb8", OPR(0x1C, 0x38), MAX, ARG_OPR },
+ { "minsb8", OPRL(0x1C, 0x38), MAX, ARG_OPRL },
+ { "minsw4", OPR(0x1C, 0x39), MAX, ARG_OPR },
+ { "minsw4", OPRL(0x1C, 0x39), MAX, ARG_OPRL },
+ { "minub8", OPR(0x1C, 0x3A), MAX, ARG_OPR },
+ { "minub8", OPRL(0x1C, 0x3A), MAX, ARG_OPRL },
+ { "minuw4", OPR(0x1C, 0x3B), MAX, ARG_OPR },
+ { "minuw4", OPRL(0x1C, 0x3B), MAX, ARG_OPRL },
+ { "maxub8", OPR(0x1C, 0x3C), MAX, ARG_OPR },
+ { "maxub8", OPRL(0x1C, 0x3C), MAX, ARG_OPRL },
+ { "maxuw4", OPR(0x1C, 0x3D), MAX, ARG_OPR },
+ { "maxuw4", OPRL(0x1C, 0x3D), MAX, ARG_OPRL },
+ { "maxsb8", OPR(0x1C, 0x3E), MAX, ARG_OPR },
+ { "maxsb8", OPRL(0x1C, 0x3E), MAX, ARG_OPRL },
+ { "maxsw4", OPR(0x1C, 0x3F), MAX, ARG_OPR },
+ { "maxsw4", OPRL(0x1C, 0x3F), MAX, ARG_OPRL },
+ { "ftoit", FP(0x1C, 0x70), CIX, { FA, ZB, RC } },
+ { "ftois", FP(0x1C, 0x78), CIX, { FA, ZB, RC } },
+
+ { "hw_mtpr", OPR(0x1D,0x00), EV4, { RA, RBA, EV4EXTHWINDEX } },
+ { "hw_mtpr", OP(0x1D), OP_MASK, EV5, { RA, RBA, EV5HWINDEX } },
+ { "hw_mtpr", OP(0x1D), OP_MASK, EV6, { ZA, RB, EV6HWINDEX } },
+ { "hw_mtpr/i", OPR(0x1D,0x01), EV4, ARG_EV4HWMPR },
+ { "hw_mtpr/a", OPR(0x1D,0x02), EV4, ARG_EV4HWMPR },
+ { "hw_mtpr/ai", OPR(0x1D,0x03), EV4, ARG_EV4HWMPR },
+ { "hw_mtpr/p", OPR(0x1D,0x04), EV4, ARG_EV4HWMPR },
+ { "hw_mtpr/pi", OPR(0x1D,0x05), EV4, ARG_EV4HWMPR },
+ { "hw_mtpr/pa", OPR(0x1D,0x06), EV4, ARG_EV4HWMPR },
+ { "hw_mtpr/pai", OPR(0x1D,0x07), EV4, ARG_EV4HWMPR },
+ { "pal1d", PCD(0x1D), BASE, ARG_PCD },
+
+ { "hw_rei", SPCD(0x1E,0x3FF8000), EV4|EV5, ARG_NONE },
+ { "hw_rei_stall", SPCD(0x1E,0x3FFC000), EV5, ARG_NONE },
+ { "hw_jmp", EV6HWMBR(0x1E,0x0), EV6, { ZA, PRB, EV6HWJMPHINT } },
+ { "hw_jsr", EV6HWMBR(0x1E,0x2), EV6, { ZA, PRB, EV6HWJMPHINT } },
+ { "hw_ret", EV6HWMBR(0x1E,0x4), EV6, { ZA, PRB } },
+ { "hw_jcr", EV6HWMBR(0x1E,0x6), EV6, { ZA, PRB } },
+ { "hw_coroutine", EV6HWMBR(0x1E,0x6), EV6, { ZA, PRB } }, /* alias */
+ { "hw_jmp/stall", EV6HWMBR(0x1E,0x1), EV6, { ZA, PRB, EV6HWJMPHINT } },
+ { "hw_jsr/stall", EV6HWMBR(0x1E,0x3), EV6, { ZA, PRB, EV6HWJMPHINT } },
+ { "hw_ret/stall", EV6HWMBR(0x1E,0x5), EV6, { ZA, PRB } },
+ { "hw_jcr/stall", EV6HWMBR(0x1E,0x7), EV6, { ZA, PRB } },
+ { "hw_coroutine/stall", EV6HWMBR(0x1E,0x7), EV6, { ZA, PRB } }, /* alias */
+ { "pal1e", PCD(0x1E), BASE, ARG_PCD },
+
+ { "hw_stl", EV4HWMEM(0x1F,0x0), EV4, ARG_EV4HWMEM },
+ { "hw_stl", EV5HWMEM(0x1F,0x00), EV5, ARG_EV5HWMEM },
+ { "hw_stl", EV6HWMEM(0x1F,0x4), EV6, ARG_EV6HWMEM }, /* ??? 8 */
+ { "hw_stl/a", EV4HWMEM(0x1F,0x4), EV4, ARG_EV4HWMEM },
+ { "hw_stl/a", EV5HWMEM(0x1F,0x10), EV5, ARG_EV5HWMEM },
+ { "hw_stl/a", EV6HWMEM(0x1F,0xC), EV6, ARG_EV6HWMEM },
+ { "hw_stl/ac", EV5HWMEM(0x1F,0x11), EV5, ARG_EV5HWMEM },
+ { "hw_stl/ar", EV4HWMEM(0x1F,0x6), EV4, ARG_EV4HWMEM },
+ { "hw_stl/av", EV5HWMEM(0x1F,0x12), EV5, ARG_EV5HWMEM },
+ { "hw_stl/avc", EV5HWMEM(0x1F,0x13), EV5, ARG_EV5HWMEM },
+ { "hw_stl/c", EV5HWMEM(0x1F,0x01), EV5, ARG_EV5HWMEM },
+ { "hw_stl/p", EV4HWMEM(0x1F,0x8), EV4, ARG_EV4HWMEM },
+ { "hw_stl/p", EV5HWMEM(0x1F,0x20), EV5, ARG_EV5HWMEM },
+ { "hw_stl/p", EV6HWMEM(0x1F,0x0), EV6, ARG_EV6HWMEM },
+ { "hw_stl/pa", EV4HWMEM(0x1F,0xC), EV4, ARG_EV4HWMEM },
+ { "hw_stl/pa", EV5HWMEM(0x1F,0x30), EV5, ARG_EV5HWMEM },
+ { "hw_stl/pac", EV5HWMEM(0x1F,0x31), EV5, ARG_EV5HWMEM },
+ { "hw_stl/pav", EV5HWMEM(0x1F,0x32), EV5, ARG_EV5HWMEM },
+ { "hw_stl/pavc", EV5HWMEM(0x1F,0x33), EV5, ARG_EV5HWMEM },
+ { "hw_stl/pc", EV5HWMEM(0x1F,0x21), EV5, ARG_EV5HWMEM },
+ { "hw_stl/pr", EV4HWMEM(0x1F,0xA), EV4, ARG_EV4HWMEM },
+ { "hw_stl/pv", EV5HWMEM(0x1F,0x22), EV5, ARG_EV5HWMEM },
+ { "hw_stl/pvc", EV5HWMEM(0x1F,0x23), EV5, ARG_EV5HWMEM },
+ { "hw_stl/r", EV4HWMEM(0x1F,0x2), EV4, ARG_EV4HWMEM },
+ { "hw_stl/v", EV5HWMEM(0x1F,0x02), EV5, ARG_EV5HWMEM },
+ { "hw_stl/vc", EV5HWMEM(0x1F,0x03), EV5, ARG_EV5HWMEM },
+ { "hw_stl_c", EV5HWMEM(0x1F,0x01), EV5, ARG_EV5HWMEM },
+ { "hw_stl_c/a", EV5HWMEM(0x1F,0x11), EV5, ARG_EV5HWMEM },
+ { "hw_stl_c/av", EV5HWMEM(0x1F,0x13), EV5, ARG_EV5HWMEM },
+ { "hw_stl_c/p", EV5HWMEM(0x1F,0x21), EV5, ARG_EV5HWMEM },
+ { "hw_stl_c/p", EV6HWMEM(0x1F,0x2), EV6, ARG_EV6HWMEM },
+ { "hw_stl_c/pa", EV5HWMEM(0x1F,0x31), EV5, ARG_EV5HWMEM },
+ { "hw_stl_c/pav", EV5HWMEM(0x1F,0x33), EV5, ARG_EV5HWMEM },
+ { "hw_stl_c/pv", EV5HWMEM(0x1F,0x23), EV5, ARG_EV5HWMEM },
+ { "hw_stl_c/v", EV5HWMEM(0x1F,0x03), EV5, ARG_EV5HWMEM },
+ { "hw_stq", EV4HWMEM(0x1F,0x1), EV4, ARG_EV4HWMEM },
+ { "hw_stq", EV5HWMEM(0x1F,0x04), EV5, ARG_EV5HWMEM },
+ { "hw_stq", EV6HWMEM(0x1F,0x5), EV6, ARG_EV6HWMEM }, /* ??? 9 */
+ { "hw_stq/a", EV4HWMEM(0x1F,0x5), EV4, ARG_EV4HWMEM },
+ { "hw_stq/a", EV5HWMEM(0x1F,0x14), EV5, ARG_EV5HWMEM },
+ { "hw_stq/a", EV6HWMEM(0x1F,0xD), EV6, ARG_EV6HWMEM },
+ { "hw_stq/ac", EV5HWMEM(0x1F,0x15), EV5, ARG_EV5HWMEM },
+ { "hw_stq/ar", EV4HWMEM(0x1F,0x7), EV4, ARG_EV4HWMEM },
+ { "hw_stq/av", EV5HWMEM(0x1F,0x16), EV5, ARG_EV5HWMEM },
+ { "hw_stq/avc", EV5HWMEM(0x1F,0x17), EV5, ARG_EV5HWMEM },
+ { "hw_stq/c", EV5HWMEM(0x1F,0x05), EV5, ARG_EV5HWMEM },
+ { "hw_stq/p", EV4HWMEM(0x1F,0x9), EV4, ARG_EV4HWMEM },
+ { "hw_stq/p", EV5HWMEM(0x1F,0x24), EV5, ARG_EV5HWMEM },
+ { "hw_stq/p", EV6HWMEM(0x1F,0x1), EV6, ARG_EV6HWMEM },
+ { "hw_stq/pa", EV4HWMEM(0x1F,0xD), EV4, ARG_EV4HWMEM },
+ { "hw_stq/pa", EV5HWMEM(0x1F,0x34), EV5, ARG_EV5HWMEM },
+ { "hw_stq/pac", EV5HWMEM(0x1F,0x35), EV5, ARG_EV5HWMEM },
+ { "hw_stq/par", EV4HWMEM(0x1F,0xE), EV4, ARG_EV4HWMEM },
+ { "hw_stq/par", EV4HWMEM(0x1F,0xF), EV4, ARG_EV4HWMEM },
+ { "hw_stq/pav", EV5HWMEM(0x1F,0x36), EV5, ARG_EV5HWMEM },
+ { "hw_stq/pavc", EV5HWMEM(0x1F,0x37), EV5, ARG_EV5HWMEM },
+ { "hw_stq/pc", EV5HWMEM(0x1F,0x25), EV5, ARG_EV5HWMEM },
+ { "hw_stq/pr", EV4HWMEM(0x1F,0xB), EV4, ARG_EV4HWMEM },
+ { "hw_stq/pv", EV5HWMEM(0x1F,0x26), EV5, ARG_EV5HWMEM },
+ { "hw_stq/pvc", EV5HWMEM(0x1F,0x27), EV5, ARG_EV5HWMEM },
+ { "hw_stq/r", EV4HWMEM(0x1F,0x3), EV4, ARG_EV4HWMEM },
+ { "hw_stq/v", EV5HWMEM(0x1F,0x06), EV5, ARG_EV5HWMEM },
+ { "hw_stq/vc", EV5HWMEM(0x1F,0x07), EV5, ARG_EV5HWMEM },
+ { "hw_stq_c", EV5HWMEM(0x1F,0x05), EV5, ARG_EV5HWMEM },
+ { "hw_stq_c/a", EV5HWMEM(0x1F,0x15), EV5, ARG_EV5HWMEM },
+ { "hw_stq_c/av", EV5HWMEM(0x1F,0x17), EV5, ARG_EV5HWMEM },
+ { "hw_stq_c/p", EV5HWMEM(0x1F,0x25), EV5, ARG_EV5HWMEM },
+ { "hw_stq_c/p", EV6HWMEM(0x1F,0x3), EV6, ARG_EV6HWMEM },
+ { "hw_stq_c/pa", EV5HWMEM(0x1F,0x35), EV5, ARG_EV5HWMEM },
+ { "hw_stq_c/pav", EV5HWMEM(0x1F,0x37), EV5, ARG_EV5HWMEM },
+ { "hw_stq_c/pv", EV5HWMEM(0x1F,0x27), EV5, ARG_EV5HWMEM },
+ { "hw_stq_c/v", EV5HWMEM(0x1F,0x07), EV5, ARG_EV5HWMEM },
+ { "hw_st", EV4HWMEM(0x1F,0x0), EV4, ARG_EV4HWMEM },
+ { "hw_st", EV5HWMEM(0x1F,0x00), EV5, ARG_EV5HWMEM },
+ { "hw_st/a", EV4HWMEM(0x1F,0x4), EV4, ARG_EV4HWMEM },
+ { "hw_st/a", EV5HWMEM(0x1F,0x10), EV5, ARG_EV5HWMEM },
+ { "hw_st/ac", EV5HWMEM(0x1F,0x11), EV5, ARG_EV5HWMEM },
+ { "hw_st/aq", EV4HWMEM(0x1F,0x5), EV4, ARG_EV4HWMEM },
+ { "hw_st/aq", EV5HWMEM(0x1F,0x14), EV5, ARG_EV5HWMEM },
+ { "hw_st/aqc", EV5HWMEM(0x1F,0x15), EV5, ARG_EV5HWMEM },
+ { "hw_st/aqv", EV5HWMEM(0x1F,0x16), EV5, ARG_EV5HWMEM },
+ { "hw_st/aqvc", EV5HWMEM(0x1F,0x17), EV5, ARG_EV5HWMEM },
+ { "hw_st/ar", EV4HWMEM(0x1F,0x6), EV4, ARG_EV4HWMEM },
+ { "hw_st/arq", EV4HWMEM(0x1F,0x7), EV4, ARG_EV4HWMEM },
+ { "hw_st/av", EV5HWMEM(0x1F,0x12), EV5, ARG_EV5HWMEM },
+ { "hw_st/avc", EV5HWMEM(0x1F,0x13), EV5, ARG_EV5HWMEM },
+ { "hw_st/c", EV5HWMEM(0x1F,0x01), EV5, ARG_EV5HWMEM },
+ { "hw_st/p", EV4HWMEM(0x1F,0x8), EV4, ARG_EV4HWMEM },
+ { "hw_st/p", EV5HWMEM(0x1F,0x20), EV5, ARG_EV5HWMEM },
+ { "hw_st/pa", EV4HWMEM(0x1F,0xC), EV4, ARG_EV4HWMEM },
+ { "hw_st/pa", EV5HWMEM(0x1F,0x30), EV5, ARG_EV5HWMEM },
+ { "hw_st/pac", EV5HWMEM(0x1F,0x31), EV5, ARG_EV5HWMEM },
+ { "hw_st/paq", EV4HWMEM(0x1F,0xD), EV4, ARG_EV4HWMEM },
+ { "hw_st/paq", EV5HWMEM(0x1F,0x34), EV5, ARG_EV5HWMEM },
+ { "hw_st/paqc", EV5HWMEM(0x1F,0x35), EV5, ARG_EV5HWMEM },
+ { "hw_st/paqv", EV5HWMEM(0x1F,0x36), EV5, ARG_EV5HWMEM },
+ { "hw_st/paqvc", EV5HWMEM(0x1F,0x37), EV5, ARG_EV5HWMEM },
+ { "hw_st/par", EV4HWMEM(0x1F,0xE), EV4, ARG_EV4HWMEM },
+ { "hw_st/parq", EV4HWMEM(0x1F,0xF), EV4, ARG_EV4HWMEM },
+ { "hw_st/pav", EV5HWMEM(0x1F,0x32), EV5, ARG_EV5HWMEM },
+ { "hw_st/pavc", EV5HWMEM(0x1F,0x33), EV5, ARG_EV5HWMEM },
+ { "hw_st/pc", EV5HWMEM(0x1F,0x21), EV5, ARG_EV5HWMEM },
+ { "hw_st/pq", EV4HWMEM(0x1F,0x9), EV4, ARG_EV4HWMEM },
+ { "hw_st/pq", EV5HWMEM(0x1F,0x24), EV5, ARG_EV5HWMEM },
+ { "hw_st/pqc", EV5HWMEM(0x1F,0x25), EV5, ARG_EV5HWMEM },
+ { "hw_st/pqv", EV5HWMEM(0x1F,0x26), EV5, ARG_EV5HWMEM },
+ { "hw_st/pqvc", EV5HWMEM(0x1F,0x27), EV5, ARG_EV5HWMEM },
+ { "hw_st/pr", EV4HWMEM(0x1F,0xA), EV4, ARG_EV4HWMEM },
+ { "hw_st/prq", EV4HWMEM(0x1F,0xB), EV4, ARG_EV4HWMEM },
+ { "hw_st/pv", EV5HWMEM(0x1F,0x22), EV5, ARG_EV5HWMEM },
+ { "hw_st/pvc", EV5HWMEM(0x1F,0x23), EV5, ARG_EV5HWMEM },
+ { "hw_st/q", EV4HWMEM(0x1F,0x1), EV4, ARG_EV4HWMEM },
+ { "hw_st/q", EV5HWMEM(0x1F,0x04), EV5, ARG_EV5HWMEM },
+ { "hw_st/qc", EV5HWMEM(0x1F,0x05), EV5, ARG_EV5HWMEM },
+ { "hw_st/qv", EV5HWMEM(0x1F,0x06), EV5, ARG_EV5HWMEM },
+ { "hw_st/qvc", EV5HWMEM(0x1F,0x07), EV5, ARG_EV5HWMEM },
+ { "hw_st/r", EV4HWMEM(0x1F,0x2), EV4, ARG_EV4HWMEM },
+ { "hw_st/v", EV5HWMEM(0x1F,0x02), EV5, ARG_EV5HWMEM },
+ { "hw_st/vc", EV5HWMEM(0x1F,0x03), EV5, ARG_EV5HWMEM },
+ { "pal1f", PCD(0x1F), BASE, ARG_PCD },
+
+ { "ldf", MEM(0x20), BASE, ARG_FMEM },
+ { "ldg", MEM(0x21), BASE, ARG_FMEM },
+ { "lds", MEM(0x22), BASE, ARG_FMEM },
+ { "ldt", MEM(0x23), BASE, ARG_FMEM },
+ { "stf", MEM(0x24), BASE, ARG_FMEM },
+ { "stg", MEM(0x25), BASE, ARG_FMEM },
+ { "sts", MEM(0x26), BASE, ARG_FMEM },
+ { "stt", MEM(0x27), BASE, ARG_FMEM },
+
+ { "ldl", MEM(0x28), BASE, ARG_MEM },
+ { "ldq", MEM(0x29), BASE, ARG_MEM },
+ { "ldl_l", MEM(0x2A), BASE, ARG_MEM },
+ { "ldq_l", MEM(0x2B), BASE, ARG_MEM },
+ { "stl", MEM(0x2C), BASE, ARG_MEM },
+ { "stq", MEM(0x2D), BASE, ARG_MEM },
+ { "stl_c", MEM(0x2E), BASE, ARG_MEM },
+ { "stq_c", MEM(0x2F), BASE, ARG_MEM },
+
+ { "br", BRA(0x30), BASE, { ZA, BDISP } }, /* pseudo */
+ { "br", BRA(0x30), BASE, ARG_BRA },
+ { "fbeq", BRA(0x31), BASE, ARG_FBRA },
+ { "fblt", BRA(0x32), BASE, ARG_FBRA },
+ { "fble", BRA(0x33), BASE, ARG_FBRA },
+ { "bsr", BRA(0x34), BASE, ARG_BRA },
+ { "fbne", BRA(0x35), BASE, ARG_FBRA },
+ { "fbge", BRA(0x36), BASE, ARG_FBRA },
+ { "fbgt", BRA(0x37), BASE, ARG_FBRA },
+ { "blbc", BRA(0x38), BASE, ARG_BRA },
+ { "beq", BRA(0x39), BASE, ARG_BRA },
+ { "blt", BRA(0x3A), BASE, ARG_BRA },
+ { "ble", BRA(0x3B), BASE, ARG_BRA },
+ { "blbs", BRA(0x3C), BASE, ARG_BRA },
+ { "bne", BRA(0x3D), BASE, ARG_BRA },
+ { "bge", BRA(0x3E), BASE, ARG_BRA },
+ { "bgt", BRA(0x3F), BASE, ARG_BRA },
+};
+
+const unsigned alpha_num_opcodes = sizeof(alpha_opcodes)/sizeof(*alpha_opcodes);
+
+/* OSF register names. */
+
+static const char * const osf_regnames[64] = {
+ "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6",
+ "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp",
+ "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9",
+ "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero",
+ "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
+ "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
+ "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
+ "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31"
+};
+
+/* VMS register names. */
+
+static const char * const vms_regnames[64] = {
+ "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
+ "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
+ "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23",
+ "R24", "AI", "RA", "PV", "AT", "FP", "SP", "RZ",
+ "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7",
+ "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15",
+ "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23",
+ "F24", "F25", "F26", "F27", "F28", "F29", "F30", "FZ"
+};
+
+/* Disassemble Alpha instructions. */
+
+int
+print_insn_alpha (memaddr, info)
+ bfd_vma memaddr;
+ struct disassemble_info *info;
+{
+ static const struct alpha_opcode *opcode_index[AXP_NOPS+1];
+ const char * const * regnames;
+ const struct alpha_opcode *opcode, *opcode_end;
+ const unsigned char *opindex;
+ unsigned insn, op, isa_mask;
+ int need_comma;
+
+ /* Initialize the majorop table the first time through */
+ if (!opcode_index[0])
+ {
+ opcode = alpha_opcodes;
+ opcode_end = opcode + alpha_num_opcodes;
+
+ for (op = 0; op < AXP_NOPS; ++op)
+ {
+ opcode_index[op] = opcode;
+ while (opcode < opcode_end && op == AXP_OP (opcode->opcode))
+ ++opcode;
+ }
+ opcode_index[op] = opcode;
+ }
+
+ if (info->flavour == bfd_target_evax_flavour)
+ regnames = vms_regnames;
+ else
+ regnames = osf_regnames;
+
+ isa_mask = AXP_OPCODE_NOPAL;
+ switch (info->mach)
+ {
+ case bfd_mach_alpha_ev4:
+ isa_mask |= AXP_OPCODE_EV4;
+ break;
+ case bfd_mach_alpha_ev5:
+ isa_mask |= AXP_OPCODE_EV5;
+ break;
+ case bfd_mach_alpha_ev6:
+ isa_mask |= AXP_OPCODE_EV6;
+ break;
+ }
+
+ /* Read the insn into a host word */
+ {
+ bfd_byte buffer[4];
+ int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
+ if (status != 0)
+ {
+ (*info->memory_error_func) (status, memaddr, info);
+ return -1;
+ }
+ insn = bfd_getl32 (buffer);
+ }
+
+ /* Get the major opcode of the instruction. */
+ op = AXP_OP (insn);
+
+ /* Find the first match in the opcode table. */
+ opcode_end = opcode_index[op + 1];
+ for (opcode = opcode_index[op]; opcode < opcode_end; ++opcode)
+ {
+ if ((insn ^ opcode->opcode) & opcode->mask)
+ continue;
+
+ if (!(opcode->flags & isa_mask))
+ continue;
+
+ /* Make two passes over the operands. First see if any of them
+ have extraction functions, and, if they do, make sure the
+ instruction is valid. */
+ {
+ int invalid = 0;
+ for (opindex = opcode->operands; *opindex != 0; opindex++)
+ {
+ const struct alpha_operand *operand = alpha_operands + *opindex;
+ if (operand->extract)
+ (*operand->extract) (insn, &invalid);
+ }
+ if (invalid)
+ continue;
+ }
+
+ /* The instruction is valid. */
+ goto found;
+ }
+
+ /* No instruction found */
+ (*info->fprintf_func) (info->stream, ".long %#08x", insn);
+
+ return 4;
+
+found:
+ (*info->fprintf_func) (info->stream, "%s", opcode->name);
+ if (opcode->operands[0] != 0)
+ (*info->fprintf_func) (info->stream, "\t");
+
+ /* Now extract and print the operands. */
+ need_comma = 0;
+ for (opindex = opcode->operands; *opindex != 0; opindex++)
+ {
+ const struct alpha_operand *operand = alpha_operands + *opindex;
+ int value;
+
+ /* Operands that are marked FAKE are simply ignored. We
+ already made sure that the extract function considered
+ the instruction to be valid. */
+ if ((operand->flags & AXP_OPERAND_FAKE) != 0)
+ continue;
+
+ /* Extract the value from the instruction. */
+ if (operand->extract)
+ value = (*operand->extract) (insn, (int *) NULL);
+ else
+ {
+ value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
+ if (operand->flags & AXP_OPERAND_SIGNED)
+ {
+ int signbit = 1 << (operand->bits - 1);
+ value = (value ^ signbit) - signbit;
+ }
+ }
+
+ if (need_comma &&
+ ((operand->flags & (AXP_OPERAND_PARENS | AXP_OPERAND_COMMA))
+ != AXP_OPERAND_PARENS))
+ {
+ (*info->fprintf_func) (info->stream, ",");
+ }
+ if (operand->flags & AXP_OPERAND_PARENS)
+ (*info->fprintf_func) (info->stream, "(");
+
+ /* Print the operand as directed by the flags. */
+ if (operand->flags & AXP_OPERAND_IR)
+ (*info->fprintf_func) (info->stream, "%s", regnames[value]);
+ else if (operand->flags & AXP_OPERAND_FPR)
+ (*info->fprintf_func) (info->stream, "%s", regnames[value + 32]);
+ else if (operand->flags & AXP_OPERAND_RELATIVE)
+ (*info->print_address_func) (memaddr + 4 + value, info);
+ else if (operand->flags & AXP_OPERAND_SIGNED)
+ (*info->fprintf_func) (info->stream, "%d", value);
+ else
+ (*info->fprintf_func) (info->stream, "%#x", value);
+
+ if (operand->flags & AXP_OPERAND_PARENS)
+ (*info->fprintf_func) (info->stream, ")");
+ need_comma = 1;
+ }
+
+ return 4;
+}
Added: trunk/src/host/qemu-neo1973/alpha.ld
===================================================================
--- trunk/src/host/qemu-neo1973/alpha.ld 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/alpha.ld 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,128 @@
+OUTPUT_FORMAT("elf64-alpha", "elf64-alpha",
+ "elf64-alpha")
+OUTPUT_ARCH(alpha)
+ENTRY(__start)
+SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0x60000000 + SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rel.text :
+ { *(.rel.text) *(.rel.gnu.linkonce.t*) }
+ .rela.text :
+ { *(.rela.text) *(.rela.gnu.linkonce.t*) }
+ .rel.data :
+ { *(.rel.data) *(.rel.gnu.linkonce.d*) }
+ .rela.data :
+ { *(.rela.data) *(.rela.gnu.linkonce.d*) }
+ .rel.rodata :
+ { *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
+ .rela.rodata :
+ { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
+ .rel.got : { *(.rel.got) }
+ .rela.got : { *(.rela.got) }
+ .rel.ctors : { *(.rel.ctors) }
+ .rela.ctors : { *(.rela.ctors) }
+ .rel.dtors : { *(.rel.dtors) }
+ .rela.dtors : { *(.rela.dtors) }
+ .rel.init : { *(.rel.init) }
+ .rela.init : { *(.rela.init) }
+ .rel.fini : { *(.rel.fini) }
+ .rela.fini : { *(.rela.fini) }
+ .rel.bss : { *(.rel.bss) }
+ .rela.bss : { *(.rela.bss) }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ .init : { *(.init) } =0x47ff041f
+ .text :
+ {
+ *(.text)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ *(.gnu.linkonce.t*)
+ } =0x47ff041f
+ _etext = .;
+ PROVIDE (etext = .);
+ .fini : { *(.fini) } =0x47ff041f
+ .rodata : { *(.rodata) *(.gnu.linkonce.r*) }
+ .rodata1 : { *(.rodata1) }
+ .reginfo : { *(.reginfo) }
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. */
+ . = ALIGN(0x100000) + (. & (0x100000 - 1));
+ .data :
+ {
+ *(.data)
+ *(.gnu.linkonce.d*)
+ CONSTRUCTORS
+ }
+ .data1 : { *(.data1) }
+ .ctors :
+ {
+ *(.ctors)
+ }
+ .dtors :
+ {
+ *(.dtors)
+ }
+ .plt : { *(.plt) }
+ .got : { *(.got.plt) *(.got) }
+ .dynamic : { *(.dynamic) }
+ /* We want the small data sections together, so single-instruction offsets
+ can access them all, and initialized data all before uninitialized, so
+ we can shorten the on-disk segment size. */
+ .sdata : { *(.sdata) }
+ _edata = .;
+ PROVIDE (edata = .);
+ __bss_start = .;
+ .sbss : { *(.sbss) *(.scommon) }
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ }
+ _end = . ;
+ PROVIDE (end = .);
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /* These must appear regardless of . */
+}
Added: trunk/src/host/qemu-neo1973/arm-dis.c
===================================================================
--- trunk/src/host/qemu-neo1973/arm-dis.c 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/arm-dis.c 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,1680 @@
+/* Instruction printing code for the ARM
+ Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+ Free Software Foundation, Inc.
+ Contributed by Richard Earnshaw (rwe at pegasus.esprit.ec.org)
+ Modification by James G. Smith (jsmith at cygnus.co.uk)
+
+This file is part of libopcodes.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "dis-asm.h"
+
+struct arm_opcode {
+ unsigned long value, mask; /* recognise instruction if (op&mask)==value */
+ char *assembler; /* how to disassemble this instruction */
+};
+
+struct thumb_opcode
+{
+ unsigned short value, mask; /* recognise instruction if (op&mask)==value */
+ char * assembler; /* how to disassemble this instruction */
+};
+
+/* format of the assembler string :
+
+ %% %
+ %<bitfield>d print the bitfield in decimal
+ %<bitfield>x print the bitfield in hex
+ %<bitfield>X print the bitfield as 1 hex digit without leading "0x"
+ %<bitfield>r print as an ARM register
+ %<bitfield>f print a floating point constant if >7 else a
+ floating point register
+ %<code>y print a single precision VFP reg.
+ Codes: 0=>Sm, 1=>Sd, 2=>Sn, 3=>multi-list, 4=>Sm pair
+ %<code>z print a double precision VFP reg
+ Codes: 0=>Dm, 1=>Dd, 2=>Dn, 3=>multi-list
+ %c print condition code (always bits 28-31)
+ %P print floating point precision in arithmetic insn
+ %Q print floating point precision in ldf/stf insn
+ %R print floating point rounding mode
+ %<bitnum>'c print specified char iff bit is one
+ %<bitnum>`c print specified char iff bit is zero
+ %<bitnum>?ab print a if bit is one else print b
+ %p print 'p' iff bits 12-15 are 15
+ %t print 't' iff bit 21 set and bit 24 clear
+ %o print operand2 (immediate or register + shift)
+ %a print address for ldr/str instruction
+ %s print address for ldr/str halfword/signextend instruction
+ %b print branch destination
+ %B print arm BLX(1) destination
+ %A print address for ldc/stc/ldf/stf instruction
+ %m print register mask for ldm/stm instruction
+ %C print the PSR sub type.
+ %F print the COUNT field of a LFM/SFM instruction.
+Thumb specific format options:
+ %D print Thumb register (bits 0..2 as high number if bit 7 set)
+ %S print Thumb register (bits 3..5 as high number if bit 6 set)
+ %<bitfield>I print bitfield as a signed decimal
+ (top bit of range being the sign bit)
+ %M print Thumb register mask
+ %N print Thumb register mask (with LR)
+ %O print Thumb register mask (with PC)
+ %T print Thumb condition code (always bits 8-11)
+ %I print cirrus signed shift immediate: bits 0..3|4..6
+ %<bitfield>B print Thumb branch destination (signed displacement)
+ %<bitfield>W print (bitfield * 4) as a decimal
+ %<bitfield>H print (bitfield * 2) as a decimal
+ %<bitfield>a print (bitfield * 4) as a pc-rel offset + decoded symbol
+*/
+
+/* Note: There is a partial ordering in this table - it must be searched from
+ the top to obtain a correct match. */
+
+static struct arm_opcode arm_opcodes[] =
+{
+ /* ARM instructions. */
+ {0xe1a00000, 0xffffffff, "nop\t\t\t(mov r0,r0)"},
+ {0x012FFF10, 0x0ffffff0, "bx%c\t%0-3r"},
+ {0x00000090, 0x0fe000f0, "mul%c%20's\t%16-19r, %0-3r, %8-11r"},
+ {0x00200090, 0x0fe000f0, "mla%c%20's\t%16-19r, %0-3r, %8-11r, %12-15r"},
+ {0x01000090, 0x0fb00ff0, "swp%c%22'b\t%12-15r, %0-3r, [%16-19r]"},
+ {0x00800090, 0x0fa000f0, "%22?sumull%c%20's\t%12-15r, %16-19r, %0-3r, %8-11r"},
+ {0x00a00090, 0x0fa000f0, "%22?sumlal%c%20's\t%12-15r, %16-19r, %0-3r, %8-11r"},
+
+ /* V5J instruction. */
+ {0x012fff20, 0x0ffffff0, "bxj%c\t%0-3r"},
+
+ /* XScale instructions. */
+ {0x0e200010, 0x0fff0ff0, "mia%c\tacc0, %0-3r, %12-15r"},
+ {0x0e280010, 0x0fff0ff0, "miaph%c\tacc0, %0-3r, %12-15r"},
+ {0x0e2c0010, 0x0ffc0ff0, "mia%17'T%17`B%16'T%16`B%c\tacc0, %0-3r, %12-15r"},
+ {0x0c400000, 0x0ff00fff, "mar%c\tacc0, %12-15r, %16-19r"},
+ {0x0c500000, 0x0ff00fff, "mra%c\t%12-15r, %16-19r, acc0"},
+ {0xf450f000, 0xfc70f000, "pld\t%a"},
+
+ /* V5 Instructions. */
+ {0xe1200070, 0xfff000f0, "bkpt\t0x%16-19X%12-15X%8-11X%0-3X"},
+ {0xfa000000, 0xfe000000, "blx\t%B"},
+ {0x012fff30, 0x0ffffff0, "blx%c\t%0-3r"},
+ {0x016f0f10, 0x0fff0ff0, "clz%c\t%12-15r, %0-3r"},
+ {0xfc100000, 0xfe100000, "ldc2%22'l\t%8-11d, cr%12-15d, %A"},
+ {0xfc000000, 0xfe100000, "stc2%22'l\t%8-11d, cr%12-15d, %A"},
+ {0xfe000000, 0xff000010, "cdp2\t%8-11d, %20-23d, cr%12-15d, cr%16-19d, cr%0-3d, {%5-7d}"},
+ {0xfe000010, 0xff100010, "mcr2\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"},
+ {0xfe100010, 0xff100010, "mrc2\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"},
+
+ /* V5E "El Segundo" Instructions. */
+ {0x000000d0, 0x0e1000f0, "ldr%cd\t%12-15r, %s"},
+ {0x000000f0, 0x0e1000f0, "str%cd\t%12-15r, %s"},
+ {0x01000080, 0x0ff000f0, "smlabb%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
+ {0x010000a0, 0x0ff000f0, "smlatb%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
+ {0x010000c0, 0x0ff000f0, "smlabt%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
+ {0x010000e0, 0x0ff000f0, "smlatt%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
+
+ {0x01200080, 0x0ff000f0, "smlawb%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
+ {0x012000c0, 0x0ff000f0, "smlawt%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
+
+ {0x01400080, 0x0ff000f0, "smlalbb%c\t%12-15r, %16-19r, %0-3r, %8-11r"},
+ {0x014000a0, 0x0ff000f0, "smlaltb%c\t%12-15r, %16-19r, %0-3r, %8-11r"},
+ {0x014000c0, 0x0ff000f0, "smlalbt%c\t%12-15r, %16-19r, %0-3r, %8-11r"},
+ {0x014000e0, 0x0ff000f0, "smlaltt%c\t%12-15r, %16-19r, %0-3r, %8-11r"},
+
+ {0x01600080, 0x0ff0f0f0, "smulbb%c\t%16-19r, %0-3r, %8-11r"},
+ {0x016000a0, 0x0ff0f0f0, "smultb%c\t%16-19r, %0-3r, %8-11r"},
+ {0x016000c0, 0x0ff0f0f0, "smulbt%c\t%16-19r, %0-3r, %8-11r"},
+ {0x016000e0, 0x0ff0f0f0, "smultt%c\t%16-19r, %0-3r, %8-11r"},
+
+ {0x012000a0, 0x0ff0f0f0, "smulwb%c\t%16-19r, %0-3r, %8-11r"},
+ {0x012000e0, 0x0ff0f0f0, "smulwt%c\t%16-19r, %0-3r, %8-11r"},
+
+ {0x01000050, 0x0ff00ff0, "qadd%c\t%12-15r, %0-3r, %16-19r"},
+ {0x01400050, 0x0ff00ff0, "qdadd%c\t%12-15r, %0-3r, %16-19r"},
+ {0x01200050, 0x0ff00ff0, "qsub%c\t%12-15r, %0-3r, %16-19r"},
+ {0x01600050, 0x0ff00ff0, "qdsub%c\t%12-15r, %0-3r, %16-19r"},
+
+ {0x0c400000, 0x0ff00000, "mcrr%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"},
+ {0x0c500000, 0x0ff00000, "mrrc%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"},
+
+ /* ARM Instructions. */
+ {0x00000090, 0x0e100090, "str%c%6's%5?hb\t%12-15r, %s"},
+ {0x00100090, 0x0e100090, "ldr%c%6's%5?hb\t%12-15r, %s"},
+ {0x00000000, 0x0de00000, "and%c%20's\t%12-15r, %16-19r, %o"},
+ {0x00200000, 0x0de00000, "eor%c%20's\t%12-15r, %16-19r, %o"},
+ {0x00400000, 0x0de00000, "sub%c%20's\t%12-15r, %16-19r, %o"},
+ {0x00600000, 0x0de00000, "rsb%c%20's\t%12-15r, %16-19r, %o"},
+ {0x00800000, 0x0de00000, "add%c%20's\t%12-15r, %16-19r, %o"},
+ {0x00a00000, 0x0de00000, "adc%c%20's\t%12-15r, %16-19r, %o"},
+ {0x00c00000, 0x0de00000, "sbc%c%20's\t%12-15r, %16-19r, %o"},
+ {0x00e00000, 0x0de00000, "rsc%c%20's\t%12-15r, %16-19r, %o"},
+ {0x0120f000, 0x0db0f000, "msr%c\t%22?SCPSR%C, %o"},
+ {0x010f0000, 0x0fbf0fff, "mrs%c\t%12-15r, %22?SCPSR"},
+ {0x01000000, 0x0de00000, "tst%c%p\t%16-19r, %o"},
+ {0x01200000, 0x0de00000, "teq%c%p\t%16-19r, %o"},
+ {0x01400000, 0x0de00000, "cmp%c%p\t%16-19r, %o"},
+ {0x01600000, 0x0de00000, "cmn%c%p\t%16-19r, %o"},
+ {0x01800000, 0x0de00000, "orr%c%20's\t%12-15r, %16-19r, %o"},
+ {0x01a00000, 0x0de00000, "mov%c%20's\t%12-15r, %o"},
+ {0x01c00000, 0x0de00000, "bic%c%20's\t%12-15r, %16-19r, %o"},
+ {0x01e00000, 0x0de00000, "mvn%c%20's\t%12-15r, %o"},
+ {0x04000000, 0x0e100000, "str%c%22'b%t\t%12-15r, %a"},
+ {0x06000000, 0x0e100ff0, "str%c%22'b%t\t%12-15r, %a"},
+ {0x04000000, 0x0c100010, "str%c%22'b%t\t%12-15r, %a"},
+ {0x06000010, 0x0e000010, "undefined"},
+ {0x04100000, 0x0c100000, "ldr%c%22'b%t\t%12-15r, %a"},
+ {0x08000000, 0x0e100000, "stm%c%23?id%24?ba\t%16-19r%21'!, %m%22'^"},
+ {0x08100000, 0x0e100000, "ldm%c%23?id%24?ba\t%16-19r%21'!, %m%22'^"},
+ {0x0a000000, 0x0e000000, "b%24'l%c\t%b"},
+ {0x0f000000, 0x0f000000, "swi%c\t%0-23x"},
+
+ /* Floating point coprocessor (FPA) instructions */
+ {0x0e000100, 0x0ff08f10, "adf%c%P%R\t%12-14f, %16-18f, %0-3f"},
+ {0x0e100100, 0x0ff08f10, "muf%c%P%R\t%12-14f, %16-18f, %0-3f"},
+ {0x0e200100, 0x0ff08f10, "suf%c%P%R\t%12-14f, %16-18f, %0-3f"},
+ {0x0e300100, 0x0ff08f10, "rsf%c%P%R\t%12-14f, %16-18f, %0-3f"},
+ {0x0e400100, 0x0ff08f10, "dvf%c%P%R\t%12-14f, %16-18f, %0-3f"},
+ {0x0e500100, 0x0ff08f10, "rdf%c%P%R\t%12-14f, %16-18f, %0-3f"},
+ {0x0e600100, 0x0ff08f10, "pow%c%P%R\t%12-14f, %16-18f, %0-3f"},
+ {0x0e700100, 0x0ff08f10, "rpw%c%P%R\t%12-14f, %16-18f, %0-3f"},
+ {0x0e800100, 0x0ff08f10, "rmf%c%P%R\t%12-14f, %16-18f, %0-3f"},
+ {0x0e900100, 0x0ff08f10, "fml%c%P%R\t%12-14f, %16-18f, %0-3f"},
+ {0x0ea00100, 0x0ff08f10, "fdv%c%P%R\t%12-14f, %16-18f, %0-3f"},
+ {0x0eb00100, 0x0ff08f10, "frd%c%P%R\t%12-14f, %16-18f, %0-3f"},
+ {0x0ec00100, 0x0ff08f10, "pol%c%P%R\t%12-14f, %16-18f, %0-3f"},
+ {0x0e008100, 0x0ff08f10, "mvf%c%P%R\t%12-14f, %0-3f"},
+ {0x0e108100, 0x0ff08f10, "mnf%c%P%R\t%12-14f, %0-3f"},
+ {0x0e208100, 0x0ff08f10, "abs%c%P%R\t%12-14f, %0-3f"},
+ {0x0e308100, 0x0ff08f10, "rnd%c%P%R\t%12-14f, %0-3f"},
+ {0x0e408100, 0x0ff08f10, "sqt%c%P%R\t%12-14f, %0-3f"},
+ {0x0e508100, 0x0ff08f10, "log%c%P%R\t%12-14f, %0-3f"},
+ {0x0e608100, 0x0ff08f10, "lgn%c%P%R\t%12-14f, %0-3f"},
+ {0x0e708100, 0x0ff08f10, "exp%c%P%R\t%12-14f, %0-3f"},
+ {0x0e808100, 0x0ff08f10, "sin%c%P%R\t%12-14f, %0-3f"},
+ {0x0e908100, 0x0ff08f10, "cos%c%P%R\t%12-14f, %0-3f"},
+ {0x0ea08100, 0x0ff08f10, "tan%c%P%R\t%12-14f, %0-3f"},
+ {0x0eb08100, 0x0ff08f10, "asn%c%P%R\t%12-14f, %0-3f"},
+ {0x0ec08100, 0x0ff08f10, "acs%c%P%R\t%12-14f, %0-3f"},
+ {0x0ed08100, 0x0ff08f10, "atn%c%P%R\t%12-14f, %0-3f"},
+ {0x0ee08100, 0x0ff08f10, "urd%c%P%R\t%12-14f, %0-3f"},
+ {0x0ef08100, 0x0ff08f10, "nrm%c%P%R\t%12-14f, %0-3f"},
+ {0x0e000110, 0x0ff00f1f, "flt%c%P%R\t%16-18f, %12-15r"},
+ {0x0e100110, 0x0fff0f98, "fix%c%R\t%12-15r, %0-2f"},
+ {0x0e200110, 0x0fff0fff, "wfs%c\t%12-15r"},
+ {0x0e300110, 0x0fff0fff, "rfs%c\t%12-15r"},
+ {0x0e400110, 0x0fff0fff, "wfc%c\t%12-15r"},
+ {0x0e500110, 0x0fff0fff, "rfc%c\t%12-15r"},
+ {0x0e90f110, 0x0ff8fff0, "cmf%c\t%16-18f, %0-3f"},
+ {0x0eb0f110, 0x0ff8fff0, "cnf%c\t%16-18f, %0-3f"},
+ {0x0ed0f110, 0x0ff8fff0, "cmfe%c\t%16-18f, %0-3f"},
+ {0x0ef0f110, 0x0ff8fff0, "cnfe%c\t%16-18f, %0-3f"},
+ {0x0c000100, 0x0e100f00, "stf%c%Q\t%12-14f, %A"},
+ {0x0c100100, 0x0e100f00, "ldf%c%Q\t%12-14f, %A"},
+ {0x0c000200, 0x0e100f00, "sfm%c\t%12-14f, %F, %A"},
+ {0x0c100200, 0x0e100f00, "lfm%c\t%12-14f, %F, %A"},
+
+ /* Floating point coprocessor (VFP) instructions */
+ {0x0eb00bc0, 0x0fff0ff0, "fabsd%c\t%1z, %0z"},
+ {0x0eb00ac0, 0x0fbf0fd0, "fabss%c\t%1y, %0y"},
+ {0x0e300b00, 0x0ff00ff0, "faddd%c\t%1z, %2z, %0z"},
+ {0x0e300a00, 0x0fb00f50, "fadds%c\t%1y, %2y, %1y"},
+ {0x0eb40b40, 0x0fff0f70, "fcmp%7'ed%c\t%1z, %0z"},
+ {0x0eb40a40, 0x0fbf0f50, "fcmp%7'es%c\t%1y, %0y"},
+ {0x0eb50b40, 0x0fff0f70, "fcmp%7'ezd%c\t%1z"},
+ {0x0eb50a40, 0x0fbf0f70, "fcmp%7'ezs%c\t%1y"},
+ {0x0eb00b40, 0x0fff0ff0, "fcpyd%c\t%1z, %0z"},
+ {0x0eb00a40, 0x0fbf0fd0, "fcpys%c\t%1y, %0y"},
+ {0x0eb70ac0, 0x0fff0fd0, "fcvtds%c\t%1z, %0y"},
+ {0x0eb70bc0, 0x0fbf0ff0, "fcvtsd%c\t%1y, %0z"},
+ {0x0e800b00, 0x0ff00ff0, "fdivd%c\t%1z, %2z, %0z"},
+ {0x0e800a00, 0x0fb00f50, "fdivs%c\t%1y, %2y, %0y"},
+ {0x0d100b00, 0x0f700f00, "fldd%c\t%1z, %A"},
+ {0x0c900b00, 0x0fd00f00, "fldmia%0?xd%c\t%16-19r%21'!, %3z"},
+ {0x0d300b00, 0x0ff00f00, "fldmdb%0?xd%c\t%16-19r!, %3z"},
+ {0x0d100a00, 0x0f300f00, "flds%c\t%1y, %A"},
+ {0x0c900a00, 0x0f900f00, "fldmias%c\t%16-19r%21'!, %3y"},
+ {0x0d300a00, 0x0fb00f00, "fldmdbs%c\t%16-19r!, %3y"},
+ {0x0e000b00, 0x0ff00ff0, "fmacd%c\t%1z, %2z, %0z"},
+ {0x0e000a00, 0x0fb00f50, "fmacs%c\t%1y, %2y, %0y"},
+ {0x0e200b10, 0x0ff00fff, "fmdhr%c\t%2z, %12-15r"},
+ {0x0e000b10, 0x0ff00fff, "fmdlr%c\t%2z, %12-15r"},
+ {0x0c400b10, 0x0ff00ff0, "fmdrr%c\t%0z, %12-15r, %16-19r"},
+ {0x0e300b10, 0x0ff00fff, "fmrdh%c\t%12-15r, %2z"},
+ {0x0e100b10, 0x0ff00fff, "fmrdl%c\t%12-15r, %2z"},
+ {0x0c500b10, 0x0ff00ff0, "fmrrd%c\t%12-15r, %16-19r, %0z"},
+ {0x0c500a10, 0x0ff00fd0, "fmrrs%c\t%12-15r, %16-19r, %4y"},
+ {0x0e100a10, 0x0ff00f7f, "fmrs%c\t%12-15r, %2y"},
+ {0x0ef1fa10, 0x0fffffff, "fmstat%c"},
+ {0x0ef00a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpsid"},
+ {0x0ef10a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpscr"},
+ {0x0ef80a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpexc"},
+ {0x0ef90a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpinst\t@ Impl def"},
+ {0x0efa0a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpinst2\t@ Impl def"},
+ {0x0ef00a10, 0x0ff00fff, "fmrx%c\t%12-15r, <impl def 0x%16-19x>"},
+ {0x0e100b00, 0x0ff00ff0, "fmscd%c\t%1z, %2z, %0z"},
+ {0x0e100a00, 0x0fb00f50, "fmscs%c\t%1y, %2y, %0y"},
+ {0x0e000a10, 0x0ff00f7f, "fmsr%c\t%2y, %12-15r"},
+ {0x0c400a10, 0x0ff00fd0, "fmsrr%c\t%12-15r, %16-19r, %4y"},
+ {0x0e200b00, 0x0ff00ff0, "fmuld%c\t%1z, %2z, %0z"},
+ {0x0e200a00, 0x0fb00f50, "fmuls%c\t%1y, %2y, %0y"},
+ {0x0ee00a10, 0x0fff0fff, "fmxr%c\tfpsid, %12-15r"},
+ {0x0ee10a10, 0x0fff0fff, "fmxr%c\tfpscr, %12-15r"},
+ {0x0ee80a10, 0x0fff0fff, "fmxr%c\tfpexc, %12-15r"},
+ {0x0ee90a10, 0x0fff0fff, "fmxr%c\tfpinst, %12-15r\t@ Impl def"},
+ {0x0eea0a10, 0x0fff0fff, "fmxr%c\tfpinst2, %12-15r\t@ Impl def"},
+ {0x0ee00a10, 0x0ff00fff, "fmxr%c\t<impl def 0x%16-19x>, %12-15r"},
+ {0x0eb10b40, 0x0fff0ff0, "fnegd%c\t%1z, %0z"},
+ {0x0eb10a40, 0x0fbf0fd0, "fnegs%c\t%1y, %0y"},
+ {0x0e000b40, 0x0ff00ff0, "fnmacd%c\t%1z, %2z, %0z"},
+ {0x0e000a40, 0x0fb00f50, "fnmacs%c\t%1y, %2y, %0y"},
+ {0x0e100b40, 0x0ff00ff0, "fnmscd%c\t%1z, %2z, %0z"},
+ {0x0e100a40, 0x0fb00f50, "fnmscs%c\t%1y, %2y, %0y"},
+ {0x0e200b40, 0x0ff00ff0, "fnmuld%c\t%1z, %2z, %0z"},
+ {0x0e200a40, 0x0fb00f50, "fnmuls%c\t%1y, %2y, %0y"},
+ {0x0eb80bc0, 0x0fff0fd0, "fsitod%c\t%1z, %0y"},
+ {0x0eb80ac0, 0x0fbf0fd0, "fsitos%c\t%1y, %0y"},
+ {0x0eb10bc0, 0x0fff0ff0, "fsqrtd%c\t%1z, %0z"},
+ {0x0eb10ac0, 0x0fbf0fd0, "fsqrts%c\t%1y, %0y"},
+ {0x0d000b00, 0x0f700f00, "fstd%c\t%1z, %A"},
+ {0x0c800b00, 0x0fd00f00, "fstmia%0?xd%c\t%16-19r%21'!, %3z"},
+ {0x0d200b00, 0x0ff00f00, "fstmdb%0?xd%c\t%16-19r!, %3z"},
+ {0x0d000a00, 0x0f300f00, "fsts%c\t%1y, %A"},
+ {0x0c800a00, 0x0f900f00, "fstmias%c\t%16-19r%21'!, %3y"},
+ {0x0d200a00, 0x0fb00f00, "fstmdbs%c\t%16-19r!, %3y"},
+ {0x0e300b40, 0x0ff00ff0, "fsubd%c\t%1z, %2z, %0z"},
+ {0x0e300a40, 0x0fb00f50, "fsubs%c\t%1y, %2y, %0y"},
+ {0x0ebc0b40, 0x0fbe0f70, "fto%16?sui%7'zd%c\t%1y, %0z"},
+ {0x0ebc0a40, 0x0fbe0f50, "fto%16?sui%7'zs%c\t%1y, %0y"},
+ {0x0eb80b40, 0x0fff0fd0, "fuitod%c\t%1z, %0y"},
+ {0x0eb80a40, 0x0fbf0fd0, "fuitos%c\t%1y, %0y"},
+
+ /* Cirrus coprocessor instructions. */
+ {0x0d100400, 0x0f500f00, "cfldrs%c\tmvf%12-15d, %A"},
+ {0x0c100400, 0x0f500f00, "cfldrs%c\tmvf%12-15d, %A"},
+ {0x0d500400, 0x0f500f00, "cfldrd%c\tmvd%12-15d, %A"},
+ {0x0c500400, 0x0f500f00, "cfldrd%c\tmvd%12-15d, %A"},
+ {0x0d100500, 0x0f500f00, "cfldr32%c\tmvfx%12-15d, %A"},
+ {0x0c100500, 0x0f500f00, "cfldr32%c\tmvfx%12-15d, %A"},
+ {0x0d500500, 0x0f500f00, "cfldr64%c\tmvdx%12-15d, %A"},
+ {0x0c500500, 0x0f500f00, "cfldr64%c\tmvdx%12-15d, %A"},
+ {0x0d000400, 0x0f500f00, "cfstrs%c\tmvf%12-15d, %A"},
+ {0x0c000400, 0x0f500f00, "cfstrs%c\tmvf%12-15d, %A"},
+ {0x0d400400, 0x0f500f00, "cfstrd%c\tmvd%12-15d, %A"},
+ {0x0c400400, 0x0f500f00, "cfstrd%c\tmvd%12-15d, %A"},
+ {0x0d000500, 0x0f500f00, "cfstr32%c\tmvfx%12-15d, %A"},
+ {0x0c000500, 0x0f500f00, "cfstr32%c\tmvfx%12-15d, %A"},
+ {0x0d400500, 0x0f500f00, "cfstr64%c\tmvdx%12-15d, %A"},
+ {0x0c400500, 0x0f500f00, "cfstr64%c\tmvdx%12-15d, %A"},
+ {0x0e000450, 0x0ff00ff0, "cfmvsr%c\tmvf%16-19d, %12-15r"},
+ {0x0e100450, 0x0ff00ff0, "cfmvrs%c\t%12-15r, mvf%16-19d"},
+ {0x0e000410, 0x0ff00ff0, "cfmvdlr%c\tmvd%16-19d, %12-15r"},
+ {0x0e100410, 0x0ff00ff0, "cfmvrdl%c\t%12-15r, mvd%16-19d"},
+ {0x0e000430, 0x0ff00ff0, "cfmvdhr%c\tmvd%16-19d, %12-15r"},
+ {0x0e100430, 0x0ff00fff, "cfmvrdh%c\t%12-15r, mvd%16-19d"},
+ {0x0e000510, 0x0ff00fff, "cfmv64lr%c\tmvdx%16-19d, %12-15r"},
+ {0x0e100510, 0x0ff00fff, "cfmvr64l%c\t%12-15r, mvdx%16-19d"},
+ {0x0e000530, 0x0ff00fff, "cfmv64hr%c\tmvdx%16-19d, %12-15r"},
+ {0x0e100530, 0x0ff00fff, "cfmvr64h%c\t%12-15r, mvdx%16-19d"},
+ {0x0e100610, 0x0ff0fff0, "cfmval32%c\tmvax%0-3d, mvfx%16-19d"},
+ {0x0e000610, 0x0ff0fff0, "cfmv32al%c\tmvfx%0-3d, mvax%16-19d"},
+ {0x0e100630, 0x0ff0fff0, "cfmvam32%c\tmvax%0-3d, mvfx%16-19d"},
+ {0x0e000630, 0x0ff0fff0, "cfmv32am%c\tmvfx%0-3d, mvax%16-19d"},
+ {0x0e100650, 0x0ff0fff0, "cfmvah32%c\tmvax%0-3d, mvfx%16-19d"},
+ {0x0e000650, 0x0ff0fff0, "cfmv32ah%c\tmvfx%0-3d, mvax%16-19d"},
+ {0x0e000670, 0x0ff0fff0, "cfmv32a%c\tmvfx%0-3d, mvax%16-19d"},
+ {0x0e100670, 0x0ff0fff0, "cfmva32%c\tmvax%0-3d, mvfx%16-19d"},
+ {0x0e000690, 0x0ff0fff0, "cfmv64a%c\tmvdx%0-3d, mvax%16-19d"},
+ {0x0e100690, 0x0ff0fff0, "cfmva64%c\tmvax%0-3d, mvdx%16-19d"},
+ {0x0e1006b0, 0x0ff0fff0, "cfmvsc32%c\tdspsc, mvfx%16-19d"},
+ {0x0e0006b0, 0x0ff0fff0, "cfmv32sc%c\tmvfx%0-3d, dspsc"},
+ {0x0e000400, 0x0ff00fff, "cfcpys%c\tmvf%12-15d, mvf%16-19d"},
+ {0x0e000420, 0x0ff00fff, "cfcpyd%c\tmvd%12-15d, mvd%16-19d"},
+ {0x0e000460, 0x0ff00fff, "cfcvtsd%c\tmvd%12-15d, mvf%16-19d"},
+ {0x0e000440, 0x0ff00fff, "cfcvtds%c\tmvf%12-15d, mvd%16-19d"},
+ {0x0e000480, 0x0ff00fff, "cfcvt32s%c\tmvf%12-15d, mvfx%16-19d"},
+ {0x0e0004a0, 0x0ff00fff, "cfcvt32d%c\tmvd%12-15d, mvfx%16-19d"},
+ {0x0e0004c0, 0x0ff00fff, "cfcvt64s%c\tmvf%12-15d, mvdx%16-19d"},
+ {0x0e0004e0, 0x0ff00fff, "cfcvt64d%c\tmvd%12-15d, mvdx%16-19d"},
+ {0x0e100580, 0x0ff00fff, "cfcvts32%c\tmvfx%12-15d, mvf%16-19d"},
+ {0x0e1005a0, 0x0ff00fff, "cfcvtd32%c\tmvfx%12-15d, mvd%16-19d"},
+ {0x0e1005c0, 0x0ff00fff, "cftruncs32%c\tmvfx%12-15d, mvf%16-19d"},
+ {0x0e1005e0, 0x0ff00fff, "cftruncd32%c\tmvfx%12-15d, mvd%16-19d"},
+ {0x0e000550, 0x0ff00ff0, "cfrshl32%c\tmvfx%16-19d, mvfx%0-3d, %12-15r"},
+ {0x0e000570, 0x0ff00ff0, "cfrshl64%c\tmvdx%16-19d, mvdx%0-3d, %12-15r"},
+ {0x0e000500, 0x0ff00f00, "cfsh32%c\tmvfx%12-15d, mvfx%16-19d, #%I"},
+ {0x0e200500, 0x0ff00f00, "cfsh64%c\tmvdx%12-15d, mvdx%16-19d, #%I"},
+ {0x0e100490, 0x0ff00ff0, "cfcmps%c\t%12-15r, mvf%16-19d, mvf%0-3d"},
+ {0x0e1004b0, 0x0ff00ff0, "cfcmpd%c\t%12-15r, mvd%16-19d, mvd%0-3d"},
+ {0x0e100590, 0x0ff00ff0, "cfcmp32%c\t%12-15r, mvfx%16-19d, mvfx%0-3d"},
+ {0x0e1005b0, 0x0ff00ff0, "cfcmp64%c\t%12-15r, mvdx%16-19d, mvdx%0-3d"},
+ {0x0e300400, 0x0ff00fff, "cfabss%c\tmvf%12-15d, mvf%16-19d"},
+ {0x0e300420, 0x0ff00fff, "cfabsd%c\tmvd%12-15d, mvd%16-19d"},
+ {0x0e300440, 0x0ff00fff, "cfnegs%c\tmvf%12-15d, mvf%16-19d"},
+ {0x0e300460, 0x0ff00fff, "cfnegd%c\tmvd%12-15d, mvd%16-19d"},
+ {0x0e300480, 0x0ff00ff0, "cfadds%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"},
+ {0x0e3004a0, 0x0ff00ff0, "cfaddd%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"},
+ {0x0e3004c0, 0x0ff00ff0, "cfsubs%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"},
+ {0x0e3004e0, 0x0ff00ff0, "cfsubd%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"},
+ {0x0e100400, 0x0ff00ff0, "cfmuls%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"},
+ {0x0e100420, 0x0ff00ff0, "cfmuld%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"},
+ {0x0e300500, 0x0ff00fff, "cfabs32%c\tmvfx%12-15d, mvfx%16-19d"},
+ {0x0e300520, 0x0ff00fff, "cfabs64%c\tmvdx%12-15d, mvdx%16-19d"},
+ {0x0e300540, 0x0ff00fff, "cfneg32%c\tmvfx%12-15d, mvfx%16-19d"},
+ {0x0e300560, 0x0ff00fff, "cfneg64%c\tmvdx%12-15d, mvdx%16-19d"},
+ {0x0e300580, 0x0ff00ff0, "cfadd32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"},
+ {0x0e3005a0, 0x0ff00ff0, "cfadd64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"},
+ {0x0e3005c0, 0x0ff00ff0, "cfsub32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"},
+ {0x0e3005e0, 0x0ff00ff0, "cfsub64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"},
+ {0x0e100500, 0x0ff00ff0, "cfmul32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"},
+ {0x0e100520, 0x0ff00ff0, "cfmul64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"},
+ {0x0e100540, 0x0ff00ff0, "cfmac32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"},
+ {0x0e100560, 0x0ff00ff0, "cfmsc32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"},
+ {0x0e000600, 0x0ff00f00, "cfmadd32%c\tmvax%5-7d, mvfx%12-15d, mvfx%16-19d, mvfx%0-3d"},
+ {0x0e100600, 0x0ff00f00, "cfmsub32%c\tmvax%5-7d, mvfx%12-15d, mvfx%16-19d, mvfx%0-3d"},
+ {0x0e200600, 0x0ff00f00, "cfmadda32%c\tmvax%5-7d, mvax%12-15d, mvfx%16-19d, mvfx%0-3d"},
+ {0x0e300600, 0x0ff00f00, "cfmsuba32%c\tmvax%5-7d, mvax%12-15d, mvfx%16-19d, mvfx%0-3d"},
+
+ /* Generic coprocessor instructions */
+ {0x0e000000, 0x0f000010, "cdp%c\t%8-11d, %20-23d, cr%12-15d, cr%16-19d, cr%0-3d, {%5-7d}"},
+ {0x0e100010, 0x0f100010, "mrc%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"},
+ {0x0e000010, 0x0f100010, "mcr%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"},
+ {0x0c000000, 0x0e100000, "stc%c%22'l\t%8-11d, cr%12-15d, %A"},
+ {0x0c100000, 0x0e100000, "ldc%c%22'l\t%8-11d, cr%12-15d, %A"},
+
+ /* The rest. */
+ {0x00000000, 0x00000000, "undefined instruction %0-31x"},
+ {0x00000000, 0x00000000, 0}
+};
+
+#define BDISP(x) ((((x) & 0xffffff) ^ 0x800000) - 0x800000) /* 26 bit */
+
+static struct thumb_opcode thumb_opcodes[] =
+{
+ /* Thumb instructions. */
+
+ /* ARM V5 ISA extends Thumb. */
+ {0xbe00, 0xff00, "bkpt\t%0-7x"},
+ {0x4780, 0xff87, "blx\t%3-6r"}, /* note: 4 bit register number. */
+ /* Note: this is BLX(2). BLX(1) is done in arm-dis.c/print_insn_thumb()
+ as an extension of the special processing there for Thumb BL.
+ BL and BLX(1) involve 2 successive 16-bit instructions, which must
+ always appear together in the correct order. So, the empty
+ string is put in this table, and the string interpreter takes <empty>
+ to mean it has a pair of BL-ish instructions. */
+ {0x46C0, 0xFFFF, "nop\t\t\t(mov r8, r8)"},
+ /* Format 5 instructions do not update the PSR. */
+ {0x1C00, 0xFFC0, "mov\t%0-2r, %3-5r\t\t(add %0-2r, %3-5r, #%6-8d)"},
+ /* Format 4. */
+ {0x4000, 0xFFC0, "and\t%0-2r, %3-5r"},
+ {0x4040, 0xFFC0, "eor\t%0-2r, %3-5r"},
+ {0x4080, 0xFFC0, "lsl\t%0-2r, %3-5r"},
+ {0x40C0, 0xFFC0, "lsr\t%0-2r, %3-5r"},
+ {0x4100, 0xFFC0, "asr\t%0-2r, %3-5r"},
+ {0x4140, 0xFFC0, "adc\t%0-2r, %3-5r"},
+ {0x4180, 0xFFC0, "sbc\t%0-2r, %3-5r"},
+ {0x41C0, 0xFFC0, "ror\t%0-2r, %3-5r"},
+ {0x4200, 0xFFC0, "tst\t%0-2r, %3-5r"},
+ {0x4240, 0xFFC0, "neg\t%0-2r, %3-5r"},
+ {0x4280, 0xFFC0, "cmp\t%0-2r, %3-5r"},
+ {0x42C0, 0xFFC0, "cmn\t%0-2r, %3-5r"},
+ {0x4300, 0xFFC0, "orr\t%0-2r, %3-5r"},
+ {0x4340, 0xFFC0, "mul\t%0-2r, %3-5r"},
+ {0x4380, 0xFFC0, "bic\t%0-2r, %3-5r"},
+ {0x43C0, 0xFFC0, "mvn\t%0-2r, %3-5r"},
+ /* format 13 */
+ {0xB000, 0xFF80, "add\tsp, #%0-6W"},
+ {0xB080, 0xFF80, "sub\tsp, #%0-6W"},
+ /* format 5 */
+ {0x4700, 0xFF80, "bx\t%S"},
+ {0x4400, 0xFF00, "add\t%D, %S"},
+ {0x4500, 0xFF00, "cmp\t%D, %S"},
+ {0x4600, 0xFF00, "mov\t%D, %S"},
+ /* format 14 */
+ {0xB400, 0xFE00, "push\t%N"},
+ {0xBC00, 0xFE00, "pop\t%O"},
+ /* format 2 */
+ {0x1800, 0xFE00, "add\t%0-2r, %3-5r, %6-8r"},
+ {0x1A00, 0xFE00, "sub\t%0-2r, %3-5r, %6-8r"},
+ {0x1C00, 0xFE00, "add\t%0-2r, %3-5r, #%6-8d"},
+ {0x1E00, 0xFE00, "sub\t%0-2r, %3-5r, #%6-8d"},
+ /* format 8 */
+ {0x5200, 0xFE00, "strh\t%0-2r, [%3-5r, %6-8r]"},
+ {0x5A00, 0xFE00, "ldrh\t%0-2r, [%3-5r, %6-8r]"},
+ {0x5600, 0xF600, "ldrs%11?hb\t%0-2r, [%3-5r, %6-8r]"},
+ /* format 7 */
+ {0x5000, 0xFA00, "str%10'b\t%0-2r, [%3-5r, %6-8r]"},
+ {0x5800, 0xFA00, "ldr%10'b\t%0-2r, [%3-5r, %6-8r]"},
+ /* format 1 */
+ {0x0000, 0xF800, "lsl\t%0-2r, %3-5r, #%6-10d"},
+ {0x0800, 0xF800, "lsr\t%0-2r, %3-5r, #%6-10d"},
+ {0x1000, 0xF800, "asr\t%0-2r, %3-5r, #%6-10d"},
+ /* format 3 */
+ {0x2000, 0xF800, "mov\t%8-10r, #%0-7d"},
+ {0x2800, 0xF800, "cmp\t%8-10r, #%0-7d"},
+ {0x3000, 0xF800, "add\t%8-10r, #%0-7d"},
+ {0x3800, 0xF800, "sub\t%8-10r, #%0-7d"},
+ /* format 6 */
+ {0x4800, 0xF800, "ldr\t%8-10r, [pc, #%0-7W]\t(%0-7a)"}, /* TODO: Disassemble PC relative "LDR rD,=<symbolic>" */
+ /* format 9 */
+ {0x6000, 0xF800, "str\t%0-2r, [%3-5r, #%6-10W]"},
+ {0x6800, 0xF800, "ldr\t%0-2r, [%3-5r, #%6-10W]"},
+ {0x7000, 0xF800, "strb\t%0-2r, [%3-5r, #%6-10d]"},
+ {0x7800, 0xF800, "ldrb\t%0-2r, [%3-5r, #%6-10d]"},
+ /* format 10 */
+ {0x8000, 0xF800, "strh\t%0-2r, [%3-5r, #%6-10H]"},
+ {0x8800, 0xF800, "ldrh\t%0-2r, [%3-5r, #%6-10H]"},
+ /* format 11 */
+ {0x9000, 0xF800, "str\t%8-10r, [sp, #%0-7W]"},
+ {0x9800, 0xF800, "ldr\t%8-10r, [sp, #%0-7W]"},
+ /* format 12 */
+ {0xA000, 0xF800, "add\t%8-10r, pc, #%0-7W\t(adr %8-10r,%0-7a)"},
+ {0xA800, 0xF800, "add\t%8-10r, sp, #%0-7W"},
+ /* format 15 */
+ {0xC000, 0xF800, "stmia\t%8-10r!,%M"},
+ {0xC800, 0xF800, "ldmia\t%8-10r!,%M"},
+ /* format 18 */
+ {0xE000, 0xF800, "b\t%0-10B"},
+ {0xE800, 0xF800, "undefined"},
+ /* format 19 */
+ {0xF000, 0xF800, ""}, /* special processing required in disassembler */
+ {0xF800, 0xF800, "second half of BL instruction %0-15x"},
+ /* format 16 */
+ {0xD000, 0xFF00, "beq\t%0-7B"},
+ {0xD100, 0xFF00, "bne\t%0-7B"},
+ {0xD200, 0xFF00, "bcs\t%0-7B"},
+ {0xD300, 0xFF00, "bcc\t%0-7B"},
+ {0xD400, 0xFF00, "bmi\t%0-7B"},
+ {0xD500, 0xFF00, "bpl\t%0-7B"},
+ {0xD600, 0xFF00, "bvs\t%0-7B"},
+ {0xD700, 0xFF00, "bvc\t%0-7B"},
+ {0xD800, 0xFF00, "bhi\t%0-7B"},
+ {0xD900, 0xFF00, "bls\t%0-7B"},
+ {0xDA00, 0xFF00, "bge\t%0-7B"},
+ {0xDB00, 0xFF00, "blt\t%0-7B"},
+ {0xDC00, 0xFF00, "bgt\t%0-7B"},
+ {0xDD00, 0xFF00, "ble\t%0-7B"},
+ /* format 17 */
+ {0xDE00, 0xFF00, "bal\t%0-7B"},
+ {0xDF00, 0xFF00, "swi\t%0-7d"},
+ /* format 9 */
+ {0x6000, 0xF800, "str\t%0-2r, [%3-5r, #%6-10W]"},
+ {0x6800, 0xF800, "ldr\t%0-2r, [%3-5r, #%6-10W]"},
+ {0x7000, 0xF800, "strb\t%0-2r, [%3-5r, #%6-10d]"},
+ {0x7800, 0xF800, "ldrb\t%0-2r, [%3-5r, #%6-10d]"},
+ /* the rest */
+ {0x0000, 0x0000, "undefined instruction %0-15x"},
+ {0x0000, 0x0000, 0}
+};
+
+#define BDISP23(x) ((((((x) & 0x07ff) << 11) | (((x) & 0x07ff0000) >> 16)) \
+ ^ 0x200000) - 0x200000) /* 23bit */
+
+#ifndef streq
+#define streq(a,b) (strcmp ((a), (b)) == 0)
+#endif
+
+#ifndef strneq
+#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0)
+#endif
+
+#ifndef NUM_ELEM
+#define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0])
+#endif
+
+static char * arm_conditional[] =
+{"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
+ "hi", "ls", "ge", "lt", "gt", "le", "", "nv"};
+
+typedef struct
+{
+ const char * name;
+ const char * description;
+ const char * reg_names[16];
+}
+arm_regname;
+
+static arm_regname regnames[] =
+{
+ { "raw" , "Select raw register names",
+ { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}},
+ { "gcc", "Select register names used by GCC",
+ { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc" }},
+ { "std", "Select register names used in ARM's ISA documentation",
+ { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc" }},
+ { "apcs", "Select register names used in the APCS",
+ { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "sl", "fp", "ip", "sp", "lr", "pc" }},
+ { "atpcs", "Select register names used in the ATPCS",
+ { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "IP", "SP", "LR", "PC" }},
+ { "special-atpcs", "Select special register names used in the ATPCS",
+ { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }}
+};
+
+/* Default to STD register name set. */
+static unsigned int regname_selected = 2;
+
+#define NUM_ARM_REGNAMES NUM_ELEM (regnames)
+#define arm_regnames regnames[regname_selected].reg_names
+
+static boolean force_thumb = false;
+
+static char * arm_fp_const[] =
+{"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0"};
+
+static char * arm_shift[] =
+{"lsl", "lsr", "asr", "ror"};
+
+/* Forward declarations. */
+static void arm_decode_shift PARAMS ((long, fprintf_ftype, void *));
+static int print_insn_arm1 PARAMS ((bfd_vma, struct disassemble_info *, long));
+static int print_insn_thumb PARAMS ((bfd_vma, struct disassemble_info *, long));
+static void parse_disassembler_options PARAMS ((char *));
+int get_arm_regname_num_options (void);
+int set_arm_regname_option (int option);
+int get_arm_regnames (int option, const char **setname,
+ const char **setdescription,
+ const char ***register_names);
+
+/* Functions. */
+int
+get_arm_regname_num_options ()
+{
+ return NUM_ARM_REGNAMES;
+}
+
+int
+set_arm_regname_option (option)
+ int option;
+{
+ int old = regname_selected;
+ regname_selected = option;
+ return old;
+}
+
+int
+get_arm_regnames (option, setname, setdescription, register_names)
+ int option;
+ const char **setname;
+ const char **setdescription;
+ const char ***register_names;
+{
+ *setname = regnames[option].name;
+ *setdescription = regnames[option].description;
+ *register_names = regnames[option].reg_names;
+ return 16;
+}
+
+static void
+arm_decode_shift (given, func, stream)
+ long given;
+ fprintf_ftype func;
+ void * stream;
+{
+ func (stream, "%s", arm_regnames[given & 0xf]);
+
+ if ((given & 0xff0) != 0)
+ {
+ if ((given & 0x10) == 0)
+ {
+ int amount = (given & 0xf80) >> 7;
+ int shift = (given & 0x60) >> 5;
+
+ if (amount == 0)
+ {
+ if (shift == 3)
+ {
+ func (stream, ", rrx");
+ return;
+ }
+
+ amount = 32;
+ }
+
+ func (stream, ", %s #%d", arm_shift[shift], amount);
+ }
+ else
+ func (stream, ", %s %s", arm_shift[(given & 0x60) >> 5],
+ arm_regnames[(given & 0xf00) >> 8]);
+ }
+}
+
+/* Print one instruction from PC on INFO->STREAM.
+ Return the size of the instruction (always 4 on ARM). */
+
+static int
+print_insn_arm1 (pc, info, given)
+ bfd_vma pc;
+ struct disassemble_info * info;
+ long given;
+{
+ struct arm_opcode * insn;
+ void * stream = info->stream;
+ fprintf_ftype func = info->fprintf_func;
+
+ for (insn = arm_opcodes; insn->assembler; insn++)
+ {
+ if ((given & insn->mask) == insn->value)
+ {
+ char * c;
+
+ for (c = insn->assembler; *c; c++)
+ {
+ if (*c == '%')
+ {
+ switch (*++c)
+ {
+ case '%':
+ func (stream, "%%");
+ break;
+
+ case 'a':
+ if (((given & 0x000f0000) == 0x000f0000)
+ && ((given & 0x02000000) == 0))
+ {
+ int offset = given & 0xfff;
+
+ func (stream, "[pc");
+
+ if (given & 0x01000000)
+ {
+ if ((given & 0x00800000) == 0)
+ offset = - offset;
+
+ /* Pre-indexed. */
+ func (stream, ", #%d]", offset);
+
+ offset += pc + 8;
+
+ /* Cope with the possibility of write-back
+ being used. Probably a very dangerous thing
+ for the programmer to do, but who are we to
+ argue ? */
+ if (given & 0x00200000)
+ func (stream, "!");
+ }
+ else
+ {
+ /* Post indexed. */
+ func (stream, "], #%d", offset);
+
+ /* ie ignore the offset. */
+ offset = pc + 8;
+ }
+
+ func (stream, "\t; ");
+ info->print_address_func (offset, info);
+ }
+ else
+ {
+ func (stream, "[%s",
+ arm_regnames[(given >> 16) & 0xf]);
+ if ((given & 0x01000000) != 0)
+ {
+ if ((given & 0x02000000) == 0)
+ {
+ int offset = given & 0xfff;
+ if (offset)
+ func (stream, ", %s#%d",
+ (((given & 0x00800000) == 0)
+ ? "-" : ""), offset);
+ }
+ else
+ {
+ func (stream, ", %s",
+ (((given & 0x00800000) == 0)
+ ? "-" : ""));
+ arm_decode_shift (given, func, stream);
+ }
+
+ func (stream, "]%s",
+ ((given & 0x00200000) != 0) ? "!" : "");
+ }
+ else
+ {
+ if ((given & 0x02000000) == 0)
+ {
+ int offset = given & 0xfff;
+ if (offset)
+ func (stream, "], %s#%d",
+ (((given & 0x00800000) == 0)
+ ? "-" : ""), offset);
+ else
+ func (stream, "]");
+ }
+ else
+ {
+ func (stream, "], %s",
+ (((given & 0x00800000) == 0)
+ ? "-" : ""));
+ arm_decode_shift (given, func, stream);
+ }
+ }
+ }
+ break;
+
+ case 's':
+ if ((given & 0x004f0000) == 0x004f0000)
+ {
+ /* PC relative with immediate offset. */
+ int offset = ((given & 0xf00) >> 4) | (given & 0xf);
+
+ if ((given & 0x00800000) == 0)
+ offset = -offset;
+
+ func (stream, "[pc, #%d]\t; ", offset);
+
+ (*info->print_address_func)
+ (offset + pc + 8, info);
+ }
+ else
+ {
+ func (stream, "[%s",
+ arm_regnames[(given >> 16) & 0xf]);
+ if ((given & 0x01000000) != 0)
+ {
+ /* Pre-indexed. */
+ if ((given & 0x00400000) == 0x00400000)
+ {
+ /* Immediate. */
+ int offset = ((given & 0xf00) >> 4) | (given & 0xf);
+ if (offset)
+ func (stream, ", %s#%d",
+ (((given & 0x00800000) == 0)
+ ? "-" : ""), offset);
+ }
+ else
+ {
+ /* Register. */
+ func (stream, ", %s%s",
+ (((given & 0x00800000) == 0)
+ ? "-" : ""),
+ arm_regnames[given & 0xf]);
+ }
+
+ func (stream, "]%s",
+ ((given & 0x00200000) != 0) ? "!" : "");
+ }
+ else
+ {
+ /* Post-indexed. */
+ if ((given & 0x00400000) == 0x00400000)
+ {
+ /* Immediate. */
+ int offset = ((given & 0xf00) >> 4) | (given & 0xf);
+ if (offset)
+ func (stream, "], %s#%d",
+ (((given & 0x00800000) == 0)
+ ? "-" : ""), offset);
+ else
+ func (stream, "]");
+ }
+ else
+ {
+ /* Register. */
+ func (stream, "], %s%s",
+ (((given & 0x00800000) == 0)
+ ? "-" : ""),
+ arm_regnames[given & 0xf]);
+ }
+ }
+ }
+ break;
+
+ case 'b':
+ (*info->print_address_func)
+ (BDISP (given) * 4 + pc + 8, info);
+ break;
+
+ case 'c':
+ func (stream, "%s",
+ arm_conditional [(given >> 28) & 0xf]);
+ break;
+
+ case 'm':
+ {
+ int started = 0;
+ int reg;
+
+ func (stream, "{");
+ for (reg = 0; reg < 16; reg++)
+ if ((given & (1 << reg)) != 0)
+ {
+ if (started)
+ func (stream, ", ");
+ started = 1;
+ func (stream, "%s", arm_regnames[reg]);
+ }
+ func (stream, "}");
+ }
+ break;
+
+ case 'o':
+ if ((given & 0x02000000) != 0)
+ {
+ int rotate = (given & 0xf00) >> 7;
+ int immed = (given & 0xff);
+ immed = (((immed << (32 - rotate))
+ | (immed >> rotate)) & 0xffffffff);
+ func (stream, "#%d\t; 0x%x", immed, immed);
+ }
+ else
+ arm_decode_shift (given, func, stream);
+ break;
+
+ case 'p':
+ if ((given & 0x0000f000) == 0x0000f000)
+ func (stream, "p");
+ break;
+
+ case 't':
+ if ((given & 0x01200000) == 0x00200000)
+ func (stream, "t");
+ break;
+
+ case 'A':
+ func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]);
+ if ((given & 0x01000000) != 0)
+ {
+ int offset = given & 0xff;
+ if (offset)
+ func (stream, ", %s#%d]%s",
+ ((given & 0x00800000) == 0 ? "-" : ""),
+ offset * 4,
+ ((given & 0x00200000) != 0 ? "!" : ""));
+ else
+ func (stream, "]");
+ }
+ else
+ {
+ int offset = given & 0xff;
+ if (offset)
+ func (stream, "], %s#%d",
+ ((given & 0x00800000) == 0 ? "-" : ""),
+ offset * 4);
+ else
+ func (stream, "]");
+ }
+ break;
+
+ case 'B':
+ /* Print ARM V5 BLX(1) address: pc+25 bits. */
+ {
+ bfd_vma address;
+ bfd_vma offset = 0;
+
+ if (given & 0x00800000)
+ /* Is signed, hi bits should be ones. */
+ offset = (-1) ^ 0x00ffffff;
+
+ /* Offset is (SignExtend(offset field)<<2). */
+ offset += given & 0x00ffffff;
+ offset <<= 2;
+ address = offset + pc + 8;
+
+ if (given & 0x01000000)
+ /* H bit allows addressing to 2-byte boundaries. */
+ address += 2;
+
+ info->print_address_func (address, info);
+ }
+ break;
+
+ case 'I':
+ /* Print a Cirrus/DSP shift immediate. */
+ /* Immediates are 7bit signed ints with bits 0..3 in
+ bits 0..3 of opcode and bits 4..6 in bits 5..7
+ of opcode. */
+ {
+ int imm;
+
+ imm = (given & 0xf) | ((given & 0xe0) >> 1);
+
+ /* Is ``imm'' a negative number? */
+ if (imm & 0x40)
+ imm |= (-1 << 7);
+
+ func (stream, "%d", imm);
+ }
+
+ break;
+
+ case 'C':
+ func (stream, "_");
+ if (given & 0x80000)
+ func (stream, "f");
+ if (given & 0x40000)
+ func (stream, "s");
+ if (given & 0x20000)
+ func (stream, "x");
+ if (given & 0x10000)
+ func (stream, "c");
+ break;
+
+ case 'F':
+ switch (given & 0x00408000)
+ {
+ case 0:
+ func (stream, "4");
+ break;
+ case 0x8000:
+ func (stream, "1");
+ break;
+ case 0x00400000:
+ func (stream, "2");
+ break;
+ default:
+ func (stream, "3");
+ }
+ break;
+
+ case 'P':
+ switch (given & 0x00080080)
+ {
+ case 0:
+ func (stream, "s");
+ break;
+ case 0x80:
+ func (stream, "d");
+ break;
+ case 0x00080000:
+ func (stream, "e");
+ break;
+ default:
+ func (stream, _("<illegal precision>"));
+ break;
+ }
+ break;
+ case 'Q':
+ switch (given & 0x00408000)
+ {
+ case 0:
+ func (stream, "s");
+ break;
+ case 0x8000:
+ func (stream, "d");
+ break;
+ case 0x00400000:
+ func (stream, "e");
+ break;
+ default:
+ func (stream, "p");
+ break;
+ }
+ break;
+ case 'R':
+ switch (given & 0x60)
+ {
+ case 0:
+ break;
+ case 0x20:
+ func (stream, "p");
+ break;
+ case 0x40:
+ func (stream, "m");
+ break;
+ default:
+ func (stream, "z");
+ break;
+ }
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ {
+ int bitstart = *c++ - '0';
+ int bitend = 0;
+ while (*c >= '0' && *c <= '9')
+ bitstart = (bitstart * 10) + *c++ - '0';
+
+ switch (*c)
+ {
+ case '-':
+ c++;
+
+ while (*c >= '0' && *c <= '9')
+ bitend = (bitend * 10) + *c++ - '0';
+
+ if (!bitend)
+ abort ();
+
+ switch (*c)
+ {
+ case 'r':
+ {
+ long reg;
+
+ reg = given >> bitstart;
+ reg &= (2 << (bitend - bitstart)) - 1;
+
+ func (stream, "%s", arm_regnames[reg]);
+ }
+ break;
+ case 'd':
+ {
+ long reg;
+
+ reg = given >> bitstart;
+ reg &= (2 << (bitend - bitstart)) - 1;
+
+ func (stream, "%d", reg);
+ }
+ break;
+ case 'x':
+ {
+ long reg;
+
+ reg = given >> bitstart;
+ reg &= (2 << (bitend - bitstart)) - 1;
+
+ func (stream, "0x%08x", reg);
+
+ /* Some SWI instructions have special
+ meanings. */
+ if ((given & 0x0fffffff) == 0x0FF00000)
+ func (stream, "\t; IMB");
+ else if ((given & 0x0fffffff) == 0x0FF00001)
+ func (stream, "\t; IMBRange");
+ }
+ break;
+ case 'X':
+ {
+ long reg;
+
+ reg = given >> bitstart;
+ reg &= (2 << (bitend - bitstart)) - 1;
+
+ func (stream, "%01x", reg & 0xf);
+ }
+ break;
+ case 'f':
+ {
+ long reg;
+
+ reg = given >> bitstart;
+ reg &= (2 << (bitend - bitstart)) - 1;
+
+ if (reg > 7)
+ func (stream, "#%s",
+ arm_fp_const[reg & 7]);
+ else
+ func (stream, "f%d", reg);
+ }
+ break;
+ default:
+ abort ();
+ }
+ break;
+
+ case 'y':
+ case 'z':
+ {
+ int single = *c == 'y';
+ int regno;
+
+ switch (bitstart)
+ {
+ case 4: /* Sm pair */
+ func (stream, "{");
+ /* Fall through. */
+ case 0: /* Sm, Dm */
+ regno = given & 0x0000000f;
+ if (single)
+ {
+ regno <<= 1;
+ regno += (given >> 5) & 1;
+ }
+ break;
+
+ case 1: /* Sd, Dd */
+ regno = (given >> 12) & 0x0000000f;
+ if (single)
+ {
+ regno <<= 1;
+ regno += (given >> 22) & 1;
+ }
+ break;
+
+ case 2: /* Sn, Dn */
+ regno = (given >> 16) & 0x0000000f;
+ if (single)
+ {
+ regno <<= 1;
+ regno += (given >> 7) & 1;
+ }
+ break;
+
+ case 3: /* List */
+ func (stream, "{");
+ regno = (given >> 12) & 0x0000000f;
+ if (single)
+ {
+ regno <<= 1;
+ regno += (given >> 22) & 1;
+ }
+ break;
+
+
+ default:
+ abort ();
+ }
+
+ func (stream, "%c%d", single ? 's' : 'd', regno);
+
+ if (bitstart == 3)
+ {
+ int count = given & 0xff;
+
+ if (single == 0)
+ count >>= 1;
+
+ if (--count)
+ {
+ func (stream, "-%c%d",
+ single ? 's' : 'd',
+ regno + count);
+ }
+
+ func (stream, "}");
+ }
+ else if (bitstart == 4)
+ func (stream, ", %c%d}", single ? 's' : 'd',
+ regno + 1);
+
+ break;
+ }
+
+ case '`':
+ c++;
+ if ((given & (1 << bitstart)) == 0)
+ func (stream, "%c", *c);
+ break;
+ case '\'':
+ c++;
+ if ((given & (1 << bitstart)) != 0)
+ func (stream, "%c", *c);
+ break;
+ case '?':
+ ++c;
+ if ((given & (1 << bitstart)) != 0)
+ func (stream, "%c", *c++);
+ else
+ func (stream, "%c", *++c);
+ break;
+ default:
+ abort ();
+ }
+ break;
+
+ default:
+ abort ();
+ }
+ }
+ }
+ else
+ func (stream, "%c", *c);
+ }
+ return 4;
+ }
+ }
+ abort ();
+}
+
+/* Print one instruction from PC on INFO->STREAM.
+ Return the size of the instruction. */
+
+static int
+print_insn_thumb (pc, info, given)
+ bfd_vma pc;
+ struct disassemble_info * info;
+ long given;
+{
+ struct thumb_opcode * insn;
+ void * stream = info->stream;
+ fprintf_ftype func = info->fprintf_func;
+
+ for (insn = thumb_opcodes; insn->assembler; insn++)
+ {
+ if ((given & insn->mask) == insn->value)
+ {
+ char * c = insn->assembler;
+
+ /* Special processing for Thumb 2 instruction BL sequence: */
+ if (!*c) /* Check for empty (not NULL) assembler string. */
+ {
+ long offset;
+
+ info->bytes_per_chunk = 4;
+ info->bytes_per_line = 4;
+
+ offset = BDISP23 (given);
+ offset = offset * 2 + pc + 4;
+
+ if ((given & 0x10000000) == 0)
+ {
+ func (stream, "blx\t");
+ offset &= 0xfffffffc;
+ }
+ else
+ func (stream, "bl\t");
+
+ info->print_address_func (offset, info);
+ return 4;
+ }
+ else
+ {
+ info->bytes_per_chunk = 2;
+ info->bytes_per_line = 4;
+
+ given &= 0xffff;
+
+ for (; *c; c++)
+ {
+ if (*c == '%')
+ {
+ int domaskpc = 0;
+ int domasklr = 0;
+
+ switch (*++c)
+ {
+ case '%':
+ func (stream, "%%");
+ break;
+
+ case 'S':
+ {
+ long reg;
+
+ reg = (given >> 3) & 0x7;
+ if (given & (1 << 6))
+ reg += 8;
+
+ func (stream, "%s", arm_regnames[reg]);
+ }
+ break;
+
+ case 'D':
+ {
+ long reg;
+
+ reg = given & 0x7;
+ if (given & (1 << 7))
+ reg += 8;
+
+ func (stream, "%s", arm_regnames[reg]);
+ }
+ break;
+
+ case 'T':
+ func (stream, "%s",
+ arm_conditional [(given >> 8) & 0xf]);
+ break;
+
+ case 'N':
+ if (given & (1 << 8))
+ domasklr = 1;
+ /* Fall through. */
+ case 'O':
+ if (*c == 'O' && (given & (1 << 8)))
+ domaskpc = 1;
+ /* Fall through. */
+ case 'M':
+ {
+ int started = 0;
+ int reg;
+
+ func (stream, "{");
+
+ /* It would be nice if we could spot
+ ranges, and generate the rS-rE format: */
+ for (reg = 0; (reg < 8); reg++)
+ if ((given & (1 << reg)) != 0)
+ {
+ if (started)
+ func (stream, ", ");
+ started = 1;
+ func (stream, "%s", arm_regnames[reg]);
+ }
+
+ if (domasklr)
+ {
+ if (started)
+ func (stream, ", ");
+ started = 1;
+ func (stream, arm_regnames[14] /* "lr" */);
+ }
+
+ if (domaskpc)
+ {
+ if (started)
+ func (stream, ", ");
+ func (stream, arm_regnames[15] /* "pc" */);
+ }
+
+ func (stream, "}");
+ }
+ break;
+
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ {
+ int bitstart = *c++ - '0';
+ int bitend = 0;
+
+ while (*c >= '0' && *c <= '9')
+ bitstart = (bitstart * 10) + *c++ - '0';
+
+ switch (*c)
+ {
+ case '-':
+ {
+ long reg;
+
+ c++;
+ while (*c >= '0' && *c <= '9')
+ bitend = (bitend * 10) + *c++ - '0';
+ if (!bitend)
+ abort ();
+ reg = given >> bitstart;
+ reg &= (2 << (bitend - bitstart)) - 1;
+ switch (*c)
+ {
+ case 'r':
+ func (stream, "%s", arm_regnames[reg]);
+ break;
+
+ case 'd':
+ func (stream, "%d", reg);
+ break;
+
+ case 'H':
+ func (stream, "%d", reg << 1);
+ break;
+
+ case 'W':
+ func (stream, "%d", reg << 2);
+ break;
+
+ case 'a':
+ /* PC-relative address -- the bottom two
+ bits of the address are dropped
+ before the calculation. */
+ info->print_address_func
+ (((pc + 4) & ~3) + (reg << 2), info);
+ break;
+
+ case 'x':
+ func (stream, "0x%04x", reg);
+ break;
+
+ case 'I':
+ reg = ((reg ^ (1 << bitend)) - (1 << bitend));
+ func (stream, "%d", reg);
+ break;
+
+ case 'B':
+ reg = ((reg ^ (1 << bitend)) - (1 << bitend));
+ (*info->print_address_func)
+ (reg * 2 + pc + 4, info);
+ break;
+
+ default:
+ abort ();
+ }
+ }
+ break;
+
+ case '\'':
+ c++;
+ if ((given & (1 << bitstart)) != 0)
+ func (stream, "%c", *c);
+ break;
+
+ case '?':
+ ++c;
+ if ((given & (1 << bitstart)) != 0)
+ func (stream, "%c", *c++);
+ else
+ func (stream, "%c", *++c);
+ break;
+
+ default:
+ abort ();
+ }
+ }
+ break;
+
+ default:
+ abort ();
+ }
+ }
+ else
+ func (stream, "%c", *c);
+ }
+ }
+ return 2;
+ }
+ }
+
+ /* No match. */
+ abort ();
+}
+
+/* Parse an individual disassembler option. */
+
+void
+parse_arm_disassembler_option (option)
+ char * option;
+{
+ if (option == NULL)
+ return;
+
+ if (strneq (option, "reg-names-", 10))
+ {
+ int i;
+
+ option += 10;
+
+ for (i = NUM_ARM_REGNAMES; i--;)
+ if (streq (option, regnames[i].name))
+ {
+ regname_selected = i;
+ break;
+ }
+
+ if (i < 0)
+ fprintf (stderr, _("Unrecognised register name set: %s\n"), option);
+ }
+ else if (streq (option, "force-thumb"))
+ force_thumb = 1;
+ else if (streq (option, "no-force-thumb"))
+ force_thumb = 0;
+ else
+ fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option);
+
+ return;
+}
+
+/* Parse the string of disassembler options, spliting it at whitespaces. */
+
+static void
+parse_disassembler_options (options)
+ char * options;
+{
+ char * space;
+
+ if (options == NULL)
+ return;
+
+ do
+ {
+ space = strchr (options, ' ');
+
+ if (space)
+ {
+ * space = '\0';
+ parse_arm_disassembler_option (options);
+ * space = ' ';
+ options = space + 1;
+ }
+ else
+ parse_arm_disassembler_option (options);
+ }
+ while (space);
+}
+
+/* NOTE: There are no checks in these routines that
+ the relevant number of data bytes exist. */
+
+int
+print_insn_arm (pc, info)
+ bfd_vma pc;
+ struct disassemble_info * info;
+{
+ unsigned char b[4];
+ long given;
+ int status;
+ int is_thumb;
+ int little;
+
+ if (info->disassembler_options)
+ {
+ parse_disassembler_options (info->disassembler_options);
+
+ /* To avoid repeated parsing of these options, we remove them here. */
+ info->disassembler_options = NULL;
+ }
+
+ is_thumb = force_thumb;
+ if (pc & 1)
+ {
+ is_thumb = 1;
+ pc &= ~(bfd_vma) 1;
+ }
+
+#if 0
+ if (!is_thumb && info->symbols != NULL)
+ {
+ if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour)
+ {
+ coff_symbol_type * cs;
+
+ cs = coffsymbol (*info->symbols);
+ is_thumb = ( cs->native->u.syment.n_sclass == C_THUMBEXT
+ || cs->native->u.syment.n_sclass == C_THUMBSTAT
+ || cs->native->u.syment.n_sclass == C_THUMBLABEL
+ || cs->native->u.syment.n_sclass == C_THUMBEXTFUNC
+ || cs->native->u.syment.n_sclass == C_THUMBSTATFUNC);
+ }
+ else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour)
+ {
+ elf_symbol_type * es;
+ unsigned int type;
+
+ es = *(elf_symbol_type **)(info->symbols);
+ type = ELF_ST_TYPE (es->internal_elf_sym.st_info);
+
+ is_thumb = (type == STT_ARM_TFUNC) || (type == STT_ARM_16BIT);
+ }
+ }
+#endif
+
+ little = (info->endian == BFD_ENDIAN_LITTLE);
+ info->bytes_per_chunk = 4;
+ info->display_endian = little ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG;
+
+ if (little)
+ {
+ status = info->read_memory_func (pc, (bfd_byte *) &b[0], 4, info);
+ if (status != 0 && is_thumb)
+ {
+ info->bytes_per_chunk = 2;
+
+ status = info->read_memory_func (pc, (bfd_byte *) b, 2, info);
+ b[3] = b[2] = 0;
+ }
+
+ if (status != 0)
+ {
+ info->memory_error_func (status, pc, info);
+ return -1;
+ }
+
+ given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
+ }
+ else
+ {
+ status = info->read_memory_func
+ (pc & ~ 0x3, (bfd_byte *) &b[0], 4, info);
+ if (status != 0)
+ {
+ info->memory_error_func (status, pc, info);
+ return -1;
+ }
+
+ if (is_thumb)
+ {
+ if (pc & 0x2)
+ {
+ given = (b[2] << 8) | b[3];
+
+ status = info->read_memory_func
+ ((pc + 4) & ~ 0x3, (bfd_byte *) b, 4, info);
+ if (status != 0)
+ {
+ info->memory_error_func (status, pc + 4, info);
+ return -1;
+ }
+
+ given |= (b[0] << 24) | (b[1] << 16);
+ }
+ else
+ given = (b[0] << 8) | b[1] | (b[2] << 24) | (b[3] << 16);
+ }
+ else
+ given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]);
+ }
+
+ if (info->flags & INSN_HAS_RELOC)
+ /* If the instruction has a reloc associated with it, then
+ the offset field in the instruction will actually be the
+ addend for the reloc. (We are using REL type relocs).
+ In such cases, we can ignore the pc when computing
+ addresses, since the addend is not currently pc-relative. */
+ pc = 0;
+ if (is_thumb)
+ status = print_insn_thumb (pc, info, given);
+ else
+ status = print_insn_arm1 (pc, info, given);
+
+ return status;
+}
+
+void
+print_arm_disassembler_options (FILE * stream)
+{
+ int i;
+
+ fprintf (stream, _("\n\
+The following ARM specific disassembler options are supported for use with\n\
+the -M switch:\n"));
+
+ for (i = NUM_ARM_REGNAMES; i--;)
+ fprintf (stream, " reg-names-%s %*c%s\n",
+ regnames[i].name,
+ (int)(14 - strlen (regnames[i].name)), ' ',
+ regnames[i].description);
+
+ fprintf (stream, " force-thumb Assume all insns are Thumb insns\n");
+ fprintf (stream, " no-force-thumb Examine preceeding label to determine an insn's type\n\n");
+}
Added: trunk/src/host/qemu-neo1973/arm.ld
===================================================================
--- trunk/src/host/qemu-neo1973/arm.ld 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/arm.ld 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,153 @@
+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) }
+ .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
+ __exidx_start = .;
+ .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) }
+ __exidx_end = .;
+ .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
+ }
+ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+ .data1 : { *(.data1) }
+ .preinit_array :
+ {
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ }
+ .init_array :
+ {
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ }
+ .fini_array :
+ {
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ }
+ .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 . */
+}
Added: trunk/src/host/qemu-neo1973/block-bochs.c
===================================================================
--- trunk/src/host/qemu-neo1973/block-bochs.c 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/block-bochs.c 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,254 @@
+/*
+ * 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 0x00020000
+#define HEADER_V1 0x00010000
+#define HEADER_SIZE 512
+
+#define REDOLOG_TYPE "Redolog"
+#define GROWING_TYPE "Growing"
+
+// not allocated: 0xffffffff
+
+// always little-endian
+struct bochs_header_v1 {
+ 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;
+};
+
+// 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
+ uint32_t reserved; // for ???
+ uint64_t disk; // disk size
+ char padding[HEADER_SIZE - 64 - 8 - 24];
+ } 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) ||
+ (le32_to_cpu(bochs->version) == HEADER_V1)))
+ return 100;
+
+ return 0;
+}
+
+static int bochs_open(BlockDriverState *bs, const char *filename, int flags)
+{
+ BDRVBochsState *s = bs->opaque;
+ int fd, i;
+ struct bochs_header bochs;
+ struct bochs_header_v1 header_v1;
+
+ fd = open(filename, O_RDWR | O_BINARY);
+ if (fd < 0) {
+ fd = open(filename, O_RDONLY | O_BINARY);
+ 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) &&
+ (le32_to_cpu(bochs.version) != HEADER_V1))) {
+ goto fail;
+ }
+
+ if (le32_to_cpu(bochs.version) == HEADER_V1) {
+ memcpy(&header_v1, &bochs, sizeof(bochs));
+ bs->total_sectors = le64_to_cpu(header_v1.extra.redolog.disk) / 512;
+ } else {
+ 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,
+};
Added: trunk/src/host/qemu-neo1973/block-cloop.c
===================================================================
--- trunk/src/host/qemu-neo1973/block-cloop.c 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/block-cloop.c 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,169 @@
+/*
+ * 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;
+ uint8_t *compressed_block;
+ uint8_t *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, int flags)
+{
+ BDRVCloopState *s = bs->opaque;
+ uint32_t offsets_size,max_compressed_block_size=1,i;
+
+ s->fd = open(filename, O_RDONLY | O_BINARY);
+ if (s->fd < 0)
+ return -errno;
+ 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 = malloc(max_compressed_block_size+1)))
+ goto cloop_close;
+ if(!(s->uncompressed_block = 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,
+};
+
+
Added: trunk/src/host/qemu-neo1973/block-cow.c
===================================================================
--- trunk/src/host/qemu-neo1973/block-cow.c 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/block-cow.c 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,267 @@
+/*
+ * 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, int flags)
+{
+ 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);
+
+ /* 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 {
+ if (bs->backing_hd) {
+ /* read from the base image */
+ ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
+ if (ret < 0)
+ 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,
+ 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) {
+ /* Note: if no file, we put a dummy mtime */
+ cow_header.mtime = cpu_to_be32(0);
+
+ fd = open(image_filename, O_RDONLY | O_BINARY);
+ if (fd < 0) {
+ close(cow_fd);
+ goto mtime_fail;
+ }
+ if (fstat(fd, &st) != 0) {
+ close(fd);
+ goto mtime_fail;
+ }
+ close(fd);
+ cow_header.mtime = cpu_to_be32(st.st_mtime);
+ mtime_fail:
+ pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file),
+ image_filename);
+ }
+ 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;
+}
+
+static void cow_flush(BlockDriverState *bs)
+{
+ BDRVCowState *s = bs->opaque;
+ fsync(s->fd);
+}
+
+BlockDriver bdrv_cow = {
+ "cow",
+ sizeof(BDRVCowState),
+ cow_probe,
+ cow_open,
+ cow_read,
+ cow_write,
+ cow_close,
+ cow_create,
+ cow_flush,
+ cow_is_allocated,
+};
+#endif
Added: trunk/src/host/qemu-neo1973/block-dmg.c
===================================================================
--- trunk/src/host/qemu-neo1973/block-dmg.c 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/block-dmg.c 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,297 @@
+/*
+ * 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;
+ uint8_t *compressed_chunk;
+ uint8_t *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, int flags)
+{
+ 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);
+ if (s->fd < 0)
+ return -errno;
+ 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, flags);
+ }
+ 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 = malloc(max_compressed_size+1)))
+ goto dmg_close;
+ if(!(s->uncompressed_chunk = 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,
+};
+
Added: trunk/src/host/qemu-neo1973/block-qcow.c
===================================================================
--- trunk/src/host/qemu-neo1973/block-qcow.c 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/block-qcow.c 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,905 @@
+/*
+ * Block driver for the QCOW format
+ *
+ * Copyright (c) 2004-2006 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 {
+ BlockDriverState *hd;
+ 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, int flags)
+{
+ BDRVQcowState *s = bs->opaque;
+ int len, i, shift, ret;
+ QCowHeader header;
+
+ ret = bdrv_file_open(&s->hd, filename, flags);
+ if (ret < 0)
+ return ret;
+ if (bdrv_pread(s->hd, 0, &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;
+ if (bdrv_pread(s->hd, s->l1_table_offset, 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;
+ if (bdrv_pread(s->hd, header.backing_file_offset, 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);
+ bdrv_delete(s->hd);
+ 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 = bdrv_getlength(s->hd);
+ /* 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);
+ if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp),
+ &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);
+ if (new_l2_table) {
+ memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
+ if (bdrv_pwrite(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
+ s->l2_size * sizeof(uint64_t))
+ return 0;
+ } else {
+ if (bdrv_pread(s->hd, l2_offset, 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 = bdrv_getlength(s->hd);
+ cluster_offset = (cluster_offset + s->cluster_size - 1) &
+ ~(s->cluster_size - 1);
+ /* write the cluster content */
+ if (bdrv_pwrite(s->hd, cluster_offset, s->cluster_cache, s->cluster_size) !=
+ s->cluster_size)
+ return -1;
+ } else {
+ cluster_offset = bdrv_getlength(s->hd);
+ if (allocate == 1) {
+ /* round to cluster size */
+ cluster_offset = (cluster_offset + s->cluster_size - 1) &
+ ~(s->cluster_size - 1);
+ bdrv_truncate(s->hd, 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, 0x00, 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);
+ if (bdrv_pwrite(s->hd, cluster_offset + i * 512,
+ 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;
+ if (bdrv_pwrite(s->hd,
+ l2_offset + l2_index * sizeof(tmp), &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);
+ ret = bdrv_pread(s->hd, coffset, 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;
+}
+
+#if 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) {
+ if (bs->backing_hd) {
+ /* read from the base image */
+ ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
+ if (ret < 0)
+ return -1;
+ } else {
+ 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 {
+ ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, 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;
+}
+#endif
+
+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;
+ if (s->crypt_method) {
+ encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
+ &s->aes_encrypt_key);
+ ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512,
+ s->cluster_data, n * 512);
+ } else {
+ ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, 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;
+}
+
+typedef struct QCowAIOCB {
+ BlockDriverAIOCB common;
+ int64_t sector_num;
+ uint8_t *buf;
+ int nb_sectors;
+ int n;
+ uint64_t cluster_offset;
+ uint8_t *cluster_data;
+ BlockDriverAIOCB *hd_aiocb;
+} QCowAIOCB;
+
+static void qcow_aio_read_cb(void *opaque, int ret)
+{
+ QCowAIOCB *acb = opaque;
+ BlockDriverState *bs = acb->common.bs;
+ BDRVQcowState *s = bs->opaque;
+ int index_in_cluster;
+
+ acb->hd_aiocb = NULL;
+ if (ret < 0) {
+ fail:
+ acb->common.cb(acb->common.opaque, ret);
+ qemu_aio_release(acb);
+ return;
+ }
+
+ redo:
+ /* post process the read buffer */
+ if (!acb->cluster_offset) {
+ /* nothing to do */
+ } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
+ /* nothing to do */
+ } else {
+ if (s->crypt_method) {
+ encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf,
+ acb->n, 0,
+ &s->aes_decrypt_key);
+ }
+ }
+
+ acb->nb_sectors -= acb->n;
+ acb->sector_num += acb->n;
+ acb->buf += acb->n * 512;
+
+ if (acb->nb_sectors == 0) {
+ /* request completed */
+ acb->common.cb(acb->common.opaque, 0);
+ qemu_aio_release(acb);
+ return;
+ }
+
+ /* prepare next AIO request */
+ acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9,
+ 0, 0, 0, 0);
+ index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
+ acb->n = s->cluster_sectors - index_in_cluster;
+ if (acb->n > acb->nb_sectors)
+ acb->n = acb->nb_sectors;
+
+ if (!acb->cluster_offset) {
+ if (bs->backing_hd) {
+ /* read from the base image */
+ acb->hd_aiocb = bdrv_aio_read(bs->backing_hd,
+ acb->sector_num, acb->buf, acb->n, qcow_aio_read_cb, acb);
+ if (acb->hd_aiocb == NULL)
+ goto fail;
+ } else {
+ /* Note: in this case, no need to wait */
+ memset(acb->buf, 0, 512 * acb->n);
+ goto redo;
+ }
+ } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
+ /* add AIO support for compressed blocks ? */
+ if (decompress_cluster(s, acb->cluster_offset) < 0)
+ goto fail;
+ memcpy(acb->buf,
+ s->cluster_cache + index_in_cluster * 512, 512 * acb->n);
+ goto redo;
+ } else {
+ if ((acb->cluster_offset & 511) != 0) {
+ ret = -EIO;
+ goto fail;
+ }
+ acb->hd_aiocb = bdrv_aio_read(s->hd,
+ (acb->cluster_offset >> 9) + index_in_cluster,
+ acb->buf, acb->n, qcow_aio_read_cb, acb);
+ if (acb->hd_aiocb == NULL)
+ goto fail;
+ }
+}
+
+static BlockDriverAIOCB *qcow_aio_read(BlockDriverState *bs,
+ int64_t sector_num, uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ QCowAIOCB *acb;
+
+ acb = qemu_aio_get(bs, cb, opaque);
+ if (!acb)
+ return NULL;
+ acb->hd_aiocb = NULL;
+ acb->sector_num = sector_num;
+ acb->buf = buf;
+ acb->nb_sectors = nb_sectors;
+ acb->n = 0;
+ acb->cluster_offset = 0;
+
+ qcow_aio_read_cb(acb, 0);
+ return &acb->common;
+}
+
+static void qcow_aio_write_cb(void *opaque, int ret)
+{
+ QCowAIOCB *acb = opaque;
+ BlockDriverState *bs = acb->common.bs;
+ BDRVQcowState *s = bs->opaque;
+ int index_in_cluster;
+ uint64_t cluster_offset;
+ const uint8_t *src_buf;
+
+ acb->hd_aiocb = NULL;
+
+ if (ret < 0) {
+ fail:
+ acb->common.cb(acb->common.opaque, ret);
+ qemu_aio_release(acb);
+ return;
+ }
+
+ acb->nb_sectors -= acb->n;
+ acb->sector_num += acb->n;
+ acb->buf += acb->n * 512;
+
+ if (acb->nb_sectors == 0) {
+ /* request completed */
+ acb->common.cb(acb->common.opaque, 0);
+ qemu_aio_release(acb);
+ return;
+ }
+
+ index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
+ acb->n = s->cluster_sectors - index_in_cluster;
+ if (acb->n > acb->nb_sectors)
+ acb->n = acb->nb_sectors;
+ cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 1, 0,
+ index_in_cluster,
+ index_in_cluster + acb->n);
+ if (!cluster_offset || (cluster_offset & 511) != 0) {
+ ret = -EIO;
+ goto fail;
+ }
+ if (s->crypt_method) {
+ if (!acb->cluster_data) {
+ acb->cluster_data = qemu_mallocz(s->cluster_size);
+ if (!acb->cluster_data) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+ }
+ encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf,
+ acb->n, 1, &s->aes_encrypt_key);
+ src_buf = acb->cluster_data;
+ } else {
+ src_buf = acb->buf;
+ }
+ acb->hd_aiocb = bdrv_aio_write(s->hd,
+ (cluster_offset >> 9) + index_in_cluster,
+ src_buf, acb->n,
+ qcow_aio_write_cb, acb);
+ if (acb->hd_aiocb == NULL)
+ goto fail;
+}
+
+static BlockDriverAIOCB *qcow_aio_write(BlockDriverState *bs,
+ int64_t sector_num, const uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ BDRVQcowState *s = bs->opaque;
+ QCowAIOCB *acb;
+
+ s->cluster_cache_offset = -1; /* disable compressed cache */
+
+ acb = qemu_aio_get(bs, cb, opaque);
+ if (!acb)
+ return NULL;
+ acb->hd_aiocb = NULL;
+ acb->sector_num = sector_num;
+ acb->buf = (uint8_t *)buf;
+ acb->nb_sectors = nb_sectors;
+ acb->n = 0;
+
+ qcow_aio_write_cb(acb, 0);
+ return &acb->common;
+}
+
+static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+ QCowAIOCB *acb = (QCowAIOCB *)blockacb;
+ if (acb->hd_aiocb)
+ bdrv_aio_cancel(acb->hd_aiocb);
+ qemu_aio_release(acb);
+}
+
+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);
+ bdrv_delete(s->hd);
+}
+
+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;
+ uint64_t tmp;
+
+ fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 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) {
+ header.backing_file_offset = cpu_to_be64(header_size);
+ backing_filename_len = strlen(backing_file);
+ header.backing_file_size = cpu_to_be32(backing_filename_len);
+ header_size += backing_filename_len;
+ header.mtime = cpu_to_be32(0);
+ 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_file, 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;
+}
+
+static int qcow_make_empty(BlockDriverState *bs)
+{
+ BDRVQcowState *s = bs->opaque;
+ uint32_t l1_length = s->l1_size * sizeof(uint64_t);
+ int ret;
+
+ memset(s->l1_table, 0, l1_length);
+ if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_length) < 0)
+ return -1;
+ ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length);
+ if (ret < 0)
+ return ret;
+
+ memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
+ memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t));
+ memset(s->l2_cache_counts, 0, L2_CACHE_SIZE * sizeof(uint32_t));
+
+ return 0;
+}
+
+/* XXX: put compressed sectors first, then all the cluster aligned
+ tables to avoid losing bytes in alignment */
+static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
+ const uint8_t *buf, int nb_sectors)
+{
+ BDRVQcowState *s = bs->opaque;
+ z_stream strm;
+ int ret, out_len;
+ uint8_t *out_buf;
+ uint64_t cluster_offset;
+
+ if (nb_sectors != s->cluster_sectors)
+ return -EINVAL;
+
+ 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;
+ if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) {
+ qemu_free(out_buf);
+ return -1;
+ }
+ }
+
+ qemu_free(out_buf);
+ return 0;
+}
+
+static void qcow_flush(BlockDriverState *bs)
+{
+ BDRVQcowState *s = bs->opaque;
+ bdrv_flush(s->hd);
+}
+
+static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
+{
+ BDRVQcowState *s = bs->opaque;
+ bdi->cluster_size = s->cluster_size;
+ return 0;
+}
+
+BlockDriver bdrv_qcow = {
+ "qcow",
+ sizeof(BDRVQcowState),
+ qcow_probe,
+ qcow_open,
+ NULL,
+ NULL,
+ qcow_close,
+ qcow_create,
+ qcow_flush,
+ qcow_is_allocated,
+ qcow_set_key,
+ qcow_make_empty,
+
+ .bdrv_aio_read = qcow_aio_read,
+ .bdrv_aio_write = qcow_aio_write,
+ .bdrv_aio_cancel = qcow_aio_cancel,
+ .aiocb_size = sizeof(QCowAIOCB),
+ .bdrv_write_compressed = qcow_write_compressed,
+ .bdrv_get_info = qcow_get_info,
+};
Added: trunk/src/host/qemu-neo1973/block-qcow2.c
===================================================================
--- trunk/src/host/qemu-neo1973/block-qcow2.c 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/block-qcow2.c 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,2246 @@
+/*
+ * Block driver for the QCOW version 2 format
+ *
+ * Copyright (c) 2004-2006 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"
+#include <assert.h>
+
+/*
+ Differences with QCOW:
+
+ - Support for multiple incremental snapshots.
+ - Memory management by reference counts.
+ - Clusters which have a reference count of one have the bit
+ QCOW_OFLAG_COPIED to optimize write performance.
+ - Size of compressed clusters is stored in sectors to reduce bit usage
+ in the cluster offsets.
+ - Support for storing additional data (such as the VM state) in the
+ snapshots.
+ - If a backing store is used, the cluster size is not constrained
+ (could be backported to QCOW).
+ - L2 tables have always a size of one cluster.
+*/
+
+//#define DEBUG_ALLOC
+//#define DEBUG_ALLOC2
+
+#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
+#define QCOW_VERSION 2
+
+#define QCOW_CRYPT_NONE 0
+#define QCOW_CRYPT_AES 1
+
+/* indicate that the refcount of the referenced cluster is exactly one. */
+#define QCOW_OFLAG_COPIED (1LL << 63)
+/* indicate that the cluster is compressed (they never have the copied flag) */
+#define QCOW_OFLAG_COMPRESSED (1LL << 62)
+
+#define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */
+
+#ifndef offsetof
+#define offsetof(type, field) ((size_t) &((type *)0)->field)
+#endif
+
+typedef struct QCowHeader {
+ uint32_t magic;
+ uint32_t version;
+ uint64_t backing_file_offset;
+ uint32_t backing_file_size;
+ uint32_t cluster_bits;
+ uint64_t size; /* in bytes */
+ uint32_t crypt_method;
+ uint32_t l1_size; /* XXX: save number of clusters instead ? */
+ uint64_t l1_table_offset;
+ uint64_t refcount_table_offset;
+ uint32_t refcount_table_clusters;
+ uint32_t nb_snapshots;
+ uint64_t snapshots_offset;
+} QCowHeader;
+
+typedef struct __attribute__((packed)) QCowSnapshotHeader {
+ /* header is 8 byte aligned */
+ uint64_t l1_table_offset;
+
+ uint32_t l1_size;
+ uint16_t id_str_size;
+ uint16_t name_size;
+
+ uint32_t date_sec;
+ uint32_t date_nsec;
+
+ uint64_t vm_clock_nsec;
+
+ uint32_t vm_state_size;
+ uint32_t extra_data_size; /* for extension */
+ /* extra data follows */
+ /* id_str follows */
+ /* name follows */
+} QCowSnapshotHeader;
+
+#define L2_CACHE_SIZE 16
+
+typedef struct QCowSnapshot {
+ uint64_t l1_table_offset;
+ uint32_t l1_size;
+ char *id_str;
+ char *name;
+ uint32_t vm_state_size;
+ uint32_t date_sec;
+ uint32_t date_nsec;
+ uint64_t vm_clock_nsec;
+} QCowSnapshot;
+
+typedef struct BDRVQcowState {
+ BlockDriverState *hd;
+ int cluster_bits;
+ int cluster_size;
+ int cluster_sectors;
+ int l2_bits;
+ int l2_size;
+ int l1_size;
+ int l1_vm_state_index;
+ int csize_shift;
+ int csize_mask;
+ 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;
+
+ uint64_t *refcount_table;
+ uint64_t refcount_table_offset;
+ uint32_t refcount_table_size;
+ uint64_t refcount_block_cache_offset;
+ uint16_t *refcount_block_cache;
+ int64_t free_cluster_index;
+ int64_t free_byte_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;
+ uint64_t snapshots_offset;
+ int snapshots_size;
+ int nb_snapshots;
+ QCowSnapshot *snapshots;
+} BDRVQcowState;
+
+static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset);
+static int qcow_read(BlockDriverState *bs, int64_t sector_num,
+ uint8_t *buf, int nb_sectors);
+static int qcow_read_snapshots(BlockDriverState *bs);
+static void qcow_free_snapshots(BlockDriverState *bs);
+static int refcount_init(BlockDriverState *bs);
+static void refcount_close(BlockDriverState *bs);
+static int get_refcount(BlockDriverState *bs, int64_t cluster_index);
+static int update_cluster_refcount(BlockDriverState *bs,
+ int64_t cluster_index,
+ int addend);
+static void update_refcount(BlockDriverState *bs,
+ int64_t offset, int64_t length,
+ int addend);
+static int64_t alloc_clusters(BlockDriverState *bs, int64_t size);
+static int64_t alloc_bytes(BlockDriverState *bs, int size);
+static void free_clusters(BlockDriverState *bs,
+ int64_t offset, int64_t size);
+#ifdef DEBUG_ALLOC
+static void check_refcounts(BlockDriverState *bs);
+#endif
+
+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, int flags)
+{
+ BDRVQcowState *s = bs->opaque;
+ int len, i, shift, ret;
+ QCowHeader header;
+
+ ret = bdrv_file_open(&s->hd, filename, flags);
+ if (ret < 0)
+ return ret;
+ if (bdrv_pread(s->hd, 0, &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);
+ be64_to_cpus(&header.size);
+ be32_to_cpus(&header.cluster_bits);
+ be32_to_cpus(&header.crypt_method);
+ be64_to_cpus(&header.l1_table_offset);
+ be32_to_cpus(&header.l1_size);
+ be64_to_cpus(&header.refcount_table_offset);
+ be32_to_cpus(&header.refcount_table_clusters);
+ be64_to_cpus(&header.snapshots_offset);
+ be32_to_cpus(&header.nb_snapshots);
+
+ if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION)
+ goto fail;
+ if (header.size <= 1 ||
+ header.cluster_bits < 9 ||
+ header.cluster_bits > 16)
+ 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 = s->cluster_bits - 3; /* L2 is always one cluster */
+ s->l2_size = 1 << s->l2_bits;
+ bs->total_sectors = header.size / 512;
+ s->csize_shift = (62 - (s->cluster_bits - 8));
+ s->csize_mask = (1 << (s->cluster_bits - 8)) - 1;
+ s->cluster_offset_mask = (1LL << s->csize_shift) - 1;
+ s->refcount_table_offset = header.refcount_table_offset;
+ s->refcount_table_size =
+ header.refcount_table_clusters << (s->cluster_bits - 3);
+
+ s->snapshots_offset = header.snapshots_offset;
+ s->nb_snapshots = header.nb_snapshots;
+
+ /* read the level 1 table */
+ s->l1_size = header.l1_size;
+ shift = s->cluster_bits + s->l2_bits;
+ s->l1_vm_state_index = (header.size + (1LL << shift) - 1) >> shift;
+ /* the L1 table must contain at least enough entries to put
+ header.size bytes */
+ if (s->l1_size < s->l1_vm_state_index)
+ goto fail;
+ 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;
+ if (bdrv_pread(s->hd, s->l1_table_offset, 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;
+ /* one more sector for decompressed data alignment */
+ s->cluster_data = qemu_malloc(s->cluster_size + 512);
+ if (!s->cluster_data)
+ goto fail;
+ s->cluster_cache_offset = -1;
+
+ if (refcount_init(bs) < 0)
+ goto fail;
+
+ /* read the backing file name */
+ if (header.backing_file_offset != 0) {
+ len = header.backing_file_size;
+ if (len > 1023)
+ len = 1023;
+ if (bdrv_pread(s->hd, header.backing_file_offset, bs->backing_file, len) != len)
+ goto fail;
+ bs->backing_file[len] = '\0';
+ }
+ if (qcow_read_snapshots(bs) < 0)
+ goto fail;
+
+#ifdef DEBUG_ALLOC
+ check_refcounts(bs);
+#endif
+ return 0;
+
+ fail:
+ qcow_free_snapshots(bs);
+ refcount_close(bs);
+ qemu_free(s->l1_table);
+ qemu_free(s->l2_cache);
+ qemu_free(s->cluster_cache);
+ qemu_free(s->cluster_data);
+ bdrv_delete(s->hd);
+ 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;
+ }
+}
+
+static int copy_sectors(BlockDriverState *bs, uint64_t start_sect,
+ uint64_t cluster_offset, int n_start, int n_end)
+{
+ BDRVQcowState *s = bs->opaque;
+ int n, ret;
+
+ n = n_end - n_start;
+ if (n <= 0)
+ return 0;
+ ret = qcow_read(bs, start_sect + n_start, s->cluster_data, n);
+ if (ret < 0)
+ return ret;
+ if (s->crypt_method) {
+ encrypt_sectors(s, start_sect + n_start,
+ s->cluster_data,
+ s->cluster_data, n, 1,
+ &s->aes_encrypt_key);
+ }
+ ret = bdrv_write(s->hd, (cluster_offset >> 9) + n_start,
+ s->cluster_data, n);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static void l2_cache_reset(BlockDriverState *bs)
+{
+ BDRVQcowState *s = bs->opaque;
+
+ memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
+ memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t));
+ memset(s->l2_cache_counts, 0, L2_CACHE_SIZE * sizeof(uint32_t));
+}
+
+static inline int l2_cache_new_entry(BlockDriverState *bs)
+{
+ BDRVQcowState *s = bs->opaque;
+ uint32_t min_count;
+ int min_index, i;
+
+ /* find 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;
+ }
+ }
+ return min_index;
+}
+
+static int64_t align_offset(int64_t offset, int n)
+{
+ offset = (offset + n - 1) & ~(n - 1);
+ return offset;
+}
+
+static int grow_l1_table(BlockDriverState *bs, int min_size)
+{
+ BDRVQcowState *s = bs->opaque;
+ int new_l1_size, new_l1_size2, ret, i;
+ uint64_t *new_l1_table;
+ uint64_t new_l1_table_offset;
+ uint64_t data64;
+ uint32_t data32;
+
+ new_l1_size = s->l1_size;
+ if (min_size <= new_l1_size)
+ return 0;
+ while (min_size > new_l1_size) {
+ new_l1_size = (new_l1_size * 3 + 1) / 2;
+ }
+#ifdef DEBUG_ALLOC2
+ printf("grow l1_table from %d to %d\n", s->l1_size, new_l1_size);
+#endif
+
+ new_l1_size2 = sizeof(uint64_t) * new_l1_size;
+ new_l1_table = qemu_mallocz(new_l1_size2);
+ if (!new_l1_table)
+ return -ENOMEM;
+ memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
+
+ /* write new table (align to cluster) */
+ new_l1_table_offset = alloc_clusters(bs, new_l1_size2);
+
+ for(i = 0; i < s->l1_size; i++)
+ new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
+ ret = bdrv_pwrite(s->hd, new_l1_table_offset, new_l1_table, new_l1_size2);
+ if (ret != new_l1_size2)
+ goto fail;
+ for(i = 0; i < s->l1_size; i++)
+ new_l1_table[i] = be64_to_cpu(new_l1_table[i]);
+
+ /* set new table */
+ data64 = cpu_to_be64(new_l1_table_offset);
+ if (bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_table_offset),
+ &data64, sizeof(data64)) != sizeof(data64))
+ goto fail;
+ data32 = cpu_to_be32(new_l1_size);
+ if (bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_size),
+ &data32, sizeof(data32)) != sizeof(data32))
+ goto fail;
+ qemu_free(s->l1_table);
+ free_clusters(bs, s->l1_table_offset, s->l1_size * sizeof(uint64_t));
+ s->l1_table_offset = new_l1_table_offset;
+ s->l1_table = new_l1_table;
+ s->l1_size = new_l1_size;
+ return 0;
+ fail:
+ qemu_free(s->l1_table);
+ return -EIO;
+}
+
+/* 'allocate' is:
+ *
+ * 0 not to 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, ret;
+ uint64_t l2_offset, *l2_table, cluster_offset, tmp, old_l2_offset;
+
+ l1_index = offset >> (s->l2_bits + s->cluster_bits);
+ if (l1_index >= s->l1_size) {
+ /* outside l1 table is allowed: we grow the table if needed */
+ if (!allocate)
+ return 0;
+ if (grow_l1_table(bs, l1_index + 1) < 0)
+ return 0;
+ }
+ l2_offset = s->l1_table[l1_index];
+ if (!l2_offset) {
+ if (!allocate)
+ return 0;
+ l2_allocate:
+ old_l2_offset = l2_offset;
+ /* allocate a new l2 entry */
+ l2_offset = alloc_clusters(bs, s->l2_size * sizeof(uint64_t));
+ /* update the L1 entry */
+ s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED;
+ tmp = cpu_to_be64(l2_offset | QCOW_OFLAG_COPIED);
+ if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp),
+ &tmp, sizeof(tmp)) != sizeof(tmp))
+ return 0;
+ min_index = l2_cache_new_entry(bs);
+ l2_table = s->l2_cache + (min_index << s->l2_bits);
+
+ if (old_l2_offset == 0) {
+ memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
+ } else {
+ if (bdrv_pread(s->hd, old_l2_offset,
+ l2_table, s->l2_size * sizeof(uint64_t)) !=
+ s->l2_size * sizeof(uint64_t))
+ return 0;
+ }
+ if (bdrv_pwrite(s->hd, l2_offset,
+ l2_table, s->l2_size * sizeof(uint64_t)) !=
+ s->l2_size * sizeof(uint64_t))
+ return 0;
+ } else {
+ if (!(l2_offset & QCOW_OFLAG_COPIED)) {
+ if (allocate) {
+ free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
+ goto l2_allocate;
+ }
+ } else {
+ l2_offset &= ~QCOW_OFLAG_COPIED;
+ }
+ 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 = l2_cache_new_entry(bs);
+ l2_table = s->l2_cache + (min_index << s->l2_bits);
+ if (bdrv_pread(s->hd, l2_offset, 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) {
+ if (!allocate)
+ return cluster_offset;
+ } else if (!(cluster_offset & QCOW_OFLAG_COPIED)) {
+ if (!allocate)
+ return cluster_offset;
+ /* free the cluster */
+ if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
+ int nb_csectors;
+ nb_csectors = ((cluster_offset >> s->csize_shift) &
+ s->csize_mask) + 1;
+ free_clusters(bs, (cluster_offset & s->cluster_offset_mask) & ~511,
+ nb_csectors * 512);
+ } else {
+ free_clusters(bs, cluster_offset, s->cluster_size);
+ }
+ } else {
+ cluster_offset &= ~QCOW_OFLAG_COPIED;
+ return cluster_offset;
+ }
+ if (allocate == 1) {
+ /* allocate a new cluster */
+ cluster_offset = alloc_clusters(bs, s->cluster_size);
+
+ /* we must initialize the cluster content which won't be
+ written */
+ if ((n_end - n_start) < s->cluster_sectors) {
+ uint64_t start_sect;
+
+ start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
+ ret = copy_sectors(bs, start_sect,
+ cluster_offset, 0, n_start);
+ if (ret < 0)
+ return 0;
+ ret = copy_sectors(bs, start_sect,
+ cluster_offset, n_end, s->cluster_sectors);
+ if (ret < 0)
+ return 0;
+ }
+ tmp = cpu_to_be64(cluster_offset | QCOW_OFLAG_COPIED);
+ } else {
+ int nb_csectors;
+ cluster_offset = alloc_bytes(bs, compressed_size);
+ nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) -
+ (cluster_offset >> 9);
+ cluster_offset |= QCOW_OFLAG_COMPRESSED |
+ ((uint64_t)nb_csectors << s->csize_shift);
+ /* compressed clusters never have the copied flag */
+ tmp = cpu_to_be64(cluster_offset);
+ }
+ /* update L2 table */
+ l2_table[l2_index] = tmp;
+ if (bdrv_pwrite(s->hd,
+ l2_offset + l2_index * sizeof(tmp), &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, nb_csectors, sector_offset;
+ uint64_t coffset;
+
+ coffset = cluster_offset & s->cluster_offset_mask;
+ if (s->cluster_cache_offset != coffset) {
+ nb_csectors = ((cluster_offset >> s->csize_shift) & s->csize_mask) + 1;
+ sector_offset = coffset & 511;
+ csize = nb_csectors * 512 - sector_offset;
+ ret = bdrv_read(s->hd, coffset >> 9, s->cluster_data, nb_csectors);
+ if (ret < 0) {
+ return -1;
+ }
+ if (decompress_buffer(s->cluster_cache, s->cluster_size,
+ s->cluster_data + sector_offset, csize) < 0) {
+ return -1;
+ }
+ s->cluster_cache_offset = coffset;
+ }
+ return 0;
+}
+
+/* handle reading after the end of the backing file */
+static int backing_read1(BlockDriverState *bs,
+ int64_t sector_num, uint8_t *buf, int nb_sectors)
+{
+ int n1;
+ if ((sector_num + nb_sectors) <= bs->total_sectors)
+ return nb_sectors;
+ if (sector_num >= bs->total_sectors)
+ n1 = 0;
+ else
+ n1 = bs->total_sectors - sector_num;
+ memset(buf + n1 * 512, 0, 512 * (nb_sectors - n1));
+ return n1;
+}
+
+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, n1;
+ 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) {
+ if (bs->backing_hd) {
+ /* read from the base image */
+ n1 = backing_read1(bs->backing_hd, sector_num, buf, n);
+ if (n1 > 0) {
+ ret = bdrv_read(bs->backing_hd, sector_num, buf, n1);
+ if (ret < 0)
+ return -1;
+ }
+ } else {
+ 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 {
+ ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, 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;
+ if (s->crypt_method) {
+ encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
+ &s->aes_encrypt_key);
+ ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512,
+ s->cluster_data, n * 512);
+ } else {
+ ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, 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;
+}
+
+typedef struct QCowAIOCB {
+ BlockDriverAIOCB common;
+ int64_t sector_num;
+ uint8_t *buf;
+ int nb_sectors;
+ int n;
+ uint64_t cluster_offset;
+ uint8_t *cluster_data;
+ BlockDriverAIOCB *hd_aiocb;
+} QCowAIOCB;
+
+static void qcow_aio_read_cb(void *opaque, int ret)
+{
+ QCowAIOCB *acb = opaque;
+ BlockDriverState *bs = acb->common.bs;
+ BDRVQcowState *s = bs->opaque;
+ int index_in_cluster, n1;
+
+ acb->hd_aiocb = NULL;
+ if (ret < 0) {
+ fail:
+ acb->common.cb(acb->common.opaque, ret);
+ qemu_aio_release(acb);
+ return;
+ }
+
+ redo:
+ /* post process the read buffer */
+ if (!acb->cluster_offset) {
+ /* nothing to do */
+ } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
+ /* nothing to do */
+ } else {
+ if (s->crypt_method) {
+ encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf,
+ acb->n, 0,
+ &s->aes_decrypt_key);
+ }
+ }
+
+ acb->nb_sectors -= acb->n;
+ acb->sector_num += acb->n;
+ acb->buf += acb->n * 512;
+
+ if (acb->nb_sectors == 0) {
+ /* request completed */
+ acb->common.cb(acb->common.opaque, 0);
+ qemu_aio_release(acb);
+ return;
+ }
+
+ /* prepare next AIO request */
+ acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9,
+ 0, 0, 0, 0);
+ index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
+ acb->n = s->cluster_sectors - index_in_cluster;
+ if (acb->n > acb->nb_sectors)
+ acb->n = acb->nb_sectors;
+
+ if (!acb->cluster_offset) {
+ if (bs->backing_hd) {
+ /* read from the base image */
+ n1 = backing_read1(bs->backing_hd, acb->sector_num,
+ acb->buf, acb->n);
+ if (n1 > 0) {
+ acb->hd_aiocb = bdrv_aio_read(bs->backing_hd, acb->sector_num,
+ acb->buf, acb->n, qcow_aio_read_cb, acb);
+ if (acb->hd_aiocb == NULL)
+ goto fail;
+ } else {
+ goto redo;
+ }
+ } else {
+ /* Note: in this case, no need to wait */
+ memset(acb->buf, 0, 512 * acb->n);
+ goto redo;
+ }
+ } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
+ /* add AIO support for compressed blocks ? */
+ if (decompress_cluster(s, acb->cluster_offset) < 0)
+ goto fail;
+ memcpy(acb->buf,
+ s->cluster_cache + index_in_cluster * 512, 512 * acb->n);
+ goto redo;
+ } else {
+ if ((acb->cluster_offset & 511) != 0) {
+ ret = -EIO;
+ goto fail;
+ }
+ acb->hd_aiocb = bdrv_aio_read(s->hd,
+ (acb->cluster_offset >> 9) + index_in_cluster,
+ acb->buf, acb->n, qcow_aio_read_cb, acb);
+ if (acb->hd_aiocb == NULL)
+ goto fail;
+ }
+}
+
+static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
+ int64_t sector_num, uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ QCowAIOCB *acb;
+
+ acb = qemu_aio_get(bs, cb, opaque);
+ if (!acb)
+ return NULL;
+ acb->hd_aiocb = NULL;
+ acb->sector_num = sector_num;
+ acb->buf = buf;
+ acb->nb_sectors = nb_sectors;
+ acb->n = 0;
+ acb->cluster_offset = 0;
+ return acb;
+}
+
+static BlockDriverAIOCB *qcow_aio_read(BlockDriverState *bs,
+ int64_t sector_num, uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ QCowAIOCB *acb;
+
+ acb = qcow_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
+ if (!acb)
+ return NULL;
+
+ qcow_aio_read_cb(acb, 0);
+ return &acb->common;
+}
+
+static void qcow_aio_write_cb(void *opaque, int ret)
+{
+ QCowAIOCB *acb = opaque;
+ BlockDriverState *bs = acb->common.bs;
+ BDRVQcowState *s = bs->opaque;
+ int index_in_cluster;
+ uint64_t cluster_offset;
+ const uint8_t *src_buf;
+
+ acb->hd_aiocb = NULL;
+
+ if (ret < 0) {
+ fail:
+ acb->common.cb(acb->common.opaque, ret);
+ qemu_aio_release(acb);
+ return;
+ }
+
+ acb->nb_sectors -= acb->n;
+ acb->sector_num += acb->n;
+ acb->buf += acb->n * 512;
+
+ if (acb->nb_sectors == 0) {
+ /* request completed */
+ acb->common.cb(acb->common.opaque, 0);
+ qemu_aio_release(acb);
+ return;
+ }
+
+ index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
+ acb->n = s->cluster_sectors - index_in_cluster;
+ if (acb->n > acb->nb_sectors)
+ acb->n = acb->nb_sectors;
+ cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 1, 0,
+ index_in_cluster,
+ index_in_cluster + acb->n);
+ if (!cluster_offset || (cluster_offset & 511) != 0) {
+ ret = -EIO;
+ goto fail;
+ }
+ if (s->crypt_method) {
+ if (!acb->cluster_data) {
+ acb->cluster_data = qemu_mallocz(s->cluster_size);
+ if (!acb->cluster_data) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+ }
+ encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf,
+ acb->n, 1, &s->aes_encrypt_key);
+ src_buf = acb->cluster_data;
+ } else {
+ src_buf = acb->buf;
+ }
+ acb->hd_aiocb = bdrv_aio_write(s->hd,
+ (cluster_offset >> 9) + index_in_cluster,
+ src_buf, acb->n,
+ qcow_aio_write_cb, acb);
+ if (acb->hd_aiocb == NULL)
+ goto fail;
+}
+
+static BlockDriverAIOCB *qcow_aio_write(BlockDriverState *bs,
+ int64_t sector_num, const uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ BDRVQcowState *s = bs->opaque;
+ QCowAIOCB *acb;
+
+ s->cluster_cache_offset = -1; /* disable compressed cache */
+
+ acb = qcow_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque);
+ if (!acb)
+ return NULL;
+
+ qcow_aio_write_cb(acb, 0);
+ return &acb->common;
+}
+
+static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+ QCowAIOCB *acb = (QCowAIOCB *)blockacb;
+ if (acb->hd_aiocb)
+ bdrv_aio_cancel(acb->hd_aiocb);
+ qemu_aio_release(acb);
+}
+
+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);
+ refcount_close(bs);
+ bdrv_delete(s->hd);
+}
+
+/* XXX: use std qcow open function ? */
+typedef struct QCowCreateState {
+ int cluster_size;
+ int cluster_bits;
+ uint16_t *refcount_block;
+ uint64_t *refcount_table;
+ int64_t l1_table_offset;
+ int64_t refcount_table_offset;
+ int64_t refcount_block_offset;
+} QCowCreateState;
+
+static void create_refcount_update(QCowCreateState *s,
+ int64_t offset, int64_t size)
+{
+ int refcount;
+ int64_t start, last, cluster_offset;
+ uint16_t *p;
+
+ start = offset & ~(s->cluster_size - 1);
+ last = (offset + size - 1) & ~(s->cluster_size - 1);
+ for(cluster_offset = start; cluster_offset <= last;
+ cluster_offset += s->cluster_size) {
+ p = &s->refcount_block[cluster_offset >> s->cluster_bits];
+ refcount = be16_to_cpu(*p);
+ refcount++;
+ *p = cpu_to_be16(refcount);
+ }
+}
+
+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, l2_bits;
+ QCowHeader header;
+ uint64_t tmp, offset;
+ QCowCreateState s1, *s = &s1;
+
+ memset(s, 0, sizeof(*s));
+
+ fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 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) {
+ header.backing_file_offset = cpu_to_be64(header_size);
+ backing_filename_len = strlen(backing_file);
+ header.backing_file_size = cpu_to_be32(backing_filename_len);
+ header_size += backing_filename_len;
+ }
+ s->cluster_bits = 12; /* 4 KB clusters */
+ s->cluster_size = 1 << s->cluster_bits;
+ header.cluster_bits = cpu_to_be32(s->cluster_bits);
+ header_size = (header_size + 7) & ~7;
+ if (flags) {
+ header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
+ } else {
+ header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
+ }
+ l2_bits = s->cluster_bits - 3;
+ shift = s->cluster_bits + l2_bits;
+ l1_size = (((total_size * 512) + (1LL << shift) - 1) >> shift);
+ offset = align_offset(header_size, s->cluster_size);
+ s->l1_table_offset = offset;
+ header.l1_table_offset = cpu_to_be64(s->l1_table_offset);
+ header.l1_size = cpu_to_be32(l1_size);
+ offset += align_offset(l1_size * sizeof(uint64_t), s->cluster_size);
+
+ s->refcount_table = qemu_mallocz(s->cluster_size);
+ if (!s->refcount_table)
+ goto fail;
+ s->refcount_block = qemu_mallocz(s->cluster_size);
+ if (!s->refcount_block)
+ goto fail;
+
+ s->refcount_table_offset = offset;
+ header.refcount_table_offset = cpu_to_be64(offset);
+ header.refcount_table_clusters = cpu_to_be32(1);
+ offset += s->cluster_size;
+
+ s->refcount_table[0] = cpu_to_be64(offset);
+ s->refcount_block_offset = offset;
+ offset += s->cluster_size;
+
+ /* update refcounts */
+ create_refcount_update(s, 0, header_size);
+ create_refcount_update(s, s->l1_table_offset, l1_size * sizeof(uint64_t));
+ create_refcount_update(s, s->refcount_table_offset, s->cluster_size);
+ create_refcount_update(s, s->refcount_block_offset, s->cluster_size);
+
+ /* write all the data */
+ write(fd, &header, sizeof(header));
+ if (backing_file) {
+ write(fd, backing_file, backing_filename_len);
+ }
+ lseek(fd, s->l1_table_offset, SEEK_SET);
+ tmp = 0;
+ for(i = 0;i < l1_size; i++) {
+ write(fd, &tmp, sizeof(tmp));
+ }
+ lseek(fd, s->refcount_table_offset, SEEK_SET);
+ write(fd, s->refcount_table, s->cluster_size);
+
+ lseek(fd, s->refcount_block_offset, SEEK_SET);
+ write(fd, s->refcount_block, s->cluster_size);
+
+ qemu_free(s->refcount_table);
+ qemu_free(s->refcount_block);
+ close(fd);
+ return 0;
+ fail:
+ qemu_free(s->refcount_table);
+ qemu_free(s->refcount_block);
+ close(fd);
+ return -ENOMEM;
+}
+
+static int qcow_make_empty(BlockDriverState *bs)
+{
+#if 0
+ /* XXX: not correct */
+ BDRVQcowState *s = bs->opaque;
+ uint32_t l1_length = s->l1_size * sizeof(uint64_t);
+ int ret;
+
+ memset(s->l1_table, 0, l1_length);
+ if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_length) < 0)
+ return -1;
+ ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length);
+ if (ret < 0)
+ return ret;
+
+ l2_cache_reset(bs);
+#endif
+ return 0;
+}
+
+/* XXX: put compressed sectors first, then all the cluster aligned
+ tables to avoid losing bytes in alignment */
+static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
+ const uint8_t *buf, int nb_sectors)
+{
+ BDRVQcowState *s = bs->opaque;
+ z_stream strm;
+ int ret, out_len;
+ uint8_t *out_buf;
+ uint64_t cluster_offset;
+
+ if (nb_sectors == 0) {
+ /* align end of file to a sector boundary to ease reading with
+ sector based I/Os */
+ cluster_offset = bdrv_getlength(s->hd);
+ cluster_offset = (cluster_offset + 511) & ~511;
+ bdrv_truncate(s->hd, cluster_offset);
+ return 0;
+ }
+
+ if (nb_sectors != s->cluster_sectors)
+ return -EINVAL;
+
+ out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
+ if (!out_buf)
+ return -ENOMEM;
+
+ /* 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;
+ if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) {
+ qemu_free(out_buf);
+ return -1;
+ }
+ }
+
+ qemu_free(out_buf);
+ return 0;
+}
+
+static void qcow_flush(BlockDriverState *bs)
+{
+ BDRVQcowState *s = bs->opaque;
+ bdrv_flush(s->hd);
+}
+
+static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
+{
+ BDRVQcowState *s = bs->opaque;
+ bdi->cluster_size = s->cluster_size;
+ bdi->vm_state_offset = (int64_t)s->l1_vm_state_index <<
+ (s->cluster_bits + s->l2_bits);
+ return 0;
+}
+
+/*********************************************************/
+/* snapshot support */
+
+/* update the refcounts of snapshots and the copied flag */
+static int update_snapshot_refcount(BlockDriverState *bs,
+ int64_t l1_table_offset,
+ int l1_size,
+ int addend)
+{
+ BDRVQcowState *s = bs->opaque;
+ uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated;
+ int64_t old_offset, old_l2_offset;
+ int l2_size, i, j, l1_modified, l2_modified, nb_csectors, refcount;
+
+ l2_cache_reset(bs);
+
+ l2_table = NULL;
+ l1_table = NULL;
+ l1_size2 = l1_size * sizeof(uint64_t);
+ l1_allocated = 0;
+ if (l1_table_offset != s->l1_table_offset) {
+ l1_table = qemu_malloc(l1_size2);
+ if (!l1_table)
+ goto fail;
+ l1_allocated = 1;
+ if (bdrv_pread(s->hd, l1_table_offset,
+ l1_table, l1_size2) != l1_size2)
+ goto fail;
+ for(i = 0;i < l1_size; i++)
+ be64_to_cpus(&l1_table[i]);
+ } else {
+ assert(l1_size == s->l1_size);
+ l1_table = s->l1_table;
+ l1_allocated = 0;
+ }
+
+ l2_size = s->l2_size * sizeof(uint64_t);
+ l2_table = qemu_malloc(l2_size);
+ if (!l2_table)
+ goto fail;
+ l1_modified = 0;
+ for(i = 0; i < l1_size; i++) {
+ l2_offset = l1_table[i];
+ if (l2_offset) {
+ old_l2_offset = l2_offset;
+ l2_offset &= ~QCOW_OFLAG_COPIED;
+ l2_modified = 0;
+ if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size)
+ goto fail;
+ for(j = 0; j < s->l2_size; j++) {
+ offset = be64_to_cpu(l2_table[j]);
+ if (offset != 0) {
+ old_offset = offset;
+ offset &= ~QCOW_OFLAG_COPIED;
+ if (offset & QCOW_OFLAG_COMPRESSED) {
+ nb_csectors = ((offset >> s->csize_shift) &
+ s->csize_mask) + 1;
+ if (addend != 0)
+ update_refcount(bs, (offset & s->cluster_offset_mask) & ~511,
+ nb_csectors * 512, addend);
+ /* compressed clusters are never modified */
+ refcount = 2;
+ } else {
+ if (addend != 0) {
+ refcount = update_cluster_refcount(bs, offset >> s->cluster_bits, addend);
+ } else {
+ refcount = get_refcount(bs, offset >> s->cluster_bits);
+ }
+ }
+
+ if (refcount == 1) {
+ offset |= QCOW_OFLAG_COPIED;
+ }
+ if (offset != old_offset) {
+ l2_table[j] = cpu_to_be64(offset);
+ l2_modified = 1;
+ }
+ }
+ }
+ if (l2_modified) {
+ if (bdrv_pwrite(s->hd,
+ l2_offset, l2_table, l2_size) != l2_size)
+ goto fail;
+ }
+
+ if (addend != 0) {
+ refcount = update_cluster_refcount(bs, l2_offset >> s->cluster_bits, addend);
+ } else {
+ refcount = get_refcount(bs, l2_offset >> s->cluster_bits);
+ }
+ if (refcount == 1) {
+ l2_offset |= QCOW_OFLAG_COPIED;
+ }
+ if (l2_offset != old_l2_offset) {
+ l1_table[i] = l2_offset;
+ l1_modified = 1;
+ }
+ }
+ }
+ if (l1_modified) {
+ for(i = 0; i < l1_size; i++)
+ cpu_to_be64s(&l1_table[i]);
+ if (bdrv_pwrite(s->hd, l1_table_offset, l1_table,
+ l1_size2) != l1_size2)
+ goto fail;
+ for(i = 0; i < l1_size; i++)
+ be64_to_cpus(&l1_table[i]);
+ }
+ if (l1_allocated)
+ qemu_free(l1_table);
+ qemu_free(l2_table);
+ return 0;
+ fail:
+ if (l1_allocated)
+ qemu_free(l1_table);
+ qemu_free(l2_table);
+ return -EIO;
+}
+
+static void qcow_free_snapshots(BlockDriverState *bs)
+{
+ BDRVQcowState *s = bs->opaque;
+ int i;
+
+ for(i = 0; i < s->nb_snapshots; i++) {
+ qemu_free(s->snapshots[i].name);
+ qemu_free(s->snapshots[i].id_str);
+ }
+ qemu_free(s->snapshots);
+ s->snapshots = NULL;
+ s->nb_snapshots = 0;
+}
+
+static int qcow_read_snapshots(BlockDriverState *bs)
+{
+ BDRVQcowState *s = bs->opaque;
+ QCowSnapshotHeader h;
+ QCowSnapshot *sn;
+ int i, id_str_size, name_size;
+ int64_t offset;
+ uint32_t extra_data_size;
+
+ offset = s->snapshots_offset;
+ s->snapshots = qemu_mallocz(s->nb_snapshots * sizeof(QCowSnapshot));
+ if (!s->snapshots)
+ goto fail;
+ for(i = 0; i < s->nb_snapshots; i++) {
+ offset = align_offset(offset, 8);
+ if (bdrv_pread(s->hd, offset, &h, sizeof(h)) != sizeof(h))
+ goto fail;
+ offset += sizeof(h);
+ sn = s->snapshots + i;
+ sn->l1_table_offset = be64_to_cpu(h.l1_table_offset);
+ sn->l1_size = be32_to_cpu(h.l1_size);
+ sn->vm_state_size = be32_to_cpu(h.vm_state_size);
+ sn->date_sec = be32_to_cpu(h.date_sec);
+ sn->date_nsec = be32_to_cpu(h.date_nsec);
+ sn->vm_clock_nsec = be64_to_cpu(h.vm_clock_nsec);
+ extra_data_size = be32_to_cpu(h.extra_data_size);
+
+ id_str_size = be16_to_cpu(h.id_str_size);
+ name_size = be16_to_cpu(h.name_size);
+
+ offset += extra_data_size;
+
+ sn->id_str = qemu_malloc(id_str_size + 1);
+ if (!sn->id_str)
+ goto fail;
+ if (bdrv_pread(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
+ goto fail;
+ offset += id_str_size;
+ sn->id_str[id_str_size] = '\0';
+
+ sn->name = qemu_malloc(name_size + 1);
+ if (!sn->name)
+ goto fail;
+ if (bdrv_pread(s->hd, offset, sn->name, name_size) != name_size)
+ goto fail;
+ offset += name_size;
+ sn->name[name_size] = '\0';
+ }
+ s->snapshots_size = offset - s->snapshots_offset;
+ return 0;
+ fail:
+ qcow_free_snapshots(bs);
+ return -1;
+}
+
+/* add at the end of the file a new list of snapshots */
+static int qcow_write_snapshots(BlockDriverState *bs)
+{
+ BDRVQcowState *s = bs->opaque;
+ QCowSnapshot *sn;
+ QCowSnapshotHeader h;
+ int i, name_size, id_str_size, snapshots_size;
+ uint64_t data64;
+ uint32_t data32;
+ int64_t offset, snapshots_offset;
+
+ /* compute the size of the snapshots */
+ offset = 0;
+ for(i = 0; i < s->nb_snapshots; i++) {
+ sn = s->snapshots + i;
+ offset = align_offset(offset, 8);
+ offset += sizeof(h);
+ offset += strlen(sn->id_str);
+ offset += strlen(sn->name);
+ }
+ snapshots_size = offset;
+
+ snapshots_offset = alloc_clusters(bs, snapshots_size);
+ offset = snapshots_offset;
+
+ for(i = 0; i < s->nb_snapshots; i++) {
+ sn = s->snapshots + i;
+ memset(&h, 0, sizeof(h));
+ h.l1_table_offset = cpu_to_be64(sn->l1_table_offset);
+ h.l1_size = cpu_to_be32(sn->l1_size);
+ h.vm_state_size = cpu_to_be32(sn->vm_state_size);
+ h.date_sec = cpu_to_be32(sn->date_sec);
+ h.date_nsec = cpu_to_be32(sn->date_nsec);
+ h.vm_clock_nsec = cpu_to_be64(sn->vm_clock_nsec);
+
+ id_str_size = strlen(sn->id_str);
+ name_size = strlen(sn->name);
+ h.id_str_size = cpu_to_be16(id_str_size);
+ h.name_size = cpu_to_be16(name_size);
+ offset = align_offset(offset, 8);
+ if (bdrv_pwrite(s->hd, offset, &h, sizeof(h)) != sizeof(h))
+ goto fail;
+ offset += sizeof(h);
+ if (bdrv_pwrite(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
+ goto fail;
+ offset += id_str_size;
+ if (bdrv_pwrite(s->hd, offset, sn->name, name_size) != name_size)
+ goto fail;
+ offset += name_size;
+ }
+
+ /* update the various header fields */
+ data64 = cpu_to_be64(snapshots_offset);
+ if (bdrv_pwrite(s->hd, offsetof(QCowHeader, snapshots_offset),
+ &data64, sizeof(data64)) != sizeof(data64))
+ goto fail;
+ data32 = cpu_to_be32(s->nb_snapshots);
+ if (bdrv_pwrite(s->hd, offsetof(QCowHeader, nb_snapshots),
+ &data32, sizeof(data32)) != sizeof(data32))
+ goto fail;
+
+ /* free the old snapshot table */
+ free_clusters(bs, s->snapshots_offset, s->snapshots_size);
+ s->snapshots_offset = snapshots_offset;
+ s->snapshots_size = snapshots_size;
+ return 0;
+ fail:
+ return -1;
+}
+
+static void find_new_snapshot_id(BlockDriverState *bs,
+ char *id_str, int id_str_size)
+{
+ BDRVQcowState *s = bs->opaque;
+ QCowSnapshot *sn;
+ int i, id, id_max = 0;
+
+ for(i = 0; i < s->nb_snapshots; i++) {
+ sn = s->snapshots + i;
+ id = strtoul(sn->id_str, NULL, 10);
+ if (id > id_max)
+ id_max = id;
+ }
+ snprintf(id_str, id_str_size, "%d", id_max + 1);
+}
+
+static int find_snapshot_by_id(BlockDriverState *bs, const char *id_str)
+{
+ BDRVQcowState *s = bs->opaque;
+ int i;
+
+ for(i = 0; i < s->nb_snapshots; i++) {
+ if (!strcmp(s->snapshots[i].id_str, id_str))
+ return i;
+ }
+ return -1;
+}
+
+static int find_snapshot_by_id_or_name(BlockDriverState *bs, const char *name)
+{
+ BDRVQcowState *s = bs->opaque;
+ int i, ret;
+
+ ret = find_snapshot_by_id(bs, name);
+ if (ret >= 0)
+ return ret;
+ for(i = 0; i < s->nb_snapshots; i++) {
+ if (!strcmp(s->snapshots[i].name, name))
+ return i;
+ }
+ return -1;
+}
+
+/* if no id is provided, a new one is constructed */
+static int qcow_snapshot_create(BlockDriverState *bs,
+ QEMUSnapshotInfo *sn_info)
+{
+ BDRVQcowState *s = bs->opaque;
+ QCowSnapshot *snapshots1, sn1, *sn = &sn1;
+ int i, ret;
+ uint64_t *l1_table = NULL;
+
+ memset(sn, 0, sizeof(*sn));
+
+ if (sn_info->id_str[0] == '\0') {
+ /* compute a new id */
+ find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str));
+ }
+
+ /* check that the ID is unique */
+ if (find_snapshot_by_id(bs, sn_info->id_str) >= 0)
+ return -ENOENT;
+
+ sn->id_str = qemu_strdup(sn_info->id_str);
+ if (!sn->id_str)
+ goto fail;
+ sn->name = qemu_strdup(sn_info->name);
+ if (!sn->name)
+ goto fail;
+ sn->vm_state_size = sn_info->vm_state_size;
+ sn->date_sec = sn_info->date_sec;
+ sn->date_nsec = sn_info->date_nsec;
+ sn->vm_clock_nsec = sn_info->vm_clock_nsec;
+
+ ret = update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1);
+ if (ret < 0)
+ goto fail;
+
+ /* create the L1 table of the snapshot */
+ sn->l1_table_offset = alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
+ sn->l1_size = s->l1_size;
+
+ l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
+ if (!l1_table)
+ goto fail;
+ for(i = 0; i < s->l1_size; i++) {
+ l1_table[i] = cpu_to_be64(s->l1_table[i]);
+ }
+ if (bdrv_pwrite(s->hd, sn->l1_table_offset,
+ l1_table, s->l1_size * sizeof(uint64_t)) !=
+ (s->l1_size * sizeof(uint64_t)))
+ goto fail;
+ qemu_free(l1_table);
+ l1_table = NULL;
+
+ snapshots1 = qemu_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
+ if (!snapshots1)
+ goto fail;
+ memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot));
+ s->snapshots = snapshots1;
+ s->snapshots[s->nb_snapshots++] = *sn;
+
+ if (qcow_write_snapshots(bs) < 0)
+ goto fail;
+#ifdef DEBUG_ALLOC
+ check_refcounts(bs);
+#endif
+ return 0;
+ fail:
+ qemu_free(sn->name);
+ qemu_free(l1_table);
+ return -1;
+}
+
+/* copy the snapshot 'snapshot_name' into the current disk image */
+static int qcow_snapshot_goto(BlockDriverState *bs,
+ const char *snapshot_id)
+{
+ BDRVQcowState *s = bs->opaque;
+ QCowSnapshot *sn;
+ int i, snapshot_index, l1_size2;
+
+ snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
+ if (snapshot_index < 0)
+ return -ENOENT;
+ sn = &s->snapshots[snapshot_index];
+
+ if (update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, -1) < 0)
+ goto fail;
+
+ if (grow_l1_table(bs, sn->l1_size) < 0)
+ goto fail;
+
+ s->l1_size = sn->l1_size;
+ l1_size2 = s->l1_size * sizeof(uint64_t);
+ /* copy the snapshot l1 table to the current l1 table */
+ if (bdrv_pread(s->hd, sn->l1_table_offset,
+ s->l1_table, l1_size2) != l1_size2)
+ goto fail;
+ if (bdrv_pwrite(s->hd, s->l1_table_offset,
+ s->l1_table, l1_size2) != l1_size2)
+ goto fail;
+ for(i = 0;i < s->l1_size; i++) {
+ be64_to_cpus(&s->l1_table[i]);
+ }
+
+ if (update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1) < 0)
+ goto fail;
+
+#ifdef DEBUG_ALLOC
+ check_refcounts(bs);
+#endif
+ return 0;
+ fail:
+ return -EIO;
+}
+
+static int qcow_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
+{
+ BDRVQcowState *s = bs->opaque;
+ QCowSnapshot *sn;
+ int snapshot_index, ret;
+
+ snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
+ if (snapshot_index < 0)
+ return -ENOENT;
+ sn = &s->snapshots[snapshot_index];
+
+ ret = update_snapshot_refcount(bs, sn->l1_table_offset, sn->l1_size, -1);
+ if (ret < 0)
+ return ret;
+ /* must update the copied flag on the current cluster offsets */
+ ret = update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
+ if (ret < 0)
+ return ret;
+ free_clusters(bs, sn->l1_table_offset, sn->l1_size * sizeof(uint64_t));
+
+ qemu_free(sn->id_str);
+ qemu_free(sn->name);
+ memmove(sn, sn + 1, (s->nb_snapshots - snapshot_index - 1) * sizeof(*sn));
+ s->nb_snapshots--;
+ ret = qcow_write_snapshots(bs);
+ if (ret < 0) {
+ /* XXX: restore snapshot if error ? */
+ return ret;
+ }
+#ifdef DEBUG_ALLOC
+ check_refcounts(bs);
+#endif
+ return 0;
+}
+
+static int qcow_snapshot_list(BlockDriverState *bs,
+ QEMUSnapshotInfo **psn_tab)
+{
+ BDRVQcowState *s = bs->opaque;
+ QEMUSnapshotInfo *sn_tab, *sn_info;
+ QCowSnapshot *sn;
+ int i;
+
+ sn_tab = qemu_mallocz(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
+ if (!sn_tab)
+ goto fail;
+ for(i = 0; i < s->nb_snapshots; i++) {
+ sn_info = sn_tab + i;
+ sn = s->snapshots + i;
+ pstrcpy(sn_info->id_str, sizeof(sn_info->id_str),
+ sn->id_str);
+ pstrcpy(sn_info->name, sizeof(sn_info->name),
+ sn->name);
+ sn_info->vm_state_size = sn->vm_state_size;
+ sn_info->date_sec = sn->date_sec;
+ sn_info->date_nsec = sn->date_nsec;
+ sn_info->vm_clock_nsec = sn->vm_clock_nsec;
+ }
+ *psn_tab = sn_tab;
+ return s->nb_snapshots;
+ fail:
+ qemu_free(sn_tab);
+ *psn_tab = NULL;
+ return -ENOMEM;
+}
+
+/*********************************************************/
+/* refcount handling */
+
+static int refcount_init(BlockDriverState *bs)
+{
+ BDRVQcowState *s = bs->opaque;
+ int ret, refcount_table_size2, i;
+
+ s->refcount_block_cache = qemu_malloc(s->cluster_size);
+ if (!s->refcount_block_cache)
+ goto fail;
+ refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
+ s->refcount_table = qemu_malloc(refcount_table_size2);
+ if (!s->refcount_table)
+ goto fail;
+ if (s->refcount_table_size > 0) {
+ ret = bdrv_pread(s->hd, s->refcount_table_offset,
+ s->refcount_table, refcount_table_size2);
+ if (ret != refcount_table_size2)
+ goto fail;
+ for(i = 0; i < s->refcount_table_size; i++)
+ be64_to_cpus(&s->refcount_table[i]);
+ }
+ return 0;
+ fail:
+ return -ENOMEM;
+}
+
+static void refcount_close(BlockDriverState *bs)
+{
+ BDRVQcowState *s = bs->opaque;
+ qemu_free(s->refcount_block_cache);
+ qemu_free(s->refcount_table);
+}
+
+
+static int load_refcount_block(BlockDriverState *bs,
+ int64_t refcount_block_offset)
+{
+ BDRVQcowState *s = bs->opaque;
+ int ret;
+ ret = bdrv_pread(s->hd, refcount_block_offset, s->refcount_block_cache,
+ s->cluster_size);
+ if (ret != s->cluster_size)
+ return -EIO;
+ s->refcount_block_cache_offset = refcount_block_offset;
+ return 0;
+}
+
+static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
+{
+ BDRVQcowState *s = bs->opaque;
+ int refcount_table_index, block_index;
+ int64_t refcount_block_offset;
+
+ refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
+ if (refcount_table_index >= s->refcount_table_size)
+ return 0;
+ refcount_block_offset = s->refcount_table[refcount_table_index];
+ if (!refcount_block_offset)
+ return 0;
+ if (refcount_block_offset != s->refcount_block_cache_offset) {
+ /* better than nothing: return allocated if read error */
+ if (load_refcount_block(bs, refcount_block_offset) < 0)
+ return 1;
+ }
+ block_index = cluster_index &
+ ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
+ return be16_to_cpu(s->refcount_block_cache[block_index]);
+}
+
+/* return < 0 if error */
+static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size)
+{
+ BDRVQcowState *s = bs->opaque;
+ int i, nb_clusters;
+
+ nb_clusters = (size + s->cluster_size - 1) >> s->cluster_bits;
+ for(;;) {
+ if (get_refcount(bs, s->free_cluster_index) == 0) {
+ s->free_cluster_index++;
+ for(i = 1; i < nb_clusters; i++) {
+ if (get_refcount(bs, s->free_cluster_index) != 0)
+ goto not_found;
+ s->free_cluster_index++;
+ }
+#ifdef DEBUG_ALLOC2
+ printf("alloc_clusters: size=%lld -> %lld\n",
+ size,
+ (s->free_cluster_index - nb_clusters) << s->cluster_bits);
+#endif
+ return (s->free_cluster_index - nb_clusters) << s->cluster_bits;
+ } else {
+ not_found:
+ s->free_cluster_index++;
+ }
+ }
+}
+
+static int64_t alloc_clusters(BlockDriverState *bs, int64_t size)
+{
+ int64_t offset;
+
+ offset = alloc_clusters_noref(bs, size);
+ update_refcount(bs, offset, size, 1);
+ return offset;
+}
+
+/* only used to allocate compressed sectors. We try to allocate
+ contiguous sectors. size must be <= cluster_size */
+static int64_t alloc_bytes(BlockDriverState *bs, int size)
+{
+ BDRVQcowState *s = bs->opaque;
+ int64_t offset, cluster_offset;
+ int free_in_cluster;
+
+ assert(size > 0 && size <= s->cluster_size);
+ if (s->free_byte_offset == 0) {
+ s->free_byte_offset = alloc_clusters(bs, s->cluster_size);
+ }
+ redo:
+ free_in_cluster = s->cluster_size -
+ (s->free_byte_offset & (s->cluster_size - 1));
+ if (size <= free_in_cluster) {
+ /* enough space in current cluster */
+ offset = s->free_byte_offset;
+ s->free_byte_offset += size;
+ free_in_cluster -= size;
+ if (free_in_cluster == 0)
+ s->free_byte_offset = 0;
+ if ((offset & (s->cluster_size - 1)) != 0)
+ update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
+ } else {
+ offset = alloc_clusters(bs, s->cluster_size);
+ cluster_offset = s->free_byte_offset & ~(s->cluster_size - 1);
+ if ((cluster_offset + s->cluster_size) == offset) {
+ /* we are lucky: contiguous data */
+ offset = s->free_byte_offset;
+ update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
+ s->free_byte_offset += size;
+ } else {
+ s->free_byte_offset = offset;
+ goto redo;
+ }
+ }
+ return offset;
+}
+
+static void free_clusters(BlockDriverState *bs,
+ int64_t offset, int64_t size)
+{
+ update_refcount(bs, offset, size, -1);
+}
+
+static int grow_refcount_table(BlockDriverState *bs, int min_size)
+{
+ BDRVQcowState *s = bs->opaque;
+ int new_table_size, new_table_size2, refcount_table_clusters, i, ret;
+ uint64_t *new_table;
+ int64_t table_offset;
+ uint64_t data64;
+ uint32_t data32;
+
+ if (min_size <= s->refcount_table_size)
+ return 0;
+ /* compute new table size */
+ refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3);
+ for(;;) {
+ if (refcount_table_clusters == 0) {
+ refcount_table_clusters = 1;
+ } else {
+ refcount_table_clusters = (refcount_table_clusters * 3 + 1) / 2;
+ }
+ new_table_size = refcount_table_clusters << (s->cluster_bits - 3);
+ if (min_size <= new_table_size)
+ break;
+ }
+#ifdef DEBUG_ALLOC2
+ printf("grow_refcount_table from %d to %d\n",
+ s->refcount_table_size,
+ new_table_size);
+#endif
+ new_table_size2 = new_table_size * sizeof(uint64_t);
+ new_table = qemu_mallocz(new_table_size2);
+ if (!new_table)
+ return -ENOMEM;
+ memcpy(new_table, s->refcount_table,
+ s->refcount_table_size * sizeof(uint64_t));
+ for(i = 0; i < s->refcount_table_size; i++)
+ cpu_to_be64s(&new_table[i]);
+ /* Note: we cannot update the refcount now to avoid recursion */
+ table_offset = alloc_clusters_noref(bs, new_table_size2);
+ ret = bdrv_pwrite(s->hd, table_offset, new_table, new_table_size2);
+ if (ret != new_table_size2)
+ goto fail;
+ for(i = 0; i < s->refcount_table_size; i++)
+ be64_to_cpus(&new_table[i]);
+
+ data64 = cpu_to_be64(table_offset);
+ if (bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_offset),
+ &data64, sizeof(data64)) != sizeof(data64))
+ goto fail;
+ data32 = cpu_to_be32(refcount_table_clusters);
+ if (bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_clusters),
+ &data32, sizeof(data32)) != sizeof(data32))
+ goto fail;
+ qemu_free(s->refcount_table);
+ s->refcount_table = new_table;
+ s->refcount_table_size = new_table_size;
+
+ update_refcount(bs, table_offset, new_table_size2, 1);
+ return 0;
+ fail:
+ free_clusters(bs, table_offset, new_table_size2);
+ qemu_free(new_table);
+ return -EIO;
+}
+
+/* addend must be 1 or -1 */
+/* XXX: cache several refcount block clusters ? */
+static int update_cluster_refcount(BlockDriverState *bs,
+ int64_t cluster_index,
+ int addend)
+{
+ BDRVQcowState *s = bs->opaque;
+ int64_t offset, refcount_block_offset;
+ int ret, refcount_table_index, block_index, refcount;
+ uint64_t data64;
+
+ refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
+ if (refcount_table_index >= s->refcount_table_size) {
+ if (addend < 0)
+ return -EINVAL;
+ ret = grow_refcount_table(bs, refcount_table_index + 1);
+ if (ret < 0)
+ return ret;
+ }
+ refcount_block_offset = s->refcount_table[refcount_table_index];
+ if (!refcount_block_offset) {
+ if (addend < 0)
+ return -EINVAL;
+ /* create a new refcount block */
+ /* Note: we cannot update the refcount now to avoid recursion */
+ offset = alloc_clusters_noref(bs, s->cluster_size);
+ memset(s->refcount_block_cache, 0, s->cluster_size);
+ ret = bdrv_pwrite(s->hd, offset, s->refcount_block_cache, s->cluster_size);
+ if (ret != s->cluster_size)
+ return -EINVAL;
+ s->refcount_table[refcount_table_index] = offset;
+ data64 = cpu_to_be64(offset);
+ ret = bdrv_pwrite(s->hd, s->refcount_table_offset +
+ refcount_table_index * sizeof(uint64_t),
+ &data64, sizeof(data64));
+ if (ret != sizeof(data64))
+ return -EINVAL;
+
+ refcount_block_offset = offset;
+ s->refcount_block_cache_offset = offset;
+ update_refcount(bs, offset, s->cluster_size, 1);
+ } else {
+ if (refcount_block_offset != s->refcount_block_cache_offset) {
+ if (load_refcount_block(bs, refcount_block_offset) < 0)
+ return -EIO;
+ }
+ }
+ /* we can update the count and save it */
+ block_index = cluster_index &
+ ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
+ refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
+ refcount += addend;
+ if (refcount < 0 || refcount > 0xffff)
+ return -EINVAL;
+ if (refcount == 0 && cluster_index < s->free_cluster_index) {
+ s->free_cluster_index = cluster_index;
+ }
+ s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
+ if (bdrv_pwrite(s->hd,
+ refcount_block_offset + (block_index << REFCOUNT_SHIFT),
+ &s->refcount_block_cache[block_index], 2) != 2)
+ return -EIO;
+ return refcount;
+}
+
+static void update_refcount(BlockDriverState *bs,
+ int64_t offset, int64_t length,
+ int addend)
+{
+ BDRVQcowState *s = bs->opaque;
+ int64_t start, last, cluster_offset;
+
+#ifdef DEBUG_ALLOC2
+ printf("update_refcount: offset=%lld size=%lld addend=%d\n",
+ offset, length, addend);
+#endif
+ if (length <= 0)
+ return;
+ start = offset & ~(s->cluster_size - 1);
+ last = (offset + length - 1) & ~(s->cluster_size - 1);
+ for(cluster_offset = start; cluster_offset <= last;
+ cluster_offset += s->cluster_size) {
+ update_cluster_refcount(bs, cluster_offset >> s->cluster_bits, addend);
+ }
+}
+
+#ifdef DEBUG_ALLOC
+static void inc_refcounts(BlockDriverState *bs,
+ uint16_t *refcount_table,
+ int refcount_table_size,
+ int64_t offset, int64_t size)
+{
+ BDRVQcowState *s = bs->opaque;
+ int64_t start, last, cluster_offset;
+ int k;
+
+ if (size <= 0)
+ return;
+
+ start = offset & ~(s->cluster_size - 1);
+ last = (offset + size - 1) & ~(s->cluster_size - 1);
+ for(cluster_offset = start; cluster_offset <= last;
+ cluster_offset += s->cluster_size) {
+ k = cluster_offset >> s->cluster_bits;
+ if (k < 0 || k >= refcount_table_size) {
+ printf("ERROR: invalid cluster offset=0x%llx\n", cluster_offset);
+ } else {
+ if (++refcount_table[k] == 0) {
+ printf("ERROR: overflow cluster offset=0x%llx\n", cluster_offset);
+ }
+ }
+ }
+}
+
+static int check_refcounts_l1(BlockDriverState *bs,
+ uint16_t *refcount_table,
+ int refcount_table_size,
+ int64_t l1_table_offset, int l1_size,
+ int check_copied)
+{
+ BDRVQcowState *s = bs->opaque;
+ uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2;
+ int l2_size, i, j, nb_csectors, refcount;
+
+ l2_table = NULL;
+ l1_size2 = l1_size * sizeof(uint64_t);
+
+ inc_refcounts(bs, refcount_table, refcount_table_size,
+ l1_table_offset, l1_size2);
+
+ l1_table = qemu_malloc(l1_size2);
+ if (!l1_table)
+ goto fail;
+ if (bdrv_pread(s->hd, l1_table_offset,
+ l1_table, l1_size2) != l1_size2)
+ goto fail;
+ for(i = 0;i < l1_size; i++)
+ be64_to_cpus(&l1_table[i]);
+
+ l2_size = s->l2_size * sizeof(uint64_t);
+ l2_table = qemu_malloc(l2_size);
+ if (!l2_table)
+ goto fail;
+ for(i = 0; i < l1_size; i++) {
+ l2_offset = l1_table[i];
+ if (l2_offset) {
+ if (check_copied) {
+ refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED) >> s->cluster_bits);
+ if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) {
+ printf("ERROR OFLAG_COPIED: l2_offset=%llx refcount=%d\n",
+ l2_offset, refcount);
+ }
+ }
+ l2_offset &= ~QCOW_OFLAG_COPIED;
+ if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size)
+ goto fail;
+ for(j = 0; j < s->l2_size; j++) {
+ offset = be64_to_cpu(l2_table[j]);
+ if (offset != 0) {
+ if (offset & QCOW_OFLAG_COMPRESSED) {
+ if (offset & QCOW_OFLAG_COPIED) {
+ printf("ERROR: cluster %lld: copied flag must never be set for compressed clusters\n",
+ offset >> s->cluster_bits);
+ offset &= ~QCOW_OFLAG_COPIED;
+ }
+ nb_csectors = ((offset >> s->csize_shift) &
+ s->csize_mask) + 1;
+ offset &= s->cluster_offset_mask;
+ inc_refcounts(bs, refcount_table,
+ refcount_table_size,
+ offset & ~511, nb_csectors * 512);
+ } else {
+ if (check_copied) {
+ refcount = get_refcount(bs, (offset & ~QCOW_OFLAG_COPIED) >> s->cluster_bits);
+ if ((refcount == 1) != ((offset & QCOW_OFLAG_COPIED) != 0)) {
+ printf("ERROR OFLAG_COPIED: offset=%llx refcount=%d\n",
+ offset, refcount);
+ }
+ }
+ offset &= ~QCOW_OFLAG_COPIED;
+ inc_refcounts(bs, refcount_table,
+ refcount_table_size,
+ offset, s->cluster_size);
+ }
+ }
+ }
+ inc_refcounts(bs, refcount_table,
+ refcount_table_size,
+ l2_offset,
+ s->cluster_size);
+ }
+ }
+ qemu_free(l1_table);
+ qemu_free(l2_table);
+ return 0;
+ fail:
+ printf("ERROR: I/O error in check_refcounts_l1\n");
+ qemu_free(l1_table);
+ qemu_free(l2_table);
+ return -EIO;
+}
+
+static void check_refcounts(BlockDriverState *bs)
+{
+ BDRVQcowState *s = bs->opaque;
+ int64_t size;
+ int nb_clusters, refcount1, refcount2, i;
+ QCowSnapshot *sn;
+ uint16_t *refcount_table;
+
+ size = bdrv_getlength(s->hd);
+ nb_clusters = (size + s->cluster_size - 1) >> s->cluster_bits;
+ refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t));
+
+ /* header */
+ inc_refcounts(bs, refcount_table, nb_clusters,
+ 0, s->cluster_size);
+
+ check_refcounts_l1(bs, refcount_table, nb_clusters,
+ s->l1_table_offset, s->l1_size, 1);
+
+ /* snapshots */
+ for(i = 0; i < s->nb_snapshots; i++) {
+ sn = s->snapshots + i;
+ check_refcounts_l1(bs, refcount_table, nb_clusters,
+ sn->l1_table_offset, sn->l1_size, 0);
+ }
+ inc_refcounts(bs, refcount_table, nb_clusters,
+ s->snapshots_offset, s->snapshots_size);
+
+ /* refcount data */
+ inc_refcounts(bs, refcount_table, nb_clusters,
+ s->refcount_table_offset,
+ s->refcount_table_size * sizeof(uint64_t));
+ for(i = 0; i < s->refcount_table_size; i++) {
+ int64_t offset;
+ offset = s->refcount_table[i];
+ if (offset != 0) {
+ inc_refcounts(bs, refcount_table, nb_clusters,
+ offset, s->cluster_size);
+ }
+ }
+
+ /* compare ref counts */
+ for(i = 0; i < nb_clusters; i++) {
+ refcount1 = get_refcount(bs, i);
+ refcount2 = refcount_table[i];
+ if (refcount1 != refcount2)
+ printf("ERROR cluster %d refcount=%d reference=%d\n",
+ i, refcount1, refcount2);
+ }
+
+ qemu_free(refcount_table);
+}
+
+#if 0
+static void dump_refcounts(BlockDriverState *bs)
+{
+ BDRVQcowState *s = bs->opaque;
+ int64_t nb_clusters, k, k1, size;
+ int refcount;
+
+ size = bdrv_getlength(s->hd);
+ nb_clusters = (size + s->cluster_size - 1) >> s->cluster_bits;
+ for(k = 0; k < nb_clusters;) {
+ k1 = k;
+ refcount = get_refcount(bs, k);
+ k++;
+ while (k < nb_clusters && get_refcount(bs, k) == refcount)
+ k++;
+ printf("%lld: refcount=%d nb=%lld\n", k, refcount, k - k1);
+ }
+}
+#endif
+#endif
+
+BlockDriver bdrv_qcow2 = {
+ "qcow2",
+ sizeof(BDRVQcowState),
+ qcow_probe,
+ qcow_open,
+ NULL,
+ NULL,
+ qcow_close,
+ qcow_create,
+ qcow_flush,
+ qcow_is_allocated,
+ qcow_set_key,
+ qcow_make_empty,
+
+ .bdrv_aio_read = qcow_aio_read,
+ .bdrv_aio_write = qcow_aio_write,
+ .bdrv_aio_cancel = qcow_aio_cancel,
+ .aiocb_size = sizeof(QCowAIOCB),
+ .bdrv_write_compressed = qcow_write_compressed,
+
+ .bdrv_snapshot_create = qcow_snapshot_create,
+ .bdrv_snapshot_goto = qcow_snapshot_goto,
+ .bdrv_snapshot_delete = qcow_snapshot_delete,
+ .bdrv_snapshot_list = qcow_snapshot_list,
+ .bdrv_get_info = qcow_get_info,
+};
Added: trunk/src/host/qemu-neo1973/block-raw.c
===================================================================
--- trunk/src/host/qemu-neo1973/block-raw.c 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/block-raw.c 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,1342 @@
+/*
+ * Block driver for RAW files
+ *
+ * Copyright (c) 2006 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 <assert.h>
+#ifndef _WIN32
+#include <aio.h>
+
+#ifndef QEMU_TOOL
+#include "exec-all.h"
+#endif
+
+#ifdef CONFIG_COCOA
+#include <paths.h>
+#include <sys/param.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOBSD.h>
+#include <IOKit/storage/IOMediaBSDClient.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/storage/IOCDMedia.h>
+//#include <IOKit/storage/IOCDTypes.h>
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+#ifdef __sun__
+#define _POSIX_PTHREAD_SEMANTICS 1
+#include <signal.h>
+#include <sys/dkio.h>
+#endif
+#ifdef __linux__
+#include <sys/ioctl.h>
+#include <linux/cdrom.h>
+#include <linux/fd.h>
+#endif
+#ifdef __FreeBSD__
+#include <sys/disk.h>
+#endif
+
+//#define DEBUG_FLOPPY
+
+#define FTYPE_FILE 0
+#define FTYPE_CD 1
+#define FTYPE_FD 2
+
+/* if the FD is not accessed during that time (in ms), we try to
+ reopen it to see if the disk has been changed */
+#define FD_OPEN_TIMEOUT 1000
+
+typedef struct BDRVRawState {
+ int fd;
+ int type;
+#if defined(__linux__)
+ /* linux floppy specific */
+ int fd_open_flags;
+ int64_t fd_open_time;
+ int64_t fd_error_time;
+ int fd_got_error;
+ int fd_media_changed;
+#endif
+} BDRVRawState;
+
+static int fd_open(BlockDriverState *bs);
+
+static int raw_open(BlockDriverState *bs, const char *filename, int flags)
+{
+ BDRVRawState *s = bs->opaque;
+ int fd, open_flags, ret;
+
+ open_flags = O_BINARY;
+ if ((flags & BDRV_O_ACCESS) == O_RDWR) {
+ open_flags |= O_RDWR;
+ } else {
+ open_flags |= O_RDONLY;
+ bs->read_only = 1;
+ }
+ if (flags & BDRV_O_CREAT)
+ open_flags |= O_CREAT | O_TRUNC;
+
+ s->type = FTYPE_FILE;
+
+ fd = open(filename, open_flags, 0644);
+ if (fd < 0) {
+ ret = -errno;
+ if (ret == -EROFS)
+ ret = -EACCES;
+ return ret;
+ }
+ s->fd = fd;
+ return 0;
+}
+
+/* XXX: use host sector size if necessary with:
+#ifdef DIOCGSECTORSIZE
+ {
+ unsigned int sectorsize = 512;
+ if (!ioctl(fd, DIOCGSECTORSIZE, §orsize) &&
+ sectorsize > bufsize)
+ bufsize = sectorsize;
+ }
+#endif
+#ifdef CONFIG_COCOA
+ u_int32_t blockSize = 512;
+ if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) {
+ bufsize = blockSize;
+ }
+#endif
+*/
+
+static int raw_pread(BlockDriverState *bs, int64_t offset,
+ uint8_t *buf, int count)
+{
+ BDRVRawState *s = bs->opaque;
+ int ret;
+
+ ret = fd_open(bs);
+ if (ret < 0)
+ return ret;
+
+ lseek(s->fd, offset, SEEK_SET);
+ ret = read(s->fd, buf, count);
+ return ret;
+}
+
+static int raw_pwrite(BlockDriverState *bs, int64_t offset,
+ const uint8_t *buf, int count)
+{
+ BDRVRawState *s = bs->opaque;
+ int ret;
+
+ ret = fd_open(bs);
+ if (ret < 0)
+ return ret;
+
+ lseek(s->fd, offset, SEEK_SET);
+ ret = write(s->fd, buf, count);
+ return ret;
+}
+
+/***********************************************************/
+/* Unix AIO using POSIX AIO */
+
+typedef struct RawAIOCB {
+ BlockDriverAIOCB common;
+ struct aiocb aiocb;
+ struct RawAIOCB *next;
+} RawAIOCB;
+
+static int aio_sig_num = SIGUSR2;
+static RawAIOCB *first_aio; /* AIO issued */
+static int aio_initialized = 0;
+
+static void aio_signal_handler(int signum)
+{
+#ifndef QEMU_TOOL
+ CPUState *env = cpu_single_env;
+ if (env) {
+ /* stop the currently executing cpu because a timer occured */
+ cpu_interrupt(env, CPU_INTERRUPT_EXIT);
+#ifdef USE_KQEMU
+ if (env->kqemu_enabled) {
+ kqemu_cpu_interrupt(env);
+ }
+#endif
+ }
+#endif
+}
+
+void qemu_aio_init(void)
+{
+ struct sigaction act;
+
+ aio_initialized = 1;
+
+ sigfillset(&act.sa_mask);
+ act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
+ act.sa_handler = aio_signal_handler;
+ sigaction(aio_sig_num, &act, NULL);
+
+#if defined(__GLIBC__) && defined(__linux__)
+ {
+ /* XXX: aio thread exit seems to hang on RedHat 9 and this init
+ seems to fix the problem. */
+ struct aioinit ai;
+ memset(&ai, 0, sizeof(ai));
+ ai.aio_threads = 1;
+ ai.aio_num = 1;
+ ai.aio_idle_time = 365 * 100000;
+ aio_init(&ai);
+ }
+#endif
+}
+
+void qemu_aio_poll(void)
+{
+ RawAIOCB *acb, **pacb;
+ int ret;
+
+ for(;;) {
+ pacb = &first_aio;
+ for(;;) {
+ acb = *pacb;
+ if (!acb)
+ goto the_end;
+ ret = aio_error(&acb->aiocb);
+ if (ret == ECANCELED) {
+ /* remove the request */
+ *pacb = acb->next;
+ qemu_aio_release(acb);
+ } else if (ret != EINPROGRESS) {
+ /* end of aio */
+ if (ret == 0) {
+ ret = aio_return(&acb->aiocb);
+ if (ret == acb->aiocb.aio_nbytes)
+ ret = 0;
+ else
+ ret = -EINVAL;
+ } else {
+ ret = -ret;
+ }
+ /* remove the request */
+ *pacb = acb->next;
+ /* call the callback */
+ acb->common.cb(acb->common.opaque, ret);
+ qemu_aio_release(acb);
+ break;
+ } else {
+ pacb = &acb->next;
+ }
+ }
+ }
+ the_end: ;
+}
+
+/* Wait for all IO requests to complete. */
+void qemu_aio_flush(void)
+{
+ qemu_aio_wait_start();
+ qemu_aio_poll();
+ while (first_aio) {
+ qemu_aio_wait();
+ }
+ qemu_aio_wait_end();
+}
+
+/* wait until at least one AIO was handled */
+static sigset_t wait_oset;
+
+void qemu_aio_wait_start(void)
+{
+ sigset_t set;
+
+ if (!aio_initialized)
+ qemu_aio_init();
+ sigemptyset(&set);
+ sigaddset(&set, aio_sig_num);
+ sigprocmask(SIG_BLOCK, &set, &wait_oset);
+}
+
+void qemu_aio_wait(void)
+{
+ sigset_t set;
+ int nb_sigs;
+
+#ifndef QEMU_TOOL
+ if (qemu_bh_poll())
+ return;
+#endif
+ sigemptyset(&set);
+ sigaddset(&set, aio_sig_num);
+ sigwait(&set, &nb_sigs);
+ qemu_aio_poll();
+}
+
+void qemu_aio_wait_end(void)
+{
+ sigprocmask(SIG_SETMASK, &wait_oset, NULL);
+}
+
+static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
+ int64_t sector_num, uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ BDRVRawState *s = bs->opaque;
+ RawAIOCB *acb;
+
+ if (fd_open(bs) < 0)
+ return NULL;
+
+ acb = qemu_aio_get(bs, cb, opaque);
+ if (!acb)
+ return NULL;
+ acb->aiocb.aio_fildes = s->fd;
+ acb->aiocb.aio_sigevent.sigev_signo = aio_sig_num;
+ acb->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ acb->aiocb.aio_buf = buf;
+ acb->aiocb.aio_nbytes = nb_sectors * 512;
+ acb->aiocb.aio_offset = sector_num * 512;
+ acb->next = first_aio;
+ first_aio = acb;
+ return acb;
+}
+
+static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
+ int64_t sector_num, uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ RawAIOCB *acb;
+
+ acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
+ if (!acb)
+ return NULL;
+ if (aio_read(&acb->aiocb) < 0) {
+ qemu_aio_release(acb);
+ return NULL;
+ }
+ return &acb->common;
+}
+
+static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
+ int64_t sector_num, const uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ RawAIOCB *acb;
+
+ acb = raw_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque);
+ if (!acb)
+ return NULL;
+ if (aio_write(&acb->aiocb) < 0) {
+ qemu_aio_release(acb);
+ return NULL;
+ }
+ return &acb->common;
+}
+
+static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+ int ret;
+ RawAIOCB *acb = (RawAIOCB *)blockacb;
+ RawAIOCB **pacb;
+
+ ret = aio_cancel(acb->aiocb.aio_fildes, &acb->aiocb);
+ if (ret == AIO_NOTCANCELED) {
+ /* fail safe: if the aio could not be canceled, we wait for
+ it */
+ while (aio_error(&acb->aiocb) == EINPROGRESS);
+ }
+
+ /* remove the callback from the queue */
+ pacb = &first_aio;
+ for(;;) {
+ if (*pacb == NULL) {
+ break;
+ } else if (*pacb == acb) {
+ *pacb = acb->next;
+ qemu_aio_release(acb);
+ break;
+ }
+ pacb = &acb->next;
+ }
+}
+
+static void raw_close(BlockDriverState *bs)
+{
+ BDRVRawState *s = bs->opaque;
+ if (s->fd >= 0) {
+ close(s->fd);
+ s->fd = -1;
+ }
+}
+
+static int raw_truncate(BlockDriverState *bs, int64_t offset)
+{
+ BDRVRawState *s = bs->opaque;
+ if (s->type != FTYPE_FILE)
+ return -ENOTSUP;
+ if (ftruncate(s->fd, offset) < 0)
+ return -errno;
+ return 0;
+}
+
+static int64_t raw_getlength(BlockDriverState *bs)
+{
+ BDRVRawState *s = bs->opaque;
+ int fd = s->fd;
+ int64_t size;
+#ifdef _BSD
+ struct stat sb;
+#endif
+#ifdef __sun__
+ struct dk_minfo minfo;
+ int rv;
+#endif
+ int ret;
+
+ ret = fd_open(bs);
+ if (ret < 0)
+ return ret;
+
+#ifdef _BSD
+ if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
+#ifdef DIOCGMEDIASIZE
+ if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
+#endif
+#ifdef CONFIG_COCOA
+ size = LONG_LONG_MAX;
+#else
+ size = lseek(fd, 0LL, SEEK_END);
+#endif
+ } else
+#endif
+#ifdef __sun__
+ /*
+ * use the DKIOCGMEDIAINFO ioctl to read the size.
+ */
+ rv = ioctl ( fd, DKIOCGMEDIAINFO, &minfo );
+ if ( rv != -1 ) {
+ size = minfo.dki_lbsize * minfo.dki_capacity;
+ } else /* there are reports that lseek on some devices
+ fails, but irc discussion said that contingency
+ on contingency was overkill */
+#endif
+ {
+ size = lseek(fd, 0, SEEK_END);
+ }
+ return size;
+}
+
+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,
+ 0644);
+ if (fd < 0)
+ return -EIO;
+ ftruncate(fd, total_size * 512);
+ close(fd);
+ return 0;
+}
+
+static void raw_flush(BlockDriverState *bs)
+{
+ BDRVRawState *s = bs->opaque;
+ fsync(s->fd);
+}
+
+BlockDriver bdrv_raw = {
+ "raw",
+ sizeof(BDRVRawState),
+ NULL, /* no probe for protocols */
+ raw_open,
+ NULL,
+ NULL,
+ raw_close,
+ raw_create,
+ raw_flush,
+
+ .bdrv_aio_read = raw_aio_read,
+ .bdrv_aio_write = raw_aio_write,
+ .bdrv_aio_cancel = raw_aio_cancel,
+ .aiocb_size = sizeof(RawAIOCB),
+ .protocol_name = "file",
+ .bdrv_pread = raw_pread,
+ .bdrv_pwrite = raw_pwrite,
+ .bdrv_truncate = raw_truncate,
+ .bdrv_getlength = raw_getlength,
+};
+
+/***********************************************/
+/* host device */
+
+#ifdef CONFIG_COCOA
+static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
+static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );
+
+kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
+{
+ kern_return_t kernResult;
+ mach_port_t masterPort;
+ CFMutableDictionaryRef classesToMatch;
+
+ kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
+ if ( KERN_SUCCESS != kernResult ) {
+ printf( "IOMasterPort returned %d\n", kernResult );
+ }
+
+ classesToMatch = IOServiceMatching( kIOCDMediaClass );
+ if ( classesToMatch == NULL ) {
+ printf( "IOServiceMatching returned a NULL dictionary.\n" );
+ } else {
+ CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
+ }
+ kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );
+ if ( KERN_SUCCESS != kernResult )
+ {
+ printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
+ }
+
+ return kernResult;
+}
+
+kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize )
+{
+ io_object_t nextMedia;
+ kern_return_t kernResult = KERN_FAILURE;
+ *bsdPath = '\0';
+ nextMedia = IOIteratorNext( mediaIterator );
+ if ( nextMedia )
+ {
+ CFTypeRef bsdPathAsCFString;
+ bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 );
+ if ( bsdPathAsCFString ) {
+ size_t devPathLength;
+ strcpy( bsdPath, _PATH_DEV );
+ strcat( bsdPath, "r" );
+ devPathLength = strlen( bsdPath );
+ if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {
+ kernResult = KERN_SUCCESS;
+ }
+ CFRelease( bsdPathAsCFString );
+ }
+ IOObjectRelease( nextMedia );
+ }
+
+ return kernResult;
+}
+
+#endif
+
+static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
+{
+ BDRVRawState *s = bs->opaque;
+ int fd, open_flags, ret;
+
+#ifdef CONFIG_COCOA
+ if (strstart(filename, "/dev/cdrom", NULL)) {
+ kern_return_t kernResult;
+ io_iterator_t mediaIterator;
+ char bsdPath[ MAXPATHLEN ];
+ int fd;
+
+ kernResult = FindEjectableCDMedia( &mediaIterator );
+ kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
+
+ if ( bsdPath[ 0 ] != '\0' ) {
+ strcat(bsdPath,"s0");
+ /* some CDs don't have a partition 0 */
+ fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
+ if (fd < 0) {
+ bsdPath[strlen(bsdPath)-1] = '1';
+ } else {
+ close(fd);
+ }
+ filename = bsdPath;
+ }
+
+ if ( mediaIterator )
+ IOObjectRelease( mediaIterator );
+ }
+#endif
+ open_flags = O_BINARY;
+ if ((flags & BDRV_O_ACCESS) == O_RDWR) {
+ open_flags |= O_RDWR;
+ } else {
+ open_flags |= O_RDONLY;
+ bs->read_only = 1;
+ }
+
+ s->type = FTYPE_FILE;
+#if defined(__linux__)
+ if (strstart(filename, "/dev/cd", NULL)) {
+ /* open will not fail even if no CD is inserted */
+ open_flags |= O_NONBLOCK;
+ s->type = FTYPE_CD;
+ } else if (strstart(filename, "/dev/fd", NULL)) {
+ s->type = FTYPE_FD;
+ s->fd_open_flags = open_flags;
+ /* open will not fail even if no floppy is inserted */
+ open_flags |= O_NONBLOCK;
+ }
+#endif
+ fd = open(filename, open_flags, 0644);
+ if (fd < 0) {
+ ret = -errno;
+ if (ret == -EROFS)
+ ret = -EACCES;
+ return ret;
+ }
+ s->fd = fd;
+#if defined(__linux__)
+ /* close fd so that we can reopen it as needed */
+ if (s->type == FTYPE_FD) {
+ close(s->fd);
+ s->fd = -1;
+ s->fd_media_changed = 1;
+ }
+#endif
+ return 0;
+}
+
+#if defined(__linux__) && !defined(QEMU_TOOL)
+
+/* Note: we do not have a reliable method to detect if the floppy is
+ present. The current method is to try to open the floppy at every
+ I/O and to keep it opened during a few hundreds of ms. */
+static int fd_open(BlockDriverState *bs)
+{
+ BDRVRawState *s = bs->opaque;
+ int last_media_present;
+
+ if (s->type != FTYPE_FD)
+ return 0;
+ last_media_present = (s->fd >= 0);
+ if (s->fd >= 0 &&
+ (qemu_get_clock(rt_clock) - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
+ close(s->fd);
+ s->fd = -1;
+#ifdef DEBUG_FLOPPY
+ printf("Floppy closed\n");
+#endif
+ }
+ if (s->fd < 0) {
+ if (s->fd_got_error &&
+ (qemu_get_clock(rt_clock) - s->fd_error_time) < FD_OPEN_TIMEOUT) {
+#ifdef DEBUG_FLOPPY
+ printf("No floppy (open delayed)\n");
+#endif
+ return -EIO;
+ }
+ s->fd = open(bs->filename, s->fd_open_flags);
+ if (s->fd < 0) {
+ s->fd_error_time = qemu_get_clock(rt_clock);
+ s->fd_got_error = 1;
+ if (last_media_present)
+ s->fd_media_changed = 1;
+#ifdef DEBUG_FLOPPY
+ printf("No floppy\n");
+#endif
+ return -EIO;
+ }
+#ifdef DEBUG_FLOPPY
+ printf("Floppy opened\n");
+#endif
+ }
+ if (!last_media_present)
+ s->fd_media_changed = 1;
+ s->fd_open_time = qemu_get_clock(rt_clock);
+ s->fd_got_error = 0;
+ return 0;
+}
+#else
+static int fd_open(BlockDriverState *bs)
+{
+ return 0;
+}
+#endif
+
+#if defined(__linux__)
+
+static int raw_is_inserted(BlockDriverState *bs)
+{
+ BDRVRawState *s = bs->opaque;
+ int ret;
+
+ switch(s->type) {
+ case FTYPE_CD:
+ ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
+ if (ret == CDS_DISC_OK)
+ return 1;
+ else
+ return 0;
+ break;
+ case FTYPE_FD:
+ ret = fd_open(bs);
+ return (ret >= 0);
+ default:
+ return 1;
+ }
+}
+
+/* currently only used by fdc.c, but a CD version would be good too */
+static int raw_media_changed(BlockDriverState *bs)
+{
+ BDRVRawState *s = bs->opaque;
+
+ switch(s->type) {
+ case FTYPE_FD:
+ {
+ int ret;
+ /* XXX: we do not have a true media changed indication. It
+ does not work if the floppy is changed without trying
+ to read it */
+ fd_open(bs);
+ ret = s->fd_media_changed;
+ s->fd_media_changed = 0;
+#ifdef DEBUG_FLOPPY
+ printf("Floppy changed=%d\n", ret);
+#endif
+ return ret;
+ }
+ default:
+ return -ENOTSUP;
+ }
+}
+
+static int raw_eject(BlockDriverState *bs, int eject_flag)
+{
+ BDRVRawState *s = bs->opaque;
+
+ switch(s->type) {
+ case FTYPE_CD:
+ if (eject_flag) {
+ if (ioctl (s->fd, CDROMEJECT, NULL) < 0)
+ perror("CDROMEJECT");
+ } else {
+ if (ioctl (s->fd, CDROMCLOSETRAY, NULL) < 0)
+ perror("CDROMEJECT");
+ }
+ break;
+ case FTYPE_FD:
+ {
+ int fd;
+ if (s->fd >= 0) {
+ close(s->fd);
+ s->fd = -1;
+ }
+ fd = open(bs->filename, s->fd_open_flags | O_NONBLOCK);
+ if (fd >= 0) {
+ if (ioctl(fd, FDEJECT, 0) < 0)
+ perror("FDEJECT");
+ close(fd);
+ }
+ }
+ break;
+ default:
+ return -ENOTSUP;
+ }
+ return 0;
+}
+
+static int raw_set_locked(BlockDriverState *bs, int locked)
+{
+ BDRVRawState *s = bs->opaque;
+
+ switch(s->type) {
+ case FTYPE_CD:
+ if (ioctl (s->fd, CDROM_LOCKDOOR, locked) < 0) {
+ /* Note: an error can happen if the distribution automatically
+ mounts the CD-ROM */
+ // perror("CDROM_LOCKDOOR");
+ }
+ break;
+ default:
+ return -ENOTSUP;
+ }
+ return 0;
+}
+
+#else
+
+static int raw_is_inserted(BlockDriverState *bs)
+{
+ return 1;
+}
+
+static int raw_media_changed(BlockDriverState *bs)
+{
+ return -ENOTSUP;
+}
+
+static int raw_eject(BlockDriverState *bs, int eject_flag)
+{
+ return -ENOTSUP;
+}
+
+static int raw_set_locked(BlockDriverState *bs, int locked)
+{
+ return -ENOTSUP;
+}
+
+#endif /* !linux */
+
+BlockDriver bdrv_host_device = {
+ "host_device",
+ sizeof(BDRVRawState),
+ NULL, /* no probe for protocols */
+ hdev_open,
+ NULL,
+ NULL,
+ raw_close,
+ NULL,
+ raw_flush,
+
+ .bdrv_aio_read = raw_aio_read,
+ .bdrv_aio_write = raw_aio_write,
+ .bdrv_aio_cancel = raw_aio_cancel,
+ .aiocb_size = sizeof(RawAIOCB),
+ .bdrv_pread = raw_pread,
+ .bdrv_pwrite = raw_pwrite,
+ .bdrv_getlength = raw_getlength,
+
+ /* removable device support */
+ .bdrv_is_inserted = raw_is_inserted,
+ .bdrv_media_changed = raw_media_changed,
+ .bdrv_eject = raw_eject,
+ .bdrv_set_locked = raw_set_locked,
+};
+
+#else /* _WIN32 */
+
+/* XXX: use another file ? */
+#include <winioctl.h>
+
+#define FTYPE_FILE 0
+#define FTYPE_CD 1
+#define FTYPE_HARDDISK 2
+
+typedef struct BDRVRawState {
+ HANDLE hfile;
+ int type;
+ char drive_path[16]; /* format: "d:\" */
+} BDRVRawState;
+
+typedef struct RawAIOCB {
+ BlockDriverAIOCB common;
+ HANDLE hEvent;
+ OVERLAPPED ov;
+ int count;
+} RawAIOCB;
+
+int qemu_ftruncate64(int fd, int64_t length)
+{
+ LARGE_INTEGER li;
+ LONG high;
+ HANDLE h;
+ BOOL res;
+
+ if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
+ return -1;
+
+ h = (HANDLE)_get_osfhandle(fd);
+
+ /* get current position, ftruncate do not change position */
+ li.HighPart = 0;
+ li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
+ if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
+ return -1;
+
+ high = length >> 32;
+ if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
+ return -1;
+ res = SetEndOfFile(h);
+
+ /* back to old position */
+ SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
+ return res ? 0 : -1;
+}
+
+static int set_sparse(int fd)
+{
+ DWORD returned;
+ return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
+ NULL, 0, NULL, 0, &returned, NULL);
+}
+
+static int raw_open(BlockDriverState *bs, const char *filename, int flags)
+{
+ BDRVRawState *s = bs->opaque;
+ int access_flags, create_flags;
+ DWORD overlapped;
+
+ s->type = FTYPE_FILE;
+
+ if ((flags & BDRV_O_ACCESS) == O_RDWR) {
+ access_flags = GENERIC_READ | GENERIC_WRITE;
+ } else {
+ access_flags = GENERIC_READ;
+ }
+ if (flags & BDRV_O_CREAT) {
+ create_flags = CREATE_ALWAYS;
+ } else {
+ create_flags = OPEN_EXISTING;
+ }
+#ifdef QEMU_TOOL
+ overlapped = FILE_ATTRIBUTE_NORMAL;
+#else
+ overlapped = FILE_FLAG_OVERLAPPED;
+#endif
+ s->hfile = CreateFile(filename, access_flags,
+ FILE_SHARE_READ, NULL,
+ create_flags, overlapped, NULL);
+ if (s->hfile == INVALID_HANDLE_VALUE)
+ return -1;
+ return 0;
+}
+
+static int raw_pread(BlockDriverState *bs, int64_t offset,
+ uint8_t *buf, int count)
+{
+ BDRVRawState *s = bs->opaque;
+ OVERLAPPED ov;
+ DWORD ret_count;
+ int ret;
+
+ memset(&ov, 0, sizeof(ov));
+ ov.Offset = offset;
+ ov.OffsetHigh = offset >> 32;
+ ret = ReadFile(s->hfile, buf, count, &ret_count, &ov);
+ if (!ret) {
+ ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
+ if (!ret)
+ return -EIO;
+ else
+ return ret_count;
+ }
+ return ret_count;
+}
+
+static int raw_pwrite(BlockDriverState *bs, int64_t offset,
+ const uint8_t *buf, int count)
+{
+ BDRVRawState *s = bs->opaque;
+ OVERLAPPED ov;
+ DWORD ret_count;
+ int ret;
+
+ memset(&ov, 0, sizeof(ov));
+ ov.Offset = offset;
+ ov.OffsetHigh = offset >> 32;
+ ret = WriteFile(s->hfile, buf, count, &ret_count, &ov);
+ if (!ret) {
+ ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
+ if (!ret)
+ return -EIO;
+ else
+ return ret_count;
+ }
+ return ret_count;
+}
+
+#if 0
+#ifndef QEMU_TOOL
+static void raw_aio_cb(void *opaque)
+{
+ RawAIOCB *acb = opaque;
+ BlockDriverState *bs = acb->common.bs;
+ BDRVRawState *s = bs->opaque;
+ DWORD ret_count;
+ int ret;
+
+ ret = GetOverlappedResult(s->hfile, &acb->ov, &ret_count, TRUE);
+ if (!ret || ret_count != acb->count) {
+ acb->common.cb(acb->common.opaque, -EIO);
+ } else {
+ acb->common.cb(acb->common.opaque, 0);
+ }
+}
+#endif
+
+static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
+ int64_t sector_num, uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ RawAIOCB *acb;
+ int64_t offset;
+
+ acb = qemu_aio_get(bs, cb, opaque);
+ if (acb->hEvent) {
+ acb->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (!acb->hEvent) {
+ qemu_aio_release(acb);
+ return NULL;
+ }
+ }
+ memset(&acb->ov, 0, sizeof(acb->ov));
+ offset = sector_num * 512;
+ acb->ov.Offset = offset;
+ acb->ov.OffsetHigh = offset >> 32;
+ acb->ov.hEvent = acb->hEvent;
+ acb->count = nb_sectors * 512;
+#ifndef QEMU_TOOL
+ qemu_add_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
+#endif
+ return acb;
+}
+
+static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
+ int64_t sector_num, uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ BDRVRawState *s = bs->opaque;
+ RawAIOCB *acb;
+ int ret;
+
+ acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
+ if (!acb)
+ return NULL;
+ ret = ReadFile(s->hfile, buf, acb->count, NULL, &acb->ov);
+ if (!ret) {
+ qemu_aio_release(acb);
+ return NULL;
+ }
+#ifdef QEMU_TOOL
+ qemu_aio_release(acb);
+#endif
+ return (BlockDriverAIOCB *)acb;
+}
+
+static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
+ int64_t sector_num, uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ BDRVRawState *s = bs->opaque;
+ RawAIOCB *acb;
+ int ret;
+
+ acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
+ if (!acb)
+ return NULL;
+ ret = WriteFile(s->hfile, buf, acb->count, NULL, &acb->ov);
+ if (!ret) {
+ qemu_aio_release(acb);
+ return NULL;
+ }
+#ifdef QEMU_TOOL
+ qemu_aio_release(acb);
+#endif
+ return (BlockDriverAIOCB *)acb;
+}
+
+static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+#ifndef QEMU_TOOL
+ RawAIOCB *acb = (RawAIOCB *)blockacb;
+ BlockDriverState *bs = acb->common.bs;
+ BDRVRawState *s = bs->opaque;
+
+ qemu_del_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
+ /* XXX: if more than one async I/O it is not correct */
+ CancelIo(s->hfile);
+ qemu_aio_release(acb);
+#endif
+}
+#endif /* #if 0 */
+
+static void raw_flush(BlockDriverState *bs)
+{
+ BDRVRawState *s = bs->opaque;
+ FlushFileBuffers(s->hfile);
+}
+
+static void raw_close(BlockDriverState *bs)
+{
+ BDRVRawState *s = bs->opaque;
+ CloseHandle(s->hfile);
+}
+
+static int raw_truncate(BlockDriverState *bs, int64_t offset)
+{
+ BDRVRawState *s = bs->opaque;
+ DWORD low, high;
+
+ low = offset;
+ high = offset >> 32;
+ if (!SetFilePointer(s->hfile, low, &high, FILE_BEGIN))
+ return -EIO;
+ if (!SetEndOfFile(s->hfile))
+ return -EIO;
+ return 0;
+}
+
+static int64_t raw_getlength(BlockDriverState *bs)
+{
+ BDRVRawState *s = bs->opaque;
+ LARGE_INTEGER l;
+ ULARGE_INTEGER available, total, total_free;
+ DISK_GEOMETRY dg;
+ DWORD count;
+ BOOL status;
+
+ switch(s->type) {
+ case FTYPE_FILE:
+ l.LowPart = GetFileSize(s->hfile, &l.HighPart);
+ if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
+ return -EIO;
+ break;
+ case FTYPE_CD:
+ if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free))
+ return -EIO;
+ l.QuadPart = total.QuadPart;
+ break;
+ case FTYPE_HARDDISK:
+ status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY,
+ NULL, 0, &dg, sizeof(dg), &count, NULL);
+ if (status != FALSE) {
+ l.QuadPart = dg.Cylinders.QuadPart * dg.TracksPerCylinder
+ * dg.SectorsPerTrack * dg.BytesPerSector;
+ }
+ break;
+ default:
+ return -EIO;
+ }
+ return l.QuadPart;
+}
+
+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,
+ 0644);
+ if (fd < 0)
+ return -EIO;
+ set_sparse(fd);
+ ftruncate(fd, total_size * 512);
+ close(fd);
+ return 0;
+}
+
+void qemu_aio_init(void)
+{
+}
+
+void qemu_aio_poll(void)
+{
+}
+
+void qemu_aio_flush(void)
+{
+}
+
+void qemu_aio_wait_start(void)
+{
+}
+
+void qemu_aio_wait(void)
+{
+#ifndef QEMU_TOOL
+ qemu_bh_poll();
+#endif
+}
+
+void qemu_aio_wait_end(void)
+{
+}
+
+BlockDriver bdrv_raw = {
+ "raw",
+ sizeof(BDRVRawState),
+ NULL, /* no probe for protocols */
+ raw_open,
+ NULL,
+ NULL,
+ raw_close,
+ raw_create,
+ raw_flush,
+
+#if 0
+ .bdrv_aio_read = raw_aio_read,
+ .bdrv_aio_write = raw_aio_write,
+ .bdrv_aio_cancel = raw_aio_cancel,
+ .aiocb_size = sizeof(RawAIOCB);
+#endif
+ .protocol_name = "file",
+ .bdrv_pread = raw_pread,
+ .bdrv_pwrite = raw_pwrite,
+ .bdrv_truncate = raw_truncate,
+ .bdrv_getlength = raw_getlength,
+};
+
+/***********************************************/
+/* host device */
+
+static int find_cdrom(char *cdrom_name, int cdrom_name_size)
+{
+ char drives[256], *pdrv = drives;
+ UINT type;
+
+ memset(drives, 0, sizeof(drives));
+ GetLogicalDriveStrings(sizeof(drives), drives);
+ while(pdrv[0] != '\0') {
+ type = GetDriveType(pdrv);
+ switch(type) {
+ case DRIVE_CDROM:
+ snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]);
+ return 0;
+ break;
+ }
+ pdrv += lstrlen(pdrv) + 1;
+ }
+ return -1;
+}
+
+static int find_device_type(BlockDriverState *bs, const char *filename)
+{
+ BDRVRawState *s = bs->opaque;
+ UINT type;
+ const char *p;
+
+ if (strstart(filename, "\\\\.\\", &p) ||
+ strstart(filename, "//./", &p)) {
+ if (stristart(p, "PhysicalDrive", NULL))
+ return FTYPE_HARDDISK;
+ snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]);
+ type = GetDriveType(s->drive_path);
+ if (type == DRIVE_CDROM)
+ return FTYPE_CD;
+ else
+ return FTYPE_FILE;
+ } else {
+ return FTYPE_FILE;
+ }
+}
+
+static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
+{
+ BDRVRawState *s = bs->opaque;
+ int access_flags, create_flags;
+ DWORD overlapped;
+ char device_name[64];
+
+ if (strstart(filename, "/dev/cdrom", NULL)) {
+ if (find_cdrom(device_name, sizeof(device_name)) < 0)
+ return -ENOENT;
+ filename = device_name;
+ } else {
+ /* transform drive letters into device name */
+ if (((filename[0] >= 'a' && filename[0] <= 'z') ||
+ (filename[0] >= 'A' && filename[0] <= 'Z')) &&
+ filename[1] == ':' && filename[2] == '\0') {
+ snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]);
+ filename = device_name;
+ }
+ }
+ s->type = find_device_type(bs, filename);
+
+ if ((flags & BDRV_O_ACCESS) == O_RDWR) {
+ access_flags = GENERIC_READ | GENERIC_WRITE;
+ } else {
+ access_flags = GENERIC_READ;
+ }
+ create_flags = OPEN_EXISTING;
+
+#ifdef QEMU_TOOL
+ overlapped = FILE_ATTRIBUTE_NORMAL;
+#else
+ overlapped = FILE_FLAG_OVERLAPPED;
+#endif
+ s->hfile = CreateFile(filename, access_flags,
+ FILE_SHARE_READ, NULL,
+ create_flags, overlapped, NULL);
+ if (s->hfile == INVALID_HANDLE_VALUE)
+ return -1;
+ return 0;
+}
+
+#if 0
+/***********************************************/
+/* removable device additionnal commands */
+
+static int raw_is_inserted(BlockDriverState *bs)
+{
+ return 1;
+}
+
+static int raw_media_changed(BlockDriverState *bs)
+{
+ return -ENOTSUP;
+}
+
+static int raw_eject(BlockDriverState *bs, int eject_flag)
+{
+ DWORD ret_count;
+
+ if (s->type == FTYPE_FILE)
+ return -ENOTSUP;
+ if (eject_flag) {
+ DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA,
+ NULL, 0, NULL, 0, &lpBytesReturned, NULL);
+ } else {
+ DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA,
+ NULL, 0, NULL, 0, &lpBytesReturned, NULL);
+ }
+}
+
+static int raw_set_locked(BlockDriverState *bs, int locked)
+{
+ return -ENOTSUP;
+}
+#endif
+
+BlockDriver bdrv_host_device = {
+ "host_device",
+ sizeof(BDRVRawState),
+ NULL, /* no probe for protocols */
+ hdev_open,
+ NULL,
+ NULL,
+ raw_close,
+ NULL,
+ raw_flush,
+
+#if 0
+ .bdrv_aio_read = raw_aio_read,
+ .bdrv_aio_write = raw_aio_write,
+ .bdrv_aio_cancel = raw_aio_cancel,
+ .aiocb_size = sizeof(RawAIOCB);
+#endif
+ .bdrv_pread = raw_pread,
+ .bdrv_pwrite = raw_pwrite,
+ .bdrv_getlength = raw_getlength,
+};
+#endif /* _WIN32 */
Added: trunk/src/host/qemu-neo1973/block-vmdk.c
===================================================================
--- trunk/src/host/qemu-neo1973/block-vmdk.c 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/block-vmdk.c 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,446 @@
+/*
+ * 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, int flags)
+{
+ 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 = le64_to_cpu(header.capacity);
+ s->cluster_sectors = le64_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);
+}
+
+static void vmdk_flush(BlockDriverState *bs)
+{
+ BDRVVmdkState *s = bs->opaque;
+ fsync(s->fd);
+}
+
+BlockDriver bdrv_vmdk = {
+ "vmdk",
+ sizeof(BDRVVmdkState),
+ vmdk_probe,
+ vmdk_open,
+ vmdk_read,
+ vmdk_write,
+ vmdk_close,
+ vmdk_create,
+ vmdk_flush,
+ vmdk_is_allocated,
+};
Added: trunk/src/host/qemu-neo1973/block-vpc.c
===================================================================
--- trunk/src/host/qemu-neo1973/block-vpc.c 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/block-vpc.c 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,239 @@
+/*
+ * 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, int flags)
+{
+ BDRVVPCState *s = bs->opaque;
+ int fd, i;
+ struct vpc_subheader header;
+
+ fd = open(filename, O_RDONLY | O_BINARY);
+ 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: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\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,
+};
Added: trunk/src/host/qemu-neo1973/block-vvfat.c
===================================================================
--- trunk/src/host/qemu-neo1973/block-vvfat.c 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/block-vvfat.c 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,2804 @@
+/* vim:set shiftwidth=4 ts=8: */
+/*
+ * QEMU Block driver for virtual VFAT (shadows a local directory)
+ *
+ * Copyright (c) 2004,2005 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 <sys/stat.h>
+#include <dirent.h>
+#include <assert.h>
+#include "vl.h"
+#include "block_int.h"
+
+#ifndef S_IWGRP
+#define S_IWGRP 0
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH 0
+#endif
+
+/* TODO: add ":bootsector=blabla.img:" */
+/* LATER TODO: add automatic boot sector generation from
+ BOOTEASY.ASM and Ranish Partition Manager
+ Note that DOS assumes the system files to be the first files in the
+ file system (test if the boot sector still relies on that fact)! */
+/* MAYBE TODO: write block-visofs.c */
+/* TODO: call try_commit() only after a timeout */
+
+/* #define DEBUG */
+
+#ifdef DEBUG
+
+#define DLOG(a) a
+
+#undef stderr
+#define stderr STDERR
+FILE* stderr = NULL;
+
+static void checkpoint();
+
+#ifdef __MINGW32__
+void nonono(const char* file, int line, const char* msg) {
+ fprintf(stderr, "Nonono! %s:%d %s\n", file, line, msg);
+ exit(-5);
+}
+#undef assert
+#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
+#endif
+
+#else
+
+#define DLOG(a)
+
+#endif
+
+/* dynamic array functions */
+typedef struct array_t {
+ char* pointer;
+ unsigned int size,next,item_size;
+} array_t;
+
+static inline void array_init(array_t* array,unsigned int item_size)
+{
+ array->pointer=0;
+ array->size=0;
+ array->next=0;
+ array->item_size=item_size;
+}
+
+static inline void array_free(array_t* array)
+{
+ if(array->pointer)
+ free(array->pointer);
+ array->size=array->next=0;
+}
+
+/* does not automatically grow */
+static inline void* array_get(array_t* array,unsigned int index) {
+ assert(index >= 0);
+ assert(index < array->next);
+ return array->pointer + index * array->item_size;
+}
+
+static inline int array_ensure_allocated(array_t* array, int index)
+{
+ if((index + 1) * array->item_size > array->size) {
+ int new_size = (index + 32) * array->item_size;
+ array->pointer = realloc(array->pointer, new_size);
+ if (!array->pointer)
+ return -1;
+ array->size = new_size;
+ array->next = index + 1;
+ }
+
+ return 0;
+}
+
+static inline void* array_get_next(array_t* array) {
+ unsigned int next = array->next;
+ void* result;
+
+ if (array_ensure_allocated(array, next) < 0)
+ return NULL;
+
+ array->next = next + 1;
+ result = array_get(array, next);
+
+ return result;
+}
+
+static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
+ if((array->next+count)*array->item_size>array->size) {
+ int increment=count*array->item_size;
+ array->pointer=realloc(array->pointer,array->size+increment);
+ if(!array->pointer)
+ return 0;
+ array->size+=increment;
+ }
+ memmove(array->pointer+(index+count)*array->item_size,
+ array->pointer+index*array->item_size,
+ (array->next-index)*array->item_size);
+ array->next+=count;
+ return array->pointer+index*array->item_size;
+}
+
+/* this performs a "roll", so that the element which was at index_from becomes
+ * index_to, but the order of all other elements is preserved. */
+static inline int array_roll(array_t* array,int index_to,int index_from,int count)
+{
+ char* buf;
+ char* from;
+ char* to;
+ int is;
+
+ if(!array ||
+ index_to<0 || index_to>=array->next ||
+ index_from<0 || index_from>=array->next)
+ return -1;
+
+ if(index_to==index_from)
+ return 0;
+
+ is=array->item_size;
+ from=array->pointer+index_from*is;
+ to=array->pointer+index_to*is;
+ buf=malloc(is*count);
+ memcpy(buf,from,is*count);
+
+ if(index_to<index_from)
+ memmove(to+is*count,to,from-to);
+ else
+ memmove(from,from+is*count,to-from);
+
+ memcpy(to,buf,is*count);
+
+ free(buf);
+
+ return 0;
+}
+
+inline int array_remove_slice(array_t* array,int index, int count)
+{
+ assert(index >=0);
+ assert(count > 0);
+ assert(index + count <= array->next);
+ if(array_roll(array,array->next-1,index,count))
+ return -1;
+ array->next -= count;
+ return 0;
+}
+
+int array_remove(array_t* array,int index)
+{
+ return array_remove_slice(array, index, 1);
+}
+
+/* return the index for a given member */
+int array_index(array_t* array, void* pointer)
+{
+ size_t offset = (char*)pointer - array->pointer;
+ assert(offset >= 0);
+ assert((offset % array->item_size) == 0);
+ assert(offset/array->item_size < array->next);
+ return offset/array->item_size;
+}
+
+/* These structures are used to fake a disk and the VFAT filesystem.
+ * For this reason we need to use __attribute__((packed)). */
+
+typedef struct bootsector_t {
+ uint8_t jump[3];
+ uint8_t name[8];
+ uint16_t sector_size;
+ uint8_t sectors_per_cluster;
+ uint16_t reserved_sectors;
+ uint8_t number_of_fats;
+ uint16_t root_entries;
+ uint16_t total_sectors16;
+ uint8_t media_type;
+ uint16_t sectors_per_fat;
+ uint16_t sectors_per_track;
+ uint16_t number_of_heads;
+ uint32_t hidden_sectors;
+ uint32_t total_sectors;
+ union {
+ struct {
+ uint8_t drive_number;
+ uint8_t current_head;
+ uint8_t signature;
+ uint32_t id;
+ uint8_t volume_label[11];
+ } __attribute__((packed)) fat16;
+ struct {
+ uint32_t sectors_per_fat;
+ uint16_t flags;
+ uint8_t major,minor;
+ uint32_t first_cluster_of_root_directory;
+ uint16_t info_sector;
+ uint16_t backup_boot_sector;
+ uint16_t ignored;
+ } __attribute__((packed)) fat32;
+ } u;
+ uint8_t fat_type[8];
+ uint8_t ignored[0x1c0];
+ uint8_t magic[2];
+} __attribute__((packed)) bootsector_t;
+
+typedef struct partition_t {
+ uint8_t attributes; /* 0x80 = bootable */
+ uint8_t start_head;
+ uint8_t start_sector;
+ uint8_t start_cylinder;
+ uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xb = FAT32 */
+ uint8_t end_head;
+ uint8_t end_sector;
+ uint8_t end_cylinder;
+ uint32_t start_sector_long;
+ uint32_t end_sector_long;
+} __attribute__((packed)) partition_t;
+
+typedef struct mbr_t {
+ uint8_t ignored[0x1be];
+ partition_t partition[4];
+ uint8_t magic[2];
+} __attribute__((packed)) mbr_t;
+
+typedef struct direntry_t {
+ uint8_t name[8];
+ uint8_t extension[3];
+ uint8_t attributes;
+ uint8_t reserved[2];
+ uint16_t ctime;
+ uint16_t cdate;
+ uint16_t adate;
+ uint16_t begin_hi;
+ uint16_t mtime;
+ uint16_t mdate;
+ uint16_t begin;
+ uint32_t size;
+} __attribute__((packed)) direntry_t;
+
+/* this structure are used to transparently access the files */
+
+typedef struct mapping_t {
+ /* begin is the first cluster, end is the last+1 */
+ uint32_t begin,end;
+ /* as s->directory is growable, no pointer may be used here */
+ unsigned int dir_index;
+ /* the clusters of a file may be in any order; this points to the first */
+ int first_mapping_index;
+ union {
+ /* offset is
+ * - the offset in the file (in clusters) for a file, or
+ * - the next cluster of the directory for a directory, and
+ * - the address of the buffer for a faked entry
+ */
+ struct {
+ uint32_t offset;
+ } file;
+ struct {
+ int parent_mapping_index;
+ int first_dir_index;
+ } dir;
+ } info;
+ /* path contains the full path, i.e. it always starts with s->path */
+ char* path;
+
+ enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2,
+ MODE_DIRECTORY = 4, MODE_FAKED = 8,
+ MODE_DELETED = 16, MODE_RENAMED = 32 } mode;
+ int read_only;
+} mapping_t;
+
+#ifdef DEBUG
+static void print_direntry(const struct direntry_t*);
+static void print_mapping(const struct mapping_t* mapping);
+#endif
+
+/* here begins the real VVFAT driver */
+
+typedef struct BDRVVVFATState {
+ BlockDriverState* bs; /* pointer to parent */
+ unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
+ unsigned char first_sectors[0x40*0x200];
+
+ int fat_type; /* 16 or 32 */
+ array_t fat,directory,mapping;
+
+ unsigned int cluster_size;
+ unsigned int sectors_per_cluster;
+ unsigned int sectors_per_fat;
+ unsigned int sectors_of_root_directory;
+ uint32_t last_cluster_of_root_directory;
+ unsigned int faked_sectors; /* how many sectors are faked before file data */
+ uint32_t sector_count; /* total number of sectors of the partition */
+ uint32_t cluster_count; /* total number of clusters of this partition */
+ uint32_t max_fat_value;
+
+ int current_fd;
+ mapping_t* current_mapping;
+ unsigned char* cluster; /* points to current cluster */
+ unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
+ unsigned int current_cluster;
+
+ /* write support */
+ BlockDriverState* write_target;
+ char* qcow_filename;
+ BlockDriverState* qcow;
+ void* fat2;
+ char* used_clusters;
+ array_t commits;
+ const char* path;
+ int downcase_short_names;
+} BDRVVVFATState;
+
+
+static void init_mbr(BDRVVVFATState* s)
+{
+ /* TODO: if the files mbr.img and bootsect.img exist, use them */
+ mbr_t* real_mbr=(mbr_t*)s->first_sectors;
+ partition_t* partition=&(real_mbr->partition[0]);
+
+ memset(s->first_sectors,0,512);
+
+ partition->attributes=0x80; /* bootable */
+ partition->start_head=1;
+ partition->start_sector=1;
+ partition->start_cylinder=0;
+ /* FAT12/FAT16/FAT32 */
+ partition->fs_type=(s->fat_type==12?0x1:s->fat_type==16?0x6:0xb);
+ partition->end_head=s->bs->heads-1;
+ partition->end_sector=0xff; /* end sector & upper 2 bits of cylinder */;
+ partition->end_cylinder=0xff; /* lower 8 bits of end cylinder */;
+ partition->start_sector_long=cpu_to_le32(s->bs->secs);
+ partition->end_sector_long=cpu_to_le32(s->sector_count);
+
+ real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
+}
+
+/* direntry functions */
+
+/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
+static inline int short2long_name(unsigned char* dest,const char* src)
+{
+ int i;
+ for(i=0;i<129 && src[i];i++) {
+ dest[2*i]=src[i];
+ dest[2*i+1]=0;
+ }
+ dest[2*i]=dest[2*i+1]=0;
+ for(i=2*i+2;(i%26);i++)
+ dest[i]=0xff;
+ return i;
+}
+
+static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
+{
+ char buffer[258];
+ int length=short2long_name(buffer,filename),
+ number_of_entries=(length+25)/26,i;
+ direntry_t* entry;
+
+ for(i=0;i<number_of_entries;i++) {
+ entry=array_get_next(&(s->directory));
+ entry->attributes=0xf;
+ entry->reserved[0]=0;
+ entry->begin=0;
+ entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
+ }
+ for(i=0;i<length;i++) {
+ int offset=(i%26);
+ if(offset<10) offset=1+offset;
+ else if(offset<22) offset=14+offset-10;
+ else offset=28+offset-22;
+ entry=array_get(&(s->directory),s->directory.next-1-(i/26));
+ entry->name[offset]=buffer[i];
+ }
+ return array_get(&(s->directory),s->directory.next-number_of_entries);
+}
+
+static char is_free(const direntry_t* direntry)
+{
+ /* return direntry->name[0]==0 ; */
+ return direntry->attributes == 0 || direntry->name[0]==0xe5;
+}
+
+static char is_volume_label(const direntry_t* direntry)
+{
+ return direntry->attributes == 0x28;
+}
+
+static char is_long_name(const direntry_t* direntry)
+{
+ return direntry->attributes == 0xf;
+}
+
+static char is_short_name(const direntry_t* direntry)
+{
+ return !is_volume_label(direntry) && !is_long_name(direntry)
+ && !is_free(direntry);
+}
+
+static char is_directory(const direntry_t* direntry)
+{
+ return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
+}
+
+static inline char is_dot(const direntry_t* direntry)
+{
+ return is_short_name(direntry) && direntry->name[0] == '.';
+}
+
+static char is_file(const direntry_t* direntry)
+{
+ return is_short_name(direntry) && !is_directory(direntry);
+}
+
+static inline uint32_t begin_of_direntry(const direntry_t* direntry)
+{
+ return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
+}
+
+static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
+{
+ return le32_to_cpu(direntry->size);
+}
+
+static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
+{
+ direntry->begin = cpu_to_le16(begin & 0xffff);
+ direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
+}
+
+/* fat functions */
+
+static inline uint8_t fat_chksum(const direntry_t* entry)
+{
+ uint8_t chksum=0;
+ int i;
+
+ for(i=0;i<11;i++)
+ chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0))
+ +(unsigned char)entry->name[i];
+
+ return chksum;
+}
+
+/* if return_time==0, this returns the fat_date, else the fat_time */
+static uint16_t fat_datetime(time_t time,int return_time) {
+ struct tm* t;
+#ifdef _WIN32
+ t=localtime(&time); /* this is not thread safe */
+#else
+ struct tm t1;
+ t=&t1;
+ localtime_r(&time,t);
+#endif
+ if(return_time)
+ return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
+ return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
+}
+
+static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
+{
+ if(s->fat_type==32) {
+ uint32_t* entry=array_get(&(s->fat),cluster);
+ *entry=cpu_to_le32(value);
+ } else if(s->fat_type==16) {
+ uint16_t* entry=array_get(&(s->fat),cluster);
+ *entry=cpu_to_le16(value&0xffff);
+ } else {
+ int offset = (cluster*3/2);
+ unsigned char* p = array_get(&(s->fat), offset);
+ switch (cluster&1) {
+ case 0:
+ p[0] = value&0xff;
+ p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
+ break;
+ case 1:
+ p[0] = (p[0]&0xf) | ((value&0xf)<<4);
+ p[1] = (value>>4);
+ break;
+ }
+ }
+}
+
+static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
+{
+ if(s->fat_type==32) {
+ uint32_t* entry=array_get(&(s->fat),cluster);
+ return le32_to_cpu(*entry);
+ } else if(s->fat_type==16) {
+ uint16_t* entry=array_get(&(s->fat),cluster);
+ return le16_to_cpu(*entry);
+ } else {
+ const uint8_t* x=s->fat.pointer+cluster*3/2;
+ return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
+ }
+}
+
+static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
+{
+ if(fat_entry>s->max_fat_value-8)
+ return -1;
+ return 0;
+}
+
+static inline void init_fat(BDRVVVFATState* s)
+{
+ if (s->fat_type == 12) {
+ array_init(&(s->fat),1);
+ array_ensure_allocated(&(s->fat),
+ s->sectors_per_fat * 0x200 * 3 / 2 - 1);
+ } else {
+ array_init(&(s->fat),(s->fat_type==32?4:2));
+ array_ensure_allocated(&(s->fat),
+ s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
+ }
+ memset(s->fat.pointer,0,s->fat.size);
+
+ switch(s->fat_type) {
+ case 12: s->max_fat_value=0xfff; break;
+ case 16: s->max_fat_value=0xffff; break;
+ case 32: s->max_fat_value=0x0fffffff; break;
+ default: s->max_fat_value=0; /* error... */
+ }
+
+}
+
+/* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
+/* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
+static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
+ unsigned int directory_start, const char* filename, int is_dot)
+{
+ int i,j,long_index=s->directory.next;
+ direntry_t* entry=0;
+ direntry_t* entry_long=0;
+
+ if(is_dot) {
+ entry=array_get_next(&(s->directory));
+ memset(entry->name,0x20,11);
+ memcpy(entry->name,filename,strlen(filename));
+ return entry;
+ }
+
+ entry_long=create_long_filename(s,filename);
+
+ i = strlen(filename);
+ for(j = i - 1; j>0 && filename[j]!='.';j--);
+ if (j > 0)
+ i = (j > 8 ? 8 : j);
+ else if (i > 8)
+ i = 8;
+
+ entry=array_get_next(&(s->directory));
+ memset(entry->name,0x20,11);
+ strncpy(entry->name,filename,i);
+
+ if(j > 0)
+ for (i = 0; i < 3 && filename[j+1+i]; i++)
+ entry->extension[i] = filename[j+1+i];
+
+ /* upcase & remove unwanted characters */
+ for(i=10;i>=0;i--) {
+ if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
+ if(entry->name[i]<=' ' || entry->name[i]>0x7f
+ || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
+ entry->name[i]='_';
+ else if(entry->name[i]>='a' && entry->name[i]<='z')
+ entry->name[i]+='A'-'a';
+ }
+
+ /* mangle duplicates */
+ while(1) {
+ direntry_t* entry1=array_get(&(s->directory),directory_start);
+ int j;
+
+ for(;entry1<entry;entry1++)
+ if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
+ break; /* found dupe */
+ if(entry1==entry) /* no dupe found */
+ break;
+
+ /* use all 8 characters of name */
+ if(entry->name[7]==' ') {
+ int j;
+ for(j=6;j>0 && entry->name[j]==' ';j--)
+ entry->name[j]='~';
+ }
+
+ /* increment number */
+ for(j=7;j>0 && entry->name[j]=='9';j--)
+ entry->name[j]='0';
+ if(j>0) {
+ if(entry->name[j]<'0' || entry->name[j]>'9')
+ entry->name[j]='0';
+ else
+ entry->name[j]++;
+ }
+ }
+
+ /* calculate checksum; propagate to long name */
+ if(entry_long) {
+ uint8_t chksum=fat_chksum(entry);
+
+ /* calculate anew, because realloc could have taken place */
+ entry_long=array_get(&(s->directory),long_index);
+ while(entry_long<entry && is_long_name(entry_long)) {
+ entry_long->reserved[1]=chksum;
+ entry_long++;
+ }
+ }
+
+ return entry;
+}
+
+/*
+ * Read a directory. (the index of the corresponding mapping must be passed).
+ */
+static int read_directory(BDRVVVFATState* s, int mapping_index)
+{
+ mapping_t* mapping = array_get(&(s->mapping), mapping_index);
+ direntry_t* direntry;
+ const char* dirname = mapping->path;
+ int first_cluster = mapping->begin;
+ int parent_index = mapping->info.dir.parent_mapping_index;
+ mapping_t* parent_mapping = (mapping_t*)
+ (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : 0);
+ int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
+
+ DIR* dir=opendir(dirname);
+ struct dirent* entry;
+ int i;
+
+ assert(mapping->mode & MODE_DIRECTORY);
+
+ if(!dir) {
+ mapping->end = mapping->begin;
+ return -1;
+ }
+
+ i = mapping->info.dir.first_dir_index =
+ first_cluster == 0 ? 0 : s->directory.next;
+
+ /* actually read the directory, and allocate the mappings */
+ while((entry=readdir(dir))) {
+ unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
+ char* buffer;
+ direntry_t* direntry;
+ struct stat st;
+ int is_dot=!strcmp(entry->d_name,".");
+ int is_dotdot=!strcmp(entry->d_name,"..");
+
+ if(first_cluster == 0 && (is_dotdot || is_dot))
+ continue;
+
+ buffer=(char*)malloc(length);
+ assert(buffer);
+ snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
+
+ if(stat(buffer,&st)<0) {
+ free(buffer);
+ continue;
+ }
+
+ /* create directory entry for this file */
+ direntry=create_short_and_long_name(s, i, entry->d_name,
+ is_dot || is_dotdot);
+ direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
+ direntry->reserved[0]=direntry->reserved[1]=0;
+ direntry->ctime=fat_datetime(st.st_ctime,1);
+ direntry->cdate=fat_datetime(st.st_ctime,0);
+ direntry->adate=fat_datetime(st.st_atime,0);
+ direntry->begin_hi=0;
+ direntry->mtime=fat_datetime(st.st_mtime,1);
+ direntry->mdate=fat_datetime(st.st_mtime,0);
+ if(is_dotdot)
+ set_begin_of_direntry(direntry, first_cluster_of_parent);
+ else if(is_dot)
+ set_begin_of_direntry(direntry, first_cluster);
+ else
+ direntry->begin=0; /* do that later */
+ if (st.st_size > 0x7fffffff) {
+ fprintf(stderr, "File %s is larger than 2GB\n", buffer);
+ free(buffer);
+ return -2;
+ }
+ direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
+
+ /* create mapping for this file */
+ if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
+ s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
+ s->current_mapping->begin=0;
+ s->current_mapping->end=st.st_size;
+ /*
+ * we get the direntry of the most recent direntry, which
+ * contains the short name and all the relevant information.
+ */
+ s->current_mapping->dir_index=s->directory.next-1;
+ s->current_mapping->first_mapping_index = -1;
+ if (S_ISDIR(st.st_mode)) {
+ s->current_mapping->mode = MODE_DIRECTORY;
+ s->current_mapping->info.dir.parent_mapping_index =
+ mapping_index;
+ } else {
+ s->current_mapping->mode = MODE_UNDEFINED;
+ s->current_mapping->info.file.offset = 0;
+ }
+ s->current_mapping->path=buffer;
+ s->current_mapping->read_only =
+ (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
+ }
+ }
+ closedir(dir);
+
+ /* fill with zeroes up to the end of the cluster */
+ while(s->directory.next%(0x10*s->sectors_per_cluster)) {
+ direntry_t* direntry=array_get_next(&(s->directory));
+ memset(direntry,0,sizeof(direntry_t));
+ }
+
+/* TODO: if there are more entries, bootsector has to be adjusted! */
+#define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
+ if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
+ /* root directory */
+ int cur = s->directory.next;
+ array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
+ memset(array_get(&(s->directory), cur), 0,
+ (ROOT_ENTRIES - cur) * sizeof(direntry_t));
+ }
+
+ /* reget the mapping, since s->mapping was possibly realloc()ed */
+ mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
+ first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
+ * 0x20 / s->cluster_size;
+ mapping->end = first_cluster;
+
+ direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
+ set_begin_of_direntry(direntry, mapping->begin);
+
+ return 0;
+}
+
+static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
+{
+ return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
+}
+
+static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
+{
+ return s->faked_sectors + s->sectors_per_cluster * cluster_num;
+}
+
+static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
+{
+ return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
+}
+
+#ifdef DBG
+static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
+{
+ if(mapping->mode==MODE_UNDEFINED)
+ return 0;
+ return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
+}
+#endif
+
+static int init_directories(BDRVVVFATState* s,
+ const char* dirname)
+{
+ bootsector_t* bootsector;
+ mapping_t* mapping;
+ unsigned int i;
+ unsigned int cluster;
+
+ memset(&(s->first_sectors[0]),0,0x40*0x200);
+
+ s->cluster_size=s->sectors_per_cluster*0x200;
+ s->cluster_buffer=malloc(s->cluster_size);
+ assert(s->cluster_buffer);
+
+ /*
+ * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
+ * where sc is sector_count,
+ * spf is sectors_per_fat,
+ * spc is sectors_per_clusters, and
+ * fat_type = 12, 16 or 32.
+ */
+ i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
+ s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
+
+ array_init(&(s->mapping),sizeof(mapping_t));
+ array_init(&(s->directory),sizeof(direntry_t));
+
+ /* add volume label */
+ {
+ direntry_t* entry=array_get_next(&(s->directory));
+ entry->attributes=0x28; /* archive | volume label */
+ snprintf(entry->name,11,"QEMU VVFAT");
+ }
+
+ /* Now build FAT, and write back information into directory */
+ init_fat(s);
+
+ s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
+ s->cluster_count=sector2cluster(s, s->sector_count);
+
+ mapping = array_get_next(&(s->mapping));
+ mapping->begin = 0;
+ mapping->dir_index = 0;
+ mapping->info.dir.parent_mapping_index = -1;
+ mapping->first_mapping_index = -1;
+ mapping->path = strdup(dirname);
+ i = strlen(mapping->path);
+ if (i > 0 && mapping->path[i - 1] == '/')
+ mapping->path[i - 1] = '\0';
+ mapping->mode = MODE_DIRECTORY;
+ mapping->read_only = 0;
+ s->path = mapping->path;
+
+ for (i = 0, cluster = 0; i < s->mapping.next; i++) {
+ int j;
+ /* MS-DOS expects the FAT to be 0 for the root directory
+ * (except for the media byte). */
+ /* LATER TODO: still true for FAT32? */
+ int fix_fat = (i != 0);
+ mapping = array_get(&(s->mapping), i);
+
+ if (mapping->mode & MODE_DIRECTORY) {
+ mapping->begin = cluster;
+ if(read_directory(s, i)) {
+ fprintf(stderr, "Could not read directory %s\n",
+ mapping->path);
+ return -1;
+ }
+ mapping = array_get(&(s->mapping), i);
+ } else {
+ assert(mapping->mode == MODE_UNDEFINED);
+ mapping->mode=MODE_NORMAL;
+ mapping->begin = cluster;
+ if (mapping->end > 0) {
+ direntry_t* direntry = array_get(&(s->directory),
+ mapping->dir_index);
+
+ mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
+ set_begin_of_direntry(direntry, mapping->begin);
+ } else {
+ mapping->end = cluster + 1;
+ fix_fat = 0;
+ }
+ }
+
+ assert(mapping->begin < mapping->end);
+
+ /* fix fat for entry */
+ if (fix_fat) {
+ for(j = mapping->begin; j < mapping->end - 1; j++)
+ fat_set(s, j, j+1);
+ fat_set(s, mapping->end - 1, s->max_fat_value);
+ }
+
+ /* next free cluster */
+ cluster = mapping->end;
+
+ if(cluster > s->cluster_count) {
+ fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type);
+ return -1;
+ }
+ }
+
+ mapping = array_get(&(s->mapping), 0);
+ s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
+ s->last_cluster_of_root_directory = mapping->end;
+
+ /* the FAT signature */
+ fat_set(s,0,s->max_fat_value);
+ fat_set(s,1,s->max_fat_value);
+
+ s->current_mapping = NULL;
+
+ bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
+ bootsector->jump[0]=0xeb;
+ bootsector->jump[1]=0x3e;
+ bootsector->jump[2]=0x90;
+ memcpy(bootsector->name,"QEMU ",8);
+ bootsector->sector_size=cpu_to_le16(0x200);
+ bootsector->sectors_per_cluster=s->sectors_per_cluster;
+ bootsector->reserved_sectors=cpu_to_le16(1);
+ bootsector->number_of_fats=0x2; /* number of FATs */
+ bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
+ bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
+ bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
+ s->fat.pointer[0] = bootsector->media_type;
+ bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
+ bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
+ bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
+ bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
+ bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
+
+ /* LATER TODO: if FAT32, this is wrong */
+ bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
+ bootsector->u.fat16.current_head=0;
+ bootsector->u.fat16.signature=0x29;
+ bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
+
+ memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
+ memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12 ":s->fat_type==16?"FAT16 ":"FAT32 "),8);
+ bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
+
+ return 0;
+}
+
+#ifdef DEBUG
+static BDRVVVFATState *vvv = NULL;
+#endif
+
+static int enable_write_target(BDRVVVFATState *s);
+static int is_consistent(BDRVVVFATState *s);
+
+static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
+{
+ BDRVVVFATState *s = bs->opaque;
+ int floppy = 0;
+ int i;
+
+#ifdef DEBUG
+ vvv = s;
+#endif
+
+DLOG(if (stderr == NULL) {
+ stderr = fopen("vvfat.log", "a");
+ setbuf(stderr, NULL);
+})
+
+ s->bs = bs;
+
+ s->fat_type=16;
+ /* LATER TODO: if FAT32, adjust */
+ s->sector_count=0xec04f;
+ s->sectors_per_cluster=0x10;
+ /* LATER TODO: this could be wrong for FAT32 */
+ bs->cyls=1023; bs->heads=15; bs->secs=63;
+
+ s->current_cluster=0xffffffff;
+
+ s->first_sectors_number=0x40;
+ /* read only is the default for safety */
+ bs->read_only = 1;
+ s->qcow = s->write_target = NULL;
+ s->qcow_filename = NULL;
+ s->fat2 = NULL;
+ s->downcase_short_names = 1;
+
+ if (!strstart(dirname, "fat:", NULL))
+ return -1;
+
+ if (strstr(dirname, ":rw:")) {
+ if (enable_write_target(s))
+ return -1;
+ bs->read_only = 0;
+ }
+
+ if (strstr(dirname, ":floppy:")) {
+ floppy = 1;
+ s->fat_type = 12;
+ s->first_sectors_number = 1;
+ s->sectors_per_cluster=2;
+ bs->cyls = 80; bs->heads = 2; bs->secs = 36;
+ }
+
+ if (strstr(dirname, ":32:")) {
+ fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
+ s->fat_type = 32;
+ } else if (strstr(dirname, ":16:")) {
+ s->fat_type = 16;
+ } else if (strstr(dirname, ":12:")) {
+ s->fat_type = 12;
+ s->sector_count=2880;
+ }
+
+ i = strrchr(dirname, ':') - dirname;
+ assert(i >= 3);
+ if (dirname[i-2] == ':' && isalpha(dirname[i-1]))
+ /* workaround for DOS drive names */
+ dirname += i-1;
+ else
+ dirname += i+1;
+
+ bs->total_sectors=bs->cyls*bs->heads*bs->secs;
+ if (s->sector_count > bs->total_sectors)
+ s->sector_count = bs->total_sectors;
+ if(init_directories(s, dirname))
+ return -1;
+
+ if(s->first_sectors_number==0x40)
+ init_mbr(s);
+
+ /* for some reason or other, MS-DOS does not like to know about CHS... */
+ if (floppy)
+ bs->heads = bs->cyls = bs->secs = 0;
+
+ // assert(is_consistent(s));
+ return 0;
+}
+
+static inline void vvfat_close_current_file(BDRVVVFATState *s)
+{
+ if(s->current_mapping) {
+ s->current_mapping = NULL;
+ if (s->current_fd) {
+ close(s->current_fd);
+ s->current_fd = 0;
+ }
+ }
+ s->current_cluster = -1;
+}
+
+/* mappings between index1 and index2-1 are supposed to be ordered
+ * return value is the index of the last mapping for which end>cluster_num
+ */
+static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
+{
+ int index3=index1+1;
+ while(1) {
+ mapping_t* mapping;
+ index3=(index1+index2)/2;
+ mapping=array_get(&(s->mapping),index3);
+ assert(mapping->begin < mapping->end);
+ if(mapping->begin>=cluster_num) {
+ assert(index2!=index3 || index2==0);
+ if(index2==index3)
+ return index1;
+ index2=index3;
+ } else {
+ if(index1==index3)
+ return mapping->end<=cluster_num ? index2 : index1;
+ index1=index3;
+ }
+ assert(index1<=index2);
+ DLOG(mapping=array_get(&(s->mapping),index1);
+ assert(mapping->begin<=cluster_num);
+ assert(index2 >= s->mapping.next ||
+ ((mapping = array_get(&(s->mapping),index2)) &&
+ mapping->end>cluster_num)));
+ }
+}
+
+static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
+{
+ int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
+ mapping_t* mapping;
+ if(index>=s->mapping.next)
+ return 0;
+ mapping=array_get(&(s->mapping),index);
+ if(mapping->begin>cluster_num)
+ return 0;
+ assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
+ return mapping;
+}
+
+/*
+ * This function simply compares path == mapping->path. Since the mappings
+ * are sorted by cluster, this is expensive: O(n).
+ */
+static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
+ const char* path)
+{
+ int i;
+
+ for (i = 0; i < s->mapping.next; i++) {
+ mapping_t* mapping = array_get(&(s->mapping), i);
+ if (mapping->first_mapping_index < 0 &&
+ !strcmp(path, mapping->path))
+ return mapping;
+ }
+
+ return NULL;
+}
+
+static int open_file(BDRVVVFATState* s,mapping_t* mapping)
+{
+ if(!mapping)
+ return -1;
+ if(!s->current_mapping ||
+ strcmp(s->current_mapping->path,mapping->path)) {
+ /* open file */
+ int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
+ if(fd<0)
+ return -1;
+ vvfat_close_current_file(s);
+ s->current_fd = fd;
+ s->current_mapping = mapping;
+ }
+ return 0;
+}
+
+static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
+{
+ if(s->current_cluster != cluster_num) {
+ int result=0;
+ off_t offset;
+ assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
+ if(!s->current_mapping
+ || s->current_mapping->begin>cluster_num
+ || s->current_mapping->end<=cluster_num) {
+ /* binary search of mappings for file */
+ mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
+
+ assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
+
+ if (mapping && mapping->mode & MODE_DIRECTORY) {
+ vvfat_close_current_file(s);
+ s->current_mapping = mapping;
+read_cluster_directory:
+ offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
+ s->cluster = s->directory.pointer+offset
+ + 0x20*s->current_mapping->info.dir.first_dir_index;
+ assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
+ assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
+ s->current_cluster = cluster_num;
+ return 0;
+ }
+
+ if(open_file(s,mapping))
+ return -2;
+ } else if (s->current_mapping->mode & MODE_DIRECTORY)
+ goto read_cluster_directory;
+
+ assert(s->current_fd);
+
+ offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
+ if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
+ return -3;
+ s->cluster=s->cluster_buffer;
+ result=read(s->current_fd,s->cluster,s->cluster_size);
+ if(result<0) {
+ s->current_cluster = -1;
+ return -1;
+ }
+ s->current_cluster = cluster_num;
+ }
+ return 0;
+}
+
+#ifdef DEBUG
+static void hexdump(const void* address, uint32_t len)
+{
+ const unsigned char* p = address;
+ int i, j;
+
+ for (i = 0; i < len; i += 16) {
+ for (j = 0; j < 16 && i + j < len; j++)
+ fprintf(stderr, "%02x ", p[i + j]);
+ for (; j < 16; j++)
+ fprintf(stderr, " ");
+ fprintf(stderr, " ");
+ for (j = 0; j < 16 && i + j < len; j++)
+ fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
+ fprintf(stderr, "\n");
+ }
+}
+
+static void print_direntry(const direntry_t* direntry)
+{
+ int j = 0;
+ char buffer[1024];
+
+ fprintf(stderr, "direntry 0x%x: ", (int)direntry);
+ if(!direntry)
+ return;
+ if(is_long_name(direntry)) {
+ unsigned char* c=(unsigned char*)direntry;
+ int i;
+ for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
+#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = '°'; j++;}
+ ADD_CHAR(c[i]);
+ for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
+ ADD_CHAR(c[i]);
+ for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
+ ADD_CHAR(c[i]);
+ buffer[j] = 0;
+ fprintf(stderr, "%s\n", buffer);
+ } else {
+ int i;
+ for(i=0;i<11;i++)
+ ADD_CHAR(direntry->name[i]);
+ buffer[j] = 0;
+ fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
+ buffer,
+ direntry->attributes,
+ begin_of_direntry(direntry),le32_to_cpu(direntry->size));
+ }
+}
+
+static void print_mapping(const mapping_t* mapping)
+{
+ fprintf(stderr, "mapping (0x%x): begin, end = %d, %d, dir_index = %d, first_mapping_index = %d, name = %s, mode = 0x%x, " , (int)mapping, mapping->begin, mapping->end, mapping->dir_index, mapping->first_mapping_index, mapping->path, mapping->mode);
+ if (mapping->mode & MODE_DIRECTORY)
+ fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
+ else
+ fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
+}
+#endif
+
+static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
+ uint8_t *buf, int nb_sectors)
+{
+ BDRVVVFATState *s = bs->opaque;
+ int i;
+
+ for(i=0;i<nb_sectors;i++,sector_num++) {
+ if (sector_num >= s->sector_count)
+ return -1;
+ if (s->qcow) {
+ int n;
+ if (s->qcow->drv->bdrv_is_allocated(s->qcow,
+ sector_num, nb_sectors-i, &n)) {
+DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
+ if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n))
+ return -1;
+ i += n - 1;
+ sector_num += n - 1;
+ continue;
+ }
+DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
+ }
+ if(sector_num<s->faked_sectors) {
+ if(sector_num<s->first_sectors_number)
+ memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
+ else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
+ memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
+ else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
+ memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
+ } else {
+ uint32_t sector=sector_num-s->faked_sectors,
+ sector_offset_in_cluster=(sector%s->sectors_per_cluster),
+ cluster_num=sector/s->sectors_per_cluster;
+ if(read_cluster(s, cluster_num) != 0) {
+ /* LATER TODO: strict: return -1; */
+ memset(buf+i*0x200,0,0x200);
+ continue;
+ }
+ memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
+ }
+ }
+ return 0;
+}
+
+/* LATER TODO: statify all functions */
+
+/*
+ * Idea of the write support (use snapshot):
+ *
+ * 1. check if all data is consistent, recording renames, modifications,
+ * new files and directories (in s->commits).
+ *
+ * 2. if the data is not consistent, stop committing
+ *
+ * 3. handle renames, and create new files and directories (do not yet
+ * write their contents)
+ *
+ * 4. walk the directories, fixing the mapping and direntries, and marking
+ * the handled mappings as not deleted
+ *
+ * 5. commit the contents of the files
+ *
+ * 6. handle deleted files and directories
+ *
+ */
+
+typedef struct commit_t {
+ char* path;
+ union {
+ struct { uint32_t cluster; } rename;
+ struct { int dir_index; uint32_t modified_offset; } writeout;
+ struct { uint32_t first_cluster; } new_file;
+ struct { uint32_t cluster; } mkdir;
+ } param;
+ /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
+ enum {
+ ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
+ } action;
+} commit_t;
+
+static void clear_commits(BDRVVVFATState* s)
+{
+ int i;
+DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
+ for (i = 0; i < s->commits.next; i++) {
+ commit_t* commit = array_get(&(s->commits), i);
+ assert(commit->path || commit->action == ACTION_WRITEOUT);
+ if (commit->action != ACTION_WRITEOUT) {
+ assert(commit->path);
+ free(commit->path);
+ } else
+ assert(commit->path == NULL);
+ }
+ s->commits.next = 0;
+}
+
+static void schedule_rename(BDRVVVFATState* s,
+ uint32_t cluster, char* new_path)
+{
+ commit_t* commit = array_get_next(&(s->commits));
+ commit->path = new_path;
+ commit->param.rename.cluster = cluster;
+ commit->action = ACTION_RENAME;
+}
+
+static void schedule_writeout(BDRVVVFATState* s,
+ int dir_index, uint32_t modified_offset)
+{
+ commit_t* commit = array_get_next(&(s->commits));
+ commit->path = NULL;
+ commit->param.writeout.dir_index = dir_index;
+ commit->param.writeout.modified_offset = modified_offset;
+ commit->action = ACTION_WRITEOUT;
+}
+
+static void schedule_new_file(BDRVVVFATState* s,
+ char* path, uint32_t first_cluster)
+{
+ commit_t* commit = array_get_next(&(s->commits));
+ commit->path = path;
+ commit->param.new_file.first_cluster = first_cluster;
+ commit->action = ACTION_NEW_FILE;
+}
+
+static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
+{
+ commit_t* commit = array_get_next(&(s->commits));
+ commit->path = path;
+ commit->param.mkdir.cluster = cluster;
+ commit->action = ACTION_MKDIR;
+}
+
+typedef struct {
+ unsigned char name[1024];
+ int checksum, len;
+ int sequence_number;
+} long_file_name;
+
+static void lfn_init(long_file_name* lfn)
+{
+ lfn->sequence_number = lfn->len = 0;
+ lfn->checksum = 0x100;
+}
+
+/* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
+static int parse_long_name(long_file_name* lfn,
+ const direntry_t* direntry)
+{
+ int i, j, offset;
+ const unsigned char* pointer = (const unsigned char*)direntry;
+
+ if (!is_long_name(direntry))
+ return 1;
+
+ if (pointer[0] & 0x40) {
+ lfn->sequence_number = pointer[0] & 0x3f;
+ lfn->checksum = pointer[13];
+ lfn->name[0] = 0;
+ } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
+ return -1;
+ else if (pointer[13] != lfn->checksum)
+ return -2;
+ else if (pointer[12] || pointer[26] || pointer[27])
+ return -3;
+
+ offset = 13 * (lfn->sequence_number - 1);
+ for (i = 0, j = 1; i < 13; i++, j+=2) {
+ if (j == 11)
+ j = 14;
+ else if (j == 26)
+ j = 28;
+
+ if (pointer[j+1] == 0)
+ lfn->name[offset + i] = pointer[j];
+ else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
+ return -4;
+ else
+ lfn->name[offset + i] = 0;
+ }
+
+ if (pointer[0] & 0x40)
+ lfn->len = offset + strlen(lfn->name + offset);
+
+ return 0;
+}
+
+/* returns 0 if successful, >0 if no short_name, and <0 on error */
+static int parse_short_name(BDRVVVFATState* s,
+ long_file_name* lfn, direntry_t* direntry)
+{
+ int i, j;
+
+ if (!is_short_name(direntry))
+ return 1;
+
+ for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
+ for (i = 0; i <= j; i++) {
+ if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
+ return -1;
+ else if (s->downcase_short_names)
+ lfn->name[i] = tolower(direntry->name[i]);
+ else
+ lfn->name[i] = direntry->name[i];
+ }
+
+ for (j = 2; j >= 0 && direntry->extension[j] == ' '; j--);
+ if (j >= 0) {
+ lfn->name[i++] = '.';
+ lfn->name[i + j + 1] = '\0';
+ for (;j >= 0; j--) {
+ if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
+ return -2;
+ else if (s->downcase_short_names)
+ lfn->name[i + j] = tolower(direntry->extension[j]);
+ else
+ lfn->name[i + j] = direntry->extension[j];
+ }
+ } else
+ lfn->name[i + j + 1] = '\0';
+
+ lfn->len = strlen(lfn->name);
+
+ return 0;
+}
+
+static inline uint32_t modified_fat_get(BDRVVVFATState* s,
+ unsigned int cluster)
+{
+ if (cluster < s->last_cluster_of_root_directory) {
+ if (cluster + 1 == s->last_cluster_of_root_directory)
+ return s->max_fat_value;
+ else
+ return cluster + 1;
+ }
+
+ if (s->fat_type==32) {
+ uint32_t* entry=((uint32_t*)s->fat2)+cluster;
+ return le32_to_cpu(*entry);
+ } else if (s->fat_type==16) {
+ uint16_t* entry=((uint16_t*)s->fat2)+cluster;
+ return le16_to_cpu(*entry);
+ } else {
+ const uint8_t* x=s->fat2+cluster*3/2;
+ return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
+ }
+}
+
+static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
+{
+ int was_modified = 0;
+ int i, dummy;
+
+ if (s->qcow == NULL)
+ return 0;
+
+ for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
+ was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
+ cluster2sector(s, cluster_num) + i, 1, &dummy);
+
+ return was_modified;
+}
+
+static const char* get_basename(const char* path)
+{
+ char* basename = strrchr(path, '/');
+ if (basename == NULL)
+ return path;
+ else
+ return basename + 1; /* strip '/' */
+}
+
+/*
+ * The array s->used_clusters holds the states of the clusters. If it is
+ * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
+ * was modified, bit 3 is set.
+ * If any cluster is allocated, but not part of a file or directory, this
+ * driver refuses to commit.
+ */
+typedef enum {
+ USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
+} used_t;
+
+/*
+ * get_cluster_count_for_direntry() not only determines how many clusters
+ * are occupied by direntry, but also if it was renamed or modified.
+ *
+ * A file is thought to be renamed *only* if there already was a file with
+ * exactly the same first cluster, but a different name.
+ *
+ * Further, the files/directories handled by this function are
+ * assumed to be *not* deleted (and *only* those).
+ */
+static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
+ direntry_t* direntry, const char* path)
+{
+ /*
+ * This is a little bit tricky:
+ * IF the guest OS just inserts a cluster into the file chain,
+ * and leaves the rest alone, (i.e. the original file had clusters
+ * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
+ *
+ * - do_commit will write the cluster into the file at the given
+ * offset, but
+ *
+ * - the cluster which is overwritten should be moved to a later
+ * position in the file.
+ *
+ * I am not aware that any OS does something as braindead, but this
+ * situation could happen anyway when not committing for a long time.
+ * Just to be sure that this does not bite us, detect it, and copy the
+ * contents of the clusters to-be-overwritten into the qcow.
+ */
+ int copy_it = 0;
+ int was_modified = 0;
+ int32_t ret = 0;
+
+ uint32_t cluster_num = begin_of_direntry(direntry);
+ uint32_t offset = 0;
+ int first_mapping_index = -1;
+ mapping_t* mapping = NULL;
+ const char* basename2 = NULL;
+
+ vvfat_close_current_file(s);
+
+ /* the root directory */
+ if (cluster_num == 0)
+ return 0;
+
+ /* write support */
+ if (s->qcow) {
+ basename2 = get_basename(path);
+
+ mapping = find_mapping_for_cluster(s, cluster_num);
+
+ if (mapping) {
+ const char* basename;
+
+ assert(mapping->mode & MODE_DELETED);
+ mapping->mode &= ~MODE_DELETED;
+
+ basename = get_basename(mapping->path);
+
+ assert(mapping->mode & MODE_NORMAL);
+
+ /* rename */
+ if (strcmp(basename, basename2))
+ schedule_rename(s, cluster_num, strdup(path));
+ } else if (is_file(direntry))
+ /* new file */
+ schedule_new_file(s, strdup(path), cluster_num);
+ else {
+ assert(0);
+ return 0;
+ }
+ }
+
+ while(1) {
+ if (s->qcow) {
+ if (!copy_it && cluster_was_modified(s, cluster_num)) {
+ if (mapping == NULL ||
+ mapping->begin > cluster_num ||
+ mapping->end <= cluster_num)
+ mapping = find_mapping_for_cluster(s, cluster_num);
+
+
+ if (mapping &&
+ (mapping->mode & MODE_DIRECTORY) == 0) {
+
+ /* was modified in qcow */
+ if (offset != mapping->info.file.offset + s->cluster_size
+ * (cluster_num - mapping->begin)) {
+ /* offset of this cluster in file chain has changed */
+ assert(0);
+ copy_it = 1;
+ } else if (offset == 0) {
+ const char* basename = get_basename(mapping->path);
+
+ if (strcmp(basename, basename2))
+ copy_it = 1;
+ first_mapping_index = array_index(&(s->mapping), mapping);
+ }
+
+ if (mapping->first_mapping_index != first_mapping_index
+ && mapping->info.file.offset > 0) {
+ assert(0);
+ copy_it = 1;
+ }
+
+ /* need to write out? */
+ if (!was_modified && is_file(direntry)) {
+ was_modified = 1;
+ schedule_writeout(s, mapping->dir_index, offset);
+ }
+ }
+ }
+
+ if (copy_it) {
+ int i, dummy;
+ /*
+ * This is horribly inefficient, but that is okay, since
+ * it is rarely executed, if at all.
+ */
+ int64_t offset = cluster2sector(s, cluster_num);
+
+ vvfat_close_current_file(s);
+ for (i = 0; i < s->sectors_per_cluster; i++)
+ if (!s->qcow->drv->bdrv_is_allocated(s->qcow,
+ offset + i, 1, &dummy)) {
+ if (vvfat_read(s->bs,
+ offset, s->cluster_buffer, 1))
+ return -1;
+ if (s->qcow->drv->bdrv_write(s->qcow,
+ offset, s->cluster_buffer, 1))
+ return -2;
+ }
+ }
+ }
+
+ ret++;
+ if (s->used_clusters[cluster_num] & USED_ANY)
+ return 0;
+ s->used_clusters[cluster_num] = USED_FILE;
+
+ cluster_num = modified_fat_get(s, cluster_num);
+
+ if (fat_eof(s, cluster_num))
+ return ret;
+ else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
+ return -1;
+
+ offset += s->cluster_size;
+ }
+}
+
+/*
+ * This function looks at the modified data (qcow).
+ * It returns 0 upon inconsistency or error, and the number of clusters
+ * used by the directory, its subdirectories and their files.
+ */
+static int check_directory_consistency(BDRVVVFATState *s,
+ int cluster_num, const char* path)
+{
+ int ret = 0;
+ unsigned char* cluster = malloc(s->cluster_size);
+ direntry_t* direntries = (direntry_t*)cluster;
+ mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
+
+ long_file_name lfn;
+ int path_len = strlen(path);
+ char path2[PATH_MAX];
+
+ assert(path_len < PATH_MAX); /* len was tested before! */
+ strcpy(path2, path);
+ path2[path_len] = '/';
+ path2[path_len + 1] = '\0';
+
+ if (mapping) {
+ const char* basename = get_basename(mapping->path);
+ const char* basename2 = get_basename(path);
+
+ assert(mapping->mode & MODE_DIRECTORY);
+
+ assert(mapping->mode & MODE_DELETED);
+ mapping->mode &= ~MODE_DELETED;
+
+ if (strcmp(basename, basename2))
+ schedule_rename(s, cluster_num, strdup(path));
+ } else
+ /* new directory */
+ schedule_mkdir(s, cluster_num, strdup(path));
+
+ lfn_init(&lfn);
+ do {
+ int i;
+ int subret = 0;
+
+ ret++;
+
+ if (s->used_clusters[cluster_num] & USED_ANY) {
+ fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
+ return 0;
+ }
+ s->used_clusters[cluster_num] = USED_DIRECTORY;
+
+DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
+ subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
+ s->sectors_per_cluster);
+ if (subret) {
+ fprintf(stderr, "Error fetching direntries\n");
+ fail:
+ free(cluster);
+ return 0;
+ }
+
+ for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
+ int cluster_count;
+
+DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
+ if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
+ is_free(direntries + i))
+ continue;
+
+ subret = parse_long_name(&lfn, direntries + i);
+ if (subret < 0) {
+ fprintf(stderr, "Error in long name\n");
+ goto fail;
+ }
+ if (subret == 0 || is_free(direntries + i))
+ continue;
+
+ if (fat_chksum(direntries+i) != lfn.checksum) {
+ subret = parse_short_name(s, &lfn, direntries + i);
+ if (subret < 0) {
+ fprintf(stderr, "Error in short name (%d)\n", subret);
+ goto fail;
+ }
+ if (subret > 0 || !strcmp(lfn.name, ".")
+ || !strcmp(lfn.name, ".."))
+ continue;
+ }
+ lfn.checksum = 0x100; /* cannot use long name twice */
+
+ if (path_len + 1 + lfn.len >= PATH_MAX) {
+ fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
+ goto fail;
+ }
+ strcpy(path2 + path_len + 1, lfn.name);
+
+ if (is_directory(direntries + i)) {
+ if (begin_of_direntry(direntries + i) == 0) {
+ DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
+ goto fail;
+ }
+ cluster_count = check_directory_consistency(s,
+ begin_of_direntry(direntries + i), path2);
+ if (cluster_count == 0) {
+ DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
+ goto fail;
+ }
+ } else if (is_file(direntries + i)) {
+ /* check file size with FAT */
+ cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
+ if (cluster_count !=
+ (le32_to_cpu(direntries[i].size) + s->cluster_size
+ - 1) / s->cluster_size) {
+ DLOG(fprintf(stderr, "Cluster count mismatch\n"));
+ goto fail;
+ }
+ } else
+ assert(0); /* cluster_count = 0; */
+
+ ret += cluster_count;
+ }
+
+ cluster_num = modified_fat_get(s, cluster_num);
+ } while(!fat_eof(s, cluster_num));
+
+ free(cluster);
+ return ret;
+}
+
+/* returns 1 on success */
+static int is_consistent(BDRVVVFATState* s)
+{
+ int i, check;
+ int used_clusters_count = 0;
+
+DLOG(checkpoint());
+ /*
+ * - get modified FAT
+ * - compare the two FATs (TODO)
+ * - get buffer for marking used clusters
+ * - recurse direntries from root (using bs->bdrv_read to make
+ * sure to get the new data)
+ * - check that the FAT agrees with the size
+ * - count the number of clusters occupied by this directory and
+ * its files
+ * - check that the cumulative used cluster count agrees with the
+ * FAT
+ * - if all is fine, return number of used clusters
+ */
+ if (s->fat2 == NULL) {
+ int size = 0x200 * s->sectors_per_fat;
+ s->fat2 = malloc(size);
+ memcpy(s->fat2, s->fat.pointer, size);
+ }
+ check = vvfat_read(s->bs,
+ s->first_sectors_number, s->fat2, s->sectors_per_fat);
+ if (check) {
+ fprintf(stderr, "Could not copy fat\n");
+ return 0;
+ }
+ assert (s->used_clusters);
+ for (i = 0; i < sector2cluster(s, s->sector_count); i++)
+ s->used_clusters[i] &= ~USED_ANY;
+
+ clear_commits(s);
+
+ /* mark every mapped file/directory as deleted.
+ * (check_directory_consistency() will unmark those still present). */
+ if (s->qcow)
+ for (i = 0; i < s->mapping.next; i++) {
+ mapping_t* mapping = array_get(&(s->mapping), i);
+ if (mapping->first_mapping_index < 0)
+ mapping->mode |= MODE_DELETED;
+ }
+
+ used_clusters_count = check_directory_consistency(s, 0, s->path);
+ if (used_clusters_count <= 0) {
+ DLOG(fprintf(stderr, "problem in directory\n"));
+ return 0;
+ }
+
+ check = s->last_cluster_of_root_directory;
+ for (i = check; i < sector2cluster(s, s->sector_count); i++) {
+ if (modified_fat_get(s, i)) {
+ if(!s->used_clusters[i]) {
+ DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
+ return 0;
+ }
+ check++;
+ }
+
+ if (s->used_clusters[i] == USED_ALLOCATED) {
+ /* allocated, but not used... */
+ DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
+ return 0;
+ }
+ }
+
+ if (check != used_clusters_count)
+ return 0;
+
+ return used_clusters_count;
+}
+
+static inline void adjust_mapping_indices(BDRVVVFATState* s,
+ int offset, int adjust)
+{
+ int i;
+
+ for (i = 0; i < s->mapping.next; i++) {
+ mapping_t* mapping = array_get(&(s->mapping), i);
+
+#define ADJUST_MAPPING_INDEX(name) \
+ if (mapping->name >= offset) \
+ mapping->name += adjust
+
+ ADJUST_MAPPING_INDEX(first_mapping_index);
+ if (mapping->mode & MODE_DIRECTORY)
+ ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
+ }
+}
+
+/* insert or update mapping */
+static mapping_t* insert_mapping(BDRVVVFATState* s,
+ uint32_t begin, uint32_t end)
+{
+ /*
+ * - find mapping where mapping->begin >= begin,
+ * - if mapping->begin > begin: insert
+ * - adjust all references to mappings!
+ * - else: adjust
+ * - replace name
+ */
+ int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
+ mapping_t* mapping = NULL;
+ mapping_t* first_mapping = array_get(&(s->mapping), 0);
+
+ if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
+ && mapping->begin < begin) {
+ mapping->end = begin;
+ index++;
+ mapping = array_get(&(s->mapping), index);
+ }
+ if (index >= s->mapping.next || mapping->begin > begin) {
+ mapping = array_insert(&(s->mapping), index, 1);
+ mapping->path = NULL;
+ adjust_mapping_indices(s, index, +1);
+ }
+
+ mapping->begin = begin;
+ mapping->end = end;
+
+DLOG(mapping_t* next_mapping;
+assert(index + 1 >= s->mapping.next ||
+((next_mapping = array_get(&(s->mapping), index + 1)) &&
+ next_mapping->begin >= end)));
+
+ if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
+ s->current_mapping = array_get(&(s->mapping),
+ s->current_mapping - first_mapping);
+
+ return mapping;
+}
+
+static int remove_mapping(BDRVVVFATState* s, int mapping_index)
+{
+ mapping_t* mapping = array_get(&(s->mapping), mapping_index);
+ mapping_t* first_mapping = array_get(&(s->mapping), 0);
+
+ /* free mapping */
+ if (mapping->first_mapping_index < 0)
+ free(mapping->path);
+
+ /* remove from s->mapping */
+ array_remove(&(s->mapping), mapping_index);
+
+ /* adjust all references to mappings */
+ adjust_mapping_indices(s, mapping_index, -1);
+
+ if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
+ s->current_mapping = array_get(&(s->mapping),
+ s->current_mapping - first_mapping);
+
+ return 0;
+}
+
+static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
+{
+ int i;
+ for (i = 0; i < s->mapping.next; i++) {
+ mapping_t* mapping = array_get(&(s->mapping), i);
+ if (mapping->dir_index >= offset)
+ mapping->dir_index += adjust;
+ if ((mapping->mode & MODE_DIRECTORY) &&
+ mapping->info.dir.first_dir_index >= offset)
+ mapping->info.dir.first_dir_index += adjust;
+ }
+}
+
+static direntry_t* insert_direntries(BDRVVVFATState* s,
+ int dir_index, int count)
+{
+ /*
+ * make room in s->directory,
+ * adjust_dirindices
+ */
+ direntry_t* result = array_insert(&(s->directory), dir_index, count);
+ if (result == NULL)
+ return NULL;
+ adjust_dirindices(s, dir_index, count);
+ return result;
+}
+
+static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
+{
+ int ret = array_remove_slice(&(s->directory), dir_index, count);
+ if (ret)
+ return ret;
+ adjust_dirindices(s, dir_index, -count);
+ return 0;
+}
+
+/*
+ * Adapt the mappings of the cluster chain starting at first cluster
+ * (i.e. if a file starts at first_cluster, the chain is followed according
+ * to the modified fat, and the corresponding entries in s->mapping are
+ * adjusted)
+ */
+static int commit_mappings(BDRVVVFATState* s,
+ uint32_t first_cluster, int dir_index)
+{
+ mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
+ direntry_t* direntry = array_get(&(s->directory), dir_index);
+ uint32_t cluster = first_cluster;
+
+ vvfat_close_current_file(s);
+
+ assert(mapping);
+ assert(mapping->begin == first_cluster);
+ mapping->first_mapping_index = -1;
+ mapping->dir_index = dir_index;
+ mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
+ MODE_DIRECTORY : MODE_NORMAL;
+
+ while (!fat_eof(s, cluster)) {
+ uint32_t c, c1;
+
+ for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
+ c = c1, c1 = modified_fat_get(s, c1));
+
+ c++;
+ if (c > mapping->end) {
+ int index = array_index(&(s->mapping), mapping);
+ int i, max_i = s->mapping.next - index;
+ for (i = 1; i < max_i && mapping[i].begin < c; i++);
+ while (--i > 0)
+ remove_mapping(s, index + 1);
+ }
+ assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
+ || mapping[1].begin >= c);
+ mapping->end = c;
+
+ if (!fat_eof(s, c1)) {
+ int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
+ mapping_t* next_mapping = i >= s->mapping.next ? NULL :
+ array_get(&(s->mapping), i);
+
+ if (next_mapping == NULL || next_mapping->begin > c1) {
+ int i1 = array_index(&(s->mapping), mapping);
+
+ next_mapping = insert_mapping(s, c1, c1+1);
+
+ if (c1 < c)
+ i1++;
+ mapping = array_get(&(s->mapping), i1);
+ }
+
+ next_mapping->dir_index = mapping->dir_index;
+ next_mapping->first_mapping_index =
+ mapping->first_mapping_index < 0 ?
+ array_index(&(s->mapping), mapping) :
+ mapping->first_mapping_index;
+ next_mapping->path = mapping->path;
+ next_mapping->mode = mapping->mode;
+ next_mapping->read_only = mapping->read_only;
+ if (mapping->mode & MODE_DIRECTORY) {
+ next_mapping->info.dir.parent_mapping_index =
+ mapping->info.dir.parent_mapping_index;
+ next_mapping->info.dir.first_dir_index =
+ mapping->info.dir.first_dir_index +
+ 0x10 * s->sectors_per_cluster *
+ (mapping->end - mapping->begin);
+ } else
+ next_mapping->info.file.offset = mapping->info.file.offset +
+ mapping->end - mapping->begin;
+
+ mapping = next_mapping;
+ }
+
+ cluster = c1;
+ }
+
+ return 0;
+}
+
+static int commit_direntries(BDRVVVFATState* s,
+ int dir_index, int parent_mapping_index)
+{
+ direntry_t* direntry = array_get(&(s->directory), dir_index);
+ uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
+ mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
+
+ int factor = 0x10 * s->sectors_per_cluster;
+ int old_cluster_count, new_cluster_count;
+ int current_dir_index = mapping->info.dir.first_dir_index;
+ int first_dir_index = current_dir_index;
+ int ret, i;
+ uint32_t c;
+
+DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
+
+ assert(direntry);
+ assert(mapping);
+ assert(mapping->begin == first_cluster);
+ assert(mapping->info.dir.first_dir_index < s->directory.next);
+ assert(mapping->mode & MODE_DIRECTORY);
+ assert(dir_index == 0 || is_directory(direntry));
+
+ mapping->info.dir.parent_mapping_index = parent_mapping_index;
+
+ if (first_cluster == 0) {
+ old_cluster_count = new_cluster_count =
+ s->last_cluster_of_root_directory;
+ } else {
+ for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
+ c = fat_get(s, c))
+ old_cluster_count++;
+
+ for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
+ c = modified_fat_get(s, c))
+ new_cluster_count++;
+ }
+
+ if (new_cluster_count > old_cluster_count) {
+ if (insert_direntries(s,
+ current_dir_index + factor * old_cluster_count,
+ factor * (new_cluster_count - old_cluster_count)) == NULL)
+ return -1;
+ } else if (new_cluster_count < old_cluster_count)
+ remove_direntries(s,
+ current_dir_index + factor * new_cluster_count,
+ factor * (old_cluster_count - new_cluster_count));
+
+ for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
+ void* direntry = array_get(&(s->directory), current_dir_index);
+ int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
+ s->sectors_per_cluster);
+ if (ret)
+ return ret;
+ assert(!strncmp(s->directory.pointer, "QEMU", 4));
+ current_dir_index += factor;
+ }
+
+ ret = commit_mappings(s, first_cluster, dir_index);
+ if (ret)
+ return ret;
+
+ /* recurse */
+ for (i = 0; i < factor * new_cluster_count; i++) {
+ direntry = array_get(&(s->directory), first_dir_index + i);
+ if (is_directory(direntry) && !is_dot(direntry)) {
+ mapping = find_mapping_for_cluster(s, first_cluster);
+ assert(mapping->mode & MODE_DIRECTORY);
+ ret = commit_direntries(s, first_dir_index + i,
+ array_index(&(s->mapping), mapping));
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/* commit one file (adjust contents, adjust mapping),
+ return first_mapping_index */
+static int commit_one_file(BDRVVVFATState* s,
+ int dir_index, uint32_t offset)
+{
+ direntry_t* direntry = array_get(&(s->directory), dir_index);
+ uint32_t c = begin_of_direntry(direntry);
+ uint32_t first_cluster = c;
+ mapping_t* mapping = find_mapping_for_cluster(s, c);
+ uint32_t size = filesize_of_direntry(direntry);
+ char* cluster = malloc(s->cluster_size);
+ uint32_t i;
+ int fd = 0;
+
+ assert(offset < size);
+ assert((offset % s->cluster_size) == 0);
+
+ for (i = s->cluster_size; i < offset; i += s->cluster_size)
+ c = modified_fat_get(s, c);
+
+ fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
+ if (fd < 0) {
+ fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
+ strerror(errno), errno);
+ return fd;
+ }
+ if (offset > 0)
+ if (lseek(fd, offset, SEEK_SET) != offset)
+ return -3;
+
+ while (offset < size) {
+ uint32_t c1;
+ int rest_size = (size - offset > s->cluster_size ?
+ s->cluster_size : size - offset);
+ int ret;
+
+ c1 = modified_fat_get(s, c);
+
+ assert((size - offset == 0 && fat_eof(s, c)) ||
+ (size > offset && c >=2 && !fat_eof(s, c)));
+ assert(size >= 0);
+
+ ret = vvfat_read(s->bs, cluster2sector(s, c),
+ cluster, (rest_size + 0x1ff) / 0x200);
+
+ if (ret < 0)
+ return ret;
+
+ if (write(fd, cluster, rest_size) < 0)
+ return -2;
+
+ offset += rest_size;
+ c = c1;
+ }
+
+ ftruncate(fd, size);
+ close(fd);
+
+ return commit_mappings(s, first_cluster, dir_index);
+}
+
+#ifdef DEBUG
+/* test, if all mappings point to valid direntries */
+static void check1(BDRVVVFATState* s)
+{
+ int i;
+ for (i = 0; i < s->mapping.next; i++) {
+ mapping_t* mapping = array_get(&(s->mapping), i);
+ if (mapping->mode & MODE_DELETED) {
+ fprintf(stderr, "deleted\n");
+ continue;
+ }
+ assert(mapping->dir_index >= 0);
+ assert(mapping->dir_index < s->directory.next);
+ direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
+ assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
+ if (mapping->mode & MODE_DIRECTORY) {
+ assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
+ assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
+ }
+ }
+}
+
+/* test, if all direntries have mappings */
+static void check2(BDRVVVFATState* s)
+{
+ int i;
+ int first_mapping = -1;
+
+ for (i = 0; i < s->directory.next; i++) {
+ direntry_t* direntry = array_get(&(s->directory), i);
+
+ if (is_short_name(direntry) && begin_of_direntry(direntry)) {
+ mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
+ assert(mapping);
+ assert(mapping->dir_index == i || is_dot(direntry));
+ assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
+ }
+
+ if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
+ /* cluster start */
+ int j, count = 0;
+
+ for (j = 0; j < s->mapping.next; j++) {
+ mapping_t* mapping = array_get(&(s->mapping), j);
+ if (mapping->mode & MODE_DELETED)
+ continue;
+ if (mapping->mode & MODE_DIRECTORY) {
+ if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
+ assert(++count == 1);
+ if (mapping->first_mapping_index == -1)
+ first_mapping = array_index(&(s->mapping), mapping);
+ else
+ assert(first_mapping == mapping->first_mapping_index);
+ if (mapping->info.dir.parent_mapping_index < 0)
+ assert(j == 0);
+ else {
+ mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
+ assert(parent->mode & MODE_DIRECTORY);
+ assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
+ }
+ }
+ }
+ }
+ if (count == 0)
+ first_mapping = -1;
+ }
+ }
+}
+#endif
+
+static int handle_renames_and_mkdirs(BDRVVVFATState* s)
+{
+ int i;
+
+#ifdef DEBUG
+ fprintf(stderr, "handle_renames\n");
+ for (i = 0; i < s->commits.next; i++) {
+ commit_t* commit = array_get(&(s->commits), i);
+ fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
+ }
+#endif
+
+ for (i = 0; i < s->commits.next;) {
+ commit_t* commit = array_get(&(s->commits), i);
+ if (commit->action == ACTION_RENAME) {
+ mapping_t* mapping = find_mapping_for_cluster(s,
+ commit->param.rename.cluster);
+ char* old_path = mapping->path;
+
+ assert(commit->path);
+ mapping->path = commit->path;
+ if (rename(old_path, mapping->path))
+ return -2;
+
+ if (mapping->mode & MODE_DIRECTORY) {
+ int l1 = strlen(mapping->path);
+ int l2 = strlen(old_path);
+ int diff = l1 - l2;
+ direntry_t* direntry = array_get(&(s->directory),
+ mapping->info.dir.first_dir_index);
+ uint32_t c = mapping->begin;
+ int i = 0;
+
+ /* recurse */
+ while (!fat_eof(s, c)) {
+ do {
+ direntry_t* d = direntry + i;
+
+ if (is_file(d) || (is_directory(d) && !is_dot(d))) {
+ mapping_t* m = find_mapping_for_cluster(s,
+ begin_of_direntry(d));
+ int l = strlen(m->path);
+ char* new_path = malloc(l + diff + 1);
+
+ assert(!strncmp(m->path, mapping->path, l2));
+
+ strcpy(new_path, mapping->path);
+ strcpy(new_path + l1, m->path + l2);
+
+ schedule_rename(s, m->begin, new_path);
+ }
+ i++;
+ } while((i % (0x10 * s->sectors_per_cluster)) != 0);
+ c = fat_get(s, c);
+ }
+ }
+
+ free(old_path);
+ array_remove(&(s->commits), i);
+ continue;
+ } else if (commit->action == ACTION_MKDIR) {
+ mapping_t* mapping;
+ int j, parent_path_len;
+
+#ifdef __MINGW32__
+ if (mkdir(commit->path))
+ return -5;
+#else
+ if (mkdir(commit->path, 0755))
+ return -5;
+#endif
+
+ mapping = insert_mapping(s, commit->param.mkdir.cluster,
+ commit->param.mkdir.cluster + 1);
+ if (mapping == NULL)
+ return -6;
+
+ mapping->mode = MODE_DIRECTORY;
+ mapping->read_only = 0;
+ mapping->path = commit->path;
+ j = s->directory.next;
+ assert(j);
+ insert_direntries(s, s->directory.next,
+ 0x10 * s->sectors_per_cluster);
+ mapping->info.dir.first_dir_index = j;
+
+ parent_path_len = strlen(commit->path)
+ - strlen(get_basename(commit->path)) - 1;
+ for (j = 0; j < s->mapping.next; j++) {
+ mapping_t* m = array_get(&(s->mapping), j);
+ if (m->first_mapping_index < 0 && m != mapping &&
+ !strncmp(m->path, mapping->path, parent_path_len) &&
+ strlen(m->path) == parent_path_len)
+ break;
+ }
+ assert(j < s->mapping.next);
+ mapping->info.dir.parent_mapping_index = j;
+
+ array_remove(&(s->commits), i);
+ continue;
+ }
+
+ i++;
+ }
+ return 0;
+}
+
+/*
+ * TODO: make sure that the short name is not matching *another* file
+ */
+static int handle_commits(BDRVVVFATState* s)
+{
+ int i, fail = 0;
+
+ vvfat_close_current_file(s);
+
+ for (i = 0; !fail && i < s->commits.next; i++) {
+ commit_t* commit = array_get(&(s->commits), i);
+ switch(commit->action) {
+ case ACTION_RENAME: case ACTION_MKDIR:
+ assert(0);
+ fail = -2;
+ break;
+ case ACTION_WRITEOUT: {
+ direntry_t* entry = array_get(&(s->directory),
+ commit->param.writeout.dir_index);
+ uint32_t begin = begin_of_direntry(entry);
+ mapping_t* mapping = find_mapping_for_cluster(s, begin);
+
+ assert(mapping);
+ assert(mapping->begin == begin);
+ assert(commit->path == NULL);
+
+ if (commit_one_file(s, commit->param.writeout.dir_index,
+ commit->param.writeout.modified_offset))
+ fail = -3;
+
+ break;
+ }
+ case ACTION_NEW_FILE: {
+ int begin = commit->param.new_file.first_cluster;
+ mapping_t* mapping = find_mapping_for_cluster(s, begin);
+ direntry_t* entry;
+ int i;
+
+ /* find direntry */
+ for (i = 0; i < s->directory.next; i++) {
+ entry = array_get(&(s->directory), i);
+ if (is_file(entry) && begin_of_direntry(entry) == begin)
+ break;
+ }
+
+ if (i >= s->directory.next) {
+ fail = -6;
+ continue;
+ }
+
+ /* make sure there exists an initial mapping */
+ if (mapping && mapping->begin != begin) {
+ mapping->end = begin;
+ mapping = NULL;
+ }
+ if (mapping == NULL) {
+ mapping = insert_mapping(s, begin, begin+1);
+ }
+ /* most members will be fixed in commit_mappings() */
+ assert(commit->path);
+ mapping->path = commit->path;
+ mapping->read_only = 0;
+ mapping->mode = MODE_NORMAL;
+ mapping->info.file.offset = 0;
+
+ if (commit_one_file(s, i, 0))
+ fail = -7;
+
+ break;
+ }
+ default:
+ assert(0);
+ }
+ }
+ if (i > 0 && array_remove_slice(&(s->commits), 0, i))
+ return -1;
+ return fail;
+}
+
+static int handle_deletes(BDRVVVFATState* s)
+{
+ int i, deferred = 1, deleted = 1;
+
+ /* delete files corresponding to mappings marked as deleted */
+ /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
+ while (deferred && deleted) {
+ deferred = 0;
+ deleted = 0;
+
+ for (i = 1; i < s->mapping.next; i++) {
+ mapping_t* mapping = array_get(&(s->mapping), i);
+ if (mapping->mode & MODE_DELETED) {
+ direntry_t* entry = array_get(&(s->directory),
+ mapping->dir_index);
+
+ if (is_free(entry)) {
+ /* remove file/directory */
+ if (mapping->mode & MODE_DIRECTORY) {
+ int j, next_dir_index = s->directory.next,
+ first_dir_index = mapping->info.dir.first_dir_index;
+
+ if (rmdir(mapping->path) < 0) {
+ if (errno == ENOTEMPTY) {
+ deferred++;
+ continue;
+ } else
+ return -5;
+ }
+
+ for (j = 1; j < s->mapping.next; j++) {
+ mapping_t* m = array_get(&(s->mapping), j);
+ if (m->mode & MODE_DIRECTORY &&
+ m->info.dir.first_dir_index >
+ first_dir_index &&
+ m->info.dir.first_dir_index <
+ next_dir_index)
+ next_dir_index =
+ m->info.dir.first_dir_index;
+ }
+ remove_direntries(s, first_dir_index,
+ next_dir_index - first_dir_index);
+
+ deleted++;
+ }
+ } else {
+ if (unlink(mapping->path))
+ return -4;
+ deleted++;
+ }
+ DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
+ remove_mapping(s, i);
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * synchronize mapping with new state:
+ *
+ * - copy FAT (with bdrv_read)
+ * - mark all filenames corresponding to mappings as deleted
+ * - recurse direntries from root (using bs->bdrv_read)
+ * - delete files corresponding to mappings marked as deleted
+ */
+static int do_commit(BDRVVVFATState* s)
+{
+ int ret = 0;
+
+ /* the real meat are the commits. Nothing to do? Move along! */
+ if (s->commits.next == 0)
+ return 0;
+
+ vvfat_close_current_file(s);
+
+ ret = handle_renames_and_mkdirs(s);
+ if (ret) {
+ fprintf(stderr, "Error handling renames (%d)\n", ret);
+ assert(0);
+ return ret;
+ }
+
+ /* copy FAT (with bdrv_read) */
+ memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
+
+ /* recurse direntries from root (using bs->bdrv_read) */
+ ret = commit_direntries(s, 0, -1);
+ if (ret) {
+ fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
+ assert(0);
+ return ret;
+ }
+
+ ret = handle_commits(s);
+ if (ret) {
+ fprintf(stderr, "Error handling commits (%d)\n", ret);
+ assert(0);
+ return ret;
+ }
+
+ ret = handle_deletes(s);
+ if (ret) {
+ fprintf(stderr, "Error deleting\n");
+ assert(0);
+ return ret;
+ }
+
+ s->qcow->drv->bdrv_make_empty(s->qcow);
+
+ memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
+
+DLOG(checkpoint());
+ return 0;
+}
+
+static int try_commit(BDRVVVFATState* s)
+{
+ vvfat_close_current_file(s);
+DLOG(checkpoint());
+ if(!is_consistent(s))
+ return -1;
+ return do_commit(s);
+}
+
+static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
+ const uint8_t *buf, int nb_sectors)
+{
+ BDRVVVFATState *s = bs->opaque;
+ int i, ret;
+
+DLOG(checkpoint());
+
+ vvfat_close_current_file(s);
+
+ /*
+ * Some sanity checks:
+ * - do not allow writing to the boot sector
+ * - do not allow to write non-ASCII filenames
+ */
+
+ if (sector_num < s->first_sectors_number)
+ return -1;
+
+ for (i = sector2cluster(s, sector_num);
+ i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
+ mapping_t* mapping = find_mapping_for_cluster(s, i);
+ if (mapping) {
+ if (mapping->read_only) {
+ fprintf(stderr, "Tried to write to write-protected file %s\n",
+ mapping->path);
+ return -1;
+ }
+
+ if (mapping->mode & MODE_DIRECTORY) {
+ int begin = cluster2sector(s, i);
+ int end = begin + s->sectors_per_cluster, k;
+ int dir_index;
+ const direntry_t* direntries;
+ long_file_name lfn;
+
+ lfn_init(&lfn);
+
+ if (begin < sector_num)
+ begin = sector_num;
+ if (end > sector_num + nb_sectors)
+ end = sector_num + nb_sectors;
+ dir_index = mapping->dir_index +
+ 0x10 * (begin - mapping->begin * s->sectors_per_cluster);
+ direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
+
+ for (k = 0; k < (end - begin) * 0x10; k++) {
+ /* do not allow non-ASCII filenames */
+ if (parse_long_name(&lfn, direntries + k) < 0) {
+ fprintf(stderr, "Warning: non-ASCII filename\n");
+ return -1;
+ }
+ /* no access to the direntry of a read-only file */
+ else if (is_short_name(direntries+k) &&
+ (direntries[k].attributes & 1)) {
+ if (memcmp(direntries + k,
+ array_get(&(s->directory), dir_index + k),
+ sizeof(direntry_t))) {
+ fprintf(stderr, "Warning: tried to write to write-protected file\n");
+ return -1;
+ }
+ }
+ }
+ }
+ i = mapping->end;
+ } else
+ i++;
+ }
+
+ /*
+ * Use qcow backend. Commit later.
+ */
+DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
+ ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors);
+ if (ret < 0) {
+ fprintf(stderr, "Error writing to qcow backend\n");
+ return ret;
+ }
+
+ for (i = sector2cluster(s, sector_num);
+ i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
+ if (i >= 0)
+ s->used_clusters[i] |= USED_ALLOCATED;
+
+DLOG(checkpoint());
+ /* TODO: add timeout */
+ try_commit(s);
+
+DLOG(checkpoint());
+ return 0;
+}
+
+static int vvfat_is_allocated(BlockDriverState *bs,
+ int64_t sector_num, int nb_sectors, int* n)
+{
+ BDRVVVFATState* s = bs->opaque;
+ *n = s->sector_count - sector_num;
+ if (*n > nb_sectors)
+ *n = nb_sectors;
+ else if (*n < 0)
+ return 0;
+ return 1;
+}
+
+static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
+ const uint8_t* buffer, int nb_sectors) {
+ BDRVVVFATState* s = bs->opaque;
+ return try_commit(s);
+}
+
+static void write_target_close(BlockDriverState *bs) {
+ BDRVVVFATState* s = bs->opaque;
+ bdrv_delete(s->qcow);
+ free(s->qcow_filename);
+}
+
+static BlockDriver vvfat_write_target = {
+ "vvfat_write_target", 0, NULL, NULL, NULL,
+ write_target_commit,
+ write_target_close,
+ NULL, NULL, NULL
+};
+
+static int enable_write_target(BDRVVVFATState *s)
+{
+ int size = sector2cluster(s, s->sector_count);
+ s->used_clusters = calloc(size, 1);
+
+ array_init(&(s->commits), sizeof(commit_t));
+
+ s->qcow_filename = malloc(1024);
+ get_tmp_filename(s->qcow_filename, 1024);
+ if (bdrv_create(&bdrv_qcow,
+ s->qcow_filename, s->sector_count, "fat:", 0) < 0)
+ return -1;
+ s->qcow = bdrv_new("");
+ if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0)
+ return -1;
+
+#ifndef _WIN32
+ unlink(s->qcow_filename);
+#endif
+
+ s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
+ s->bs->backing_hd->drv = &vvfat_write_target;
+ s->bs->backing_hd->opaque = s;
+
+ return 0;
+}
+
+static void vvfat_close(BlockDriverState *bs)
+{
+ BDRVVVFATState *s = bs->opaque;
+
+ vvfat_close_current_file(s);
+ array_free(&(s->fat));
+ array_free(&(s->directory));
+ array_free(&(s->mapping));
+ if(s->cluster_buffer)
+ free(s->cluster_buffer);
+}
+
+BlockDriver bdrv_vvfat = {
+ "vvfat",
+ sizeof(BDRVVVFATState),
+ NULL, /* no probe for protocols */
+ vvfat_open,
+ vvfat_read,
+ vvfat_write,
+ vvfat_close,
+ NULL, /* ??? Not sure if we can do any meaningful flushing. */
+ NULL,
+ vvfat_is_allocated,
+ .protocol_name = "fat",
+};
+
+#ifdef DEBUG
+static void checkpoint() {
+ assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
+ check1(vvv);
+ check2(vvv);
+ assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
+#if 0
+ if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
+ fprintf(stderr, "Nonono!\n");
+ mapping_t* mapping;
+ direntry_t* direntry;
+ assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
+ assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
+ if (vvv->mapping.next<47)
+ return;
+ assert((mapping = array_get(&(vvv->mapping), 47)));
+ assert(mapping->dir_index < vvv->directory.next);
+ direntry = array_get(&(vvv->directory), mapping->dir_index);
+ assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0);
+#endif
+ return;
+ /* avoid compiler warnings: */
+ hexdump(NULL, 100);
+ remove_mapping(vvv, NULL);
+ print_mapping(NULL);
+ print_direntry(NULL);
+}
+#endif
+
Added: trunk/src/host/qemu-neo1973/block.c
===================================================================
--- trunk/src/host/qemu-neo1973/block.c 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/block.c 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,1348 @@
+/*
+ * 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
+
+#define SECTOR_BITS 9
+#define SECTOR_SIZE (1 << SECTOR_BITS)
+
+typedef struct BlockDriverAIOCBSync {
+ BlockDriverAIOCB common;
+ QEMUBH *bh;
+ int ret;
+} BlockDriverAIOCBSync;
+
+static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs,
+ int64_t sector_num, uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque);
+static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs,
+ int64_t sector_num, const uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque);
+static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb);
+static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
+ uint8_t *buf, int nb_sectors);
+static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
+ const uint8_t *buf, int nb_sectors);
+
+static BlockDriverState *bdrv_first;
+static BlockDriver *first_drv;
+
+int path_is_absolute(const char *path)
+{
+ const char *p;
+#ifdef _WIN32
+ /* specific case for names like: "\\.\d:" */
+ if (*path == '/' || *path == '\\')
+ return 1;
+#endif
+ p = strchr(path, ':');
+ if (p)
+ p++;
+ else
+ p = path;
+#ifdef _WIN32
+ return (*p == '/' || *p == '\\');
+#else
+ return (*p == '/');
+#endif
+}
+
+/* if filename is absolute, just copy it to dest. Otherwise, build a
+ path to it by considering it is relative to base_path. URL are
+ supported. */
+void path_combine(char *dest, int dest_size,
+ const char *base_path,
+ const char *filename)
+{
+ const char *p, *p1;
+ int len;
+
+ if (dest_size <= 0)
+ return;
+ if (path_is_absolute(filename)) {
+ pstrcpy(dest, dest_size, filename);
+ } else {
+ p = strchr(base_path, ':');
+ if (p)
+ p++;
+ else
+ p = base_path;
+ p1 = strrchr(base_path, '/');
+#ifdef _WIN32
+ {
+ const char *p2;
+ p2 = strrchr(base_path, '\\');
+ if (!p1 || p2 > p1)
+ p1 = p2;
+ }
+#endif
+ if (p1)
+ p1++;
+ else
+ p1 = base_path;
+ if (p1 > p)
+ p = p1;
+ len = p - base_path;
+ if (len > dest_size - 1)
+ len = dest_size - 1;
+ memcpy(dest, base_path, len);
+ dest[len] = '\0';
+ pstrcat(dest, dest_size, filename);
+ }
+}
+
+
+void bdrv_register(BlockDriver *bdrv)
+{
+ if (!bdrv->bdrv_aio_read) {
+ /* add AIO emulation layer */
+ bdrv->bdrv_aio_read = bdrv_aio_read_em;
+ bdrv->bdrv_aio_write = bdrv_aio_write_em;
+ bdrv->bdrv_aio_cancel = bdrv_aio_cancel_em;
+ bdrv->aiocb_size = sizeof(BlockDriverAIOCBSync);
+ } else if (!bdrv->bdrv_read && !bdrv->bdrv_pread) {
+ /* add synchronous IO emulation layer */
+ bdrv->bdrv_read = bdrv_read_em;
+ bdrv->bdrv_write = bdrv_write_em;
+ }
+ 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
+void get_tmp_filename(char *filename, int size)
+{
+ char temp_dir[MAX_PATH];
+
+ GetTempPath(MAX_PATH, temp_dir);
+ GetTempFileName(temp_dir, "qem", 0, filename);
+}
+#else
+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
+
+#ifdef _WIN32
+static int is_windows_drive_prefix(const char *filename)
+{
+ return (((filename[0] >= 'a' && filename[0] <= 'z') ||
+ (filename[0] >= 'A' && filename[0] <= 'Z')) &&
+ filename[1] == ':');
+}
+
+static int is_windows_drive(const char *filename)
+{
+ if (is_windows_drive_prefix(filename) &&
+ filename[2] == '\0')
+ return 1;
+ if (strstart(filename, "\\\\.\\", NULL) ||
+ strstart(filename, "//./", NULL))
+ return 1;
+ return 0;
+}
+#endif
+
+static BlockDriver *find_protocol(const char *filename)
+{
+ BlockDriver *drv1;
+ char protocol[128];
+ int len;
+ const char *p;
+
+#ifdef _WIN32
+ if (is_windows_drive(filename) ||
+ is_windows_drive_prefix(filename))
+ return &bdrv_raw;
+#endif
+ p = strchr(filename, ':');
+ if (!p)
+ return &bdrv_raw;
+ len = p - filename;
+ if (len > sizeof(protocol) - 1)
+ len = sizeof(protocol) - 1;
+ memcpy(protocol, filename, len);
+ protocol[len] = '\0';
+ for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
+ if (drv1->protocol_name &&
+ !strcmp(drv1->protocol_name, protocol))
+ return drv1;
+ }
+ return NULL;
+}
+
+/* XXX: force raw format if block or character device ? It would
+ simplify the BSD case */
+static BlockDriver *find_image_format(const char *filename)
+{
+ int ret, score, score_max;
+ BlockDriver *drv1, *drv;
+ uint8_t buf[2048];
+ BlockDriverState *bs;
+
+ /* detect host devices. By convention, /dev/cdrom[N] is always
+ recognized as a host CDROM */
+ if (strstart(filename, "/dev/cdrom", NULL))
+ return &bdrv_host_device;
+#ifdef _WIN32
+ if (is_windows_drive(filename))
+ return &bdrv_host_device;
+#else
+ {
+ struct stat st;
+ if (stat(filename, &st) >= 0 &&
+ (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) {
+ return &bdrv_host_device;
+ }
+ }
+#endif
+
+ drv = find_protocol(filename);
+ /* no need to test disk image formats for vvfat */
+ if (drv == &bdrv_vvfat)
+ return drv;
+
+ ret = bdrv_file_open(&bs, filename, BDRV_O_RDONLY);
+ if (ret < 0)
+ return NULL;
+ ret = bdrv_pread(bs, 0, buf, sizeof(buf));
+ bdrv_delete(bs);
+ if (ret < 0) {
+ return NULL;
+ }
+
+ score_max = 0;
+ for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
+ if (drv1->bdrv_probe) {
+ score = drv1->bdrv_probe(buf, ret, filename);
+ if (score > score_max) {
+ score_max = score;
+ drv = drv1;
+ }
+ }
+ }
+ return drv;
+}
+
+int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags)
+{
+ BlockDriverState *bs;
+ int ret;
+
+ bs = bdrv_new("");
+ if (!bs)
+ return -ENOMEM;
+ ret = bdrv_open2(bs, filename, flags | BDRV_O_FILE, NULL);
+ if (ret < 0) {
+ bdrv_delete(bs);
+ return ret;
+ }
+ *pbs = bs;
+ return 0;
+}
+
+int bdrv_open(BlockDriverState *bs, const char *filename, int flags)
+{
+ return bdrv_open2(bs, filename, flags, NULL);
+}
+
+int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
+ BlockDriver *drv)
+{
+ int ret, open_flags;
+ char tmp_filename[1024];
+ char backing_filename[1024];
+
+ bs->read_only = 0;
+ bs->is_temporary = 0;
+ bs->encrypted = 0;
+
+ if (flags & BDRV_O_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 -ENOMEM;
+ }
+ if (bdrv_open(bs1, filename, 0) < 0) {
+ bdrv_delete(bs1);
+ return -1;
+ }
+ total_size = bdrv_getlength(bs1) >> SECTOR_BITS;
+ bdrv_delete(bs1);
+
+ get_tmp_filename(tmp_filename, sizeof(tmp_filename));
+ realpath(filename, backing_filename);
+ if (bdrv_create(&bdrv_qcow2, tmp_filename,
+ total_size, backing_filename, 0) < 0) {
+ return -1;
+ }
+ filename = tmp_filename;
+ bs->is_temporary = 1;
+ }
+
+ pstrcpy(bs->filename, sizeof(bs->filename), filename);
+ if (flags & BDRV_O_FILE) {
+ drv = find_protocol(filename);
+ if (!drv)
+ return -ENOENT;
+ } else {
+ 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;
+ /* Note: for compatibility, we open disk image files as RDWR, and
+ RDONLY as fallback */
+ if (!(flags & BDRV_O_FILE))
+ open_flags = BDRV_O_RDWR;
+ else
+ open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT);
+ ret = drv->bdrv_open(bs, filename, open_flags);
+ if (ret == -EACCES && !(flags & BDRV_O_FILE)) {
+ ret = drv->bdrv_open(bs, filename, BDRV_O_RDONLY);
+ bs->read_only = 1;
+ }
+ if (ret < 0) {
+ qemu_free(bs->opaque);
+ bs->opaque = NULL;
+ bs->drv = NULL;
+ return ret;
+ }
+ if (drv->bdrv_getlength) {
+ bs->total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
+ }
+#ifndef _WIN32
+ if (bs->is_temporary) {
+ unlink(filename);
+ }
+#endif
+ if (bs->backing_file[0] != '\0') {
+ /* if there is a backing file, use it */
+ bs->backing_hd = bdrv_new("");
+ if (!bs->backing_hd) {
+ fail:
+ bdrv_close(bs);
+ return -ENOMEM;
+ }
+ path_combine(backing_filename, sizeof(backing_filename),
+ filename, bs->backing_file);
+ if (bdrv_open(bs->backing_hd, backing_filename, 0) < 0)
+ goto fail;
+ }
+
+ /* call the change callback */
+ bs->media_changed = 1;
+ if (bs->change_cb)
+ bs->change_cb(bs->change_opaque);
+
+ return 0;
+}
+
+void bdrv_close(BlockDriverState *bs)
+{
+ if (bs->drv) {
+ 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;
+
+ /* call the change callback */
+ bs->media_changed = 1;
+ 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)
+{
+ BlockDriver *drv = bs->drv;
+ int64_t i, total_sectors;
+ int n, j;
+ unsigned char sector[512];
+
+ if (!drv)
+ return -ENOMEDIUM;
+
+ if (bs->read_only) {
+ return -EACCES;
+ }
+
+ if (!bs->backing_hd) {
+ return -ENOTSUP;
+ }
+
+ total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
+ for (i = 0; i < total_sectors;) {
+ if (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;
+ }
+ }
+
+ if (drv->bdrv_make_empty)
+ return drv->bdrv_make_empty(bs);
+
+ return 0;
+}
+
+/* return < 0 if error. See bdrv_write() for the return codes */
+int bdrv_read(BlockDriverState *bs, int64_t sector_num,
+ uint8_t *buf, int nb_sectors)
+{
+ BlockDriver *drv = bs->drv;
+
+ if (!drv)
+ return -ENOMEDIUM;
+
+ if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
+ memcpy(buf, bs->boot_sector_data, 512);
+ sector_num++;
+ nb_sectors--;
+ buf += 512;
+ if (nb_sectors == 0)
+ return 0;
+ }
+ if (drv->bdrv_pread) {
+ int ret, len;
+ len = nb_sectors * 512;
+ ret = drv->bdrv_pread(bs, sector_num * 512, buf, len);
+ if (ret < 0)
+ return ret;
+ else if (ret != len)
+ return -EINVAL;
+ else
+ return 0;
+ } else {
+ return drv->bdrv_read(bs, sector_num, buf, nb_sectors);
+ }
+}
+
+/* Return < 0 if error. Important errors are:
+ -EIO generic I/O error (may happen for all errors)
+ -ENOMEDIUM No media inserted.
+ -EINVAL Invalid sector number or nb_sectors
+ -EACCES Trying to write a read-only device
+*/
+int bdrv_write(BlockDriverState *bs, int64_t sector_num,
+ const uint8_t *buf, int nb_sectors)
+{
+ BlockDriver *drv = bs->drv;
+ if (!bs->drv)
+ return -ENOMEDIUM;
+ if (bs->read_only)
+ return -EACCES;
+ if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
+ memcpy(bs->boot_sector_data, buf, 512);
+ }
+ if (drv->bdrv_pwrite) {
+ int ret, len;
+ len = nb_sectors * 512;
+ ret = drv->bdrv_pwrite(bs, sector_num * 512, buf, len);
+ if (ret < 0)
+ return ret;
+ else if (ret != len)
+ return -EIO;
+ else
+ return 0;
+ } else {
+ return drv->bdrv_write(bs, sector_num, buf, nb_sectors);
+ }
+}
+
+static int bdrv_pread_em(BlockDriverState *bs, int64_t offset,
+ uint8_t *buf, int count1)
+{
+ uint8_t tmp_buf[SECTOR_SIZE];
+ int len, nb_sectors, count;
+ int64_t sector_num;
+
+ count = count1;
+ /* first read to align to sector start */
+ len = (SECTOR_SIZE - offset) & (SECTOR_SIZE - 1);
+ if (len > count)
+ len = count;
+ sector_num = offset >> SECTOR_BITS;
+ if (len > 0) {
+ if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
+ return -EIO;
+ memcpy(buf, tmp_buf + (offset & (SECTOR_SIZE - 1)), len);
+ count -= len;
+ if (count == 0)
+ return count1;
+ sector_num++;
+ buf += len;
+ }
+
+ /* read the sectors "in place" */
+ nb_sectors = count >> SECTOR_BITS;
+ if (nb_sectors > 0) {
+ if (bdrv_read(bs, sector_num, buf, nb_sectors) < 0)
+ return -EIO;
+ sector_num += nb_sectors;
+ len = nb_sectors << SECTOR_BITS;
+ buf += len;
+ count -= len;
+ }
+
+ /* add data from the last sector */
+ if (count > 0) {
+ if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
+ return -EIO;
+ memcpy(buf, tmp_buf, count);
+ }
+ return count1;
+}
+
+static int bdrv_pwrite_em(BlockDriverState *bs, int64_t offset,
+ const uint8_t *buf, int count1)
+{
+ uint8_t tmp_buf[SECTOR_SIZE];
+ int len, nb_sectors, count;
+ int64_t sector_num;
+
+ count = count1;
+ /* first write to align to sector start */
+ len = (SECTOR_SIZE - offset) & (SECTOR_SIZE - 1);
+ if (len > count)
+ len = count;
+ sector_num = offset >> SECTOR_BITS;
+ if (len > 0) {
+ if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
+ return -EIO;
+ memcpy(tmp_buf + (offset & (SECTOR_SIZE - 1)), buf, len);
+ if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0)
+ return -EIO;
+ count -= len;
+ if (count == 0)
+ return count1;
+ sector_num++;
+ buf += len;
+ }
+
+ /* write the sectors "in place" */
+ nb_sectors = count >> SECTOR_BITS;
+ if (nb_sectors > 0) {
+ if (bdrv_write(bs, sector_num, buf, nb_sectors) < 0)
+ return -EIO;
+ sector_num += nb_sectors;
+ len = nb_sectors << SECTOR_BITS;
+ buf += len;
+ count -= len;
+ }
+
+ /* add data from the last sector */
+ if (count > 0) {
+ if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
+ return -EIO;
+ memcpy(tmp_buf, buf, count);
+ if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0)
+ return -EIO;
+ }
+ return count1;
+}
+
+/**
+ * Read with byte offsets (needed only for file protocols)
+ */
+int bdrv_pread(BlockDriverState *bs, int64_t offset,
+ void *buf1, int count1)
+{
+ BlockDriver *drv = bs->drv;
+
+ if (!drv)
+ return -ENOMEDIUM;
+ if (!drv->bdrv_pread)
+ return bdrv_pread_em(bs, offset, buf1, count1);
+ return drv->bdrv_pread(bs, offset, buf1, count1);
+}
+
+/**
+ * Write with byte offsets (needed only for file protocols)
+ */
+int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
+ const void *buf1, int count1)
+{
+ BlockDriver *drv = bs->drv;
+
+ if (!drv)
+ return -ENOMEDIUM;
+ if (!drv->bdrv_pwrite)
+ return bdrv_pwrite_em(bs, offset, buf1, count1);
+ return drv->bdrv_pwrite(bs, offset, buf1, count1);
+}
+
+/**
+ * Truncate file to 'offset' bytes (needed only for file protocols)
+ */
+int bdrv_truncate(BlockDriverState *bs, int64_t offset)
+{
+ BlockDriver *drv = bs->drv;
+ if (!drv)
+ return -ENOMEDIUM;
+ if (!drv->bdrv_truncate)
+ return -ENOTSUP;
+ return drv->bdrv_truncate(bs, offset);
+}
+
+/**
+ * Length of a file in bytes. Return < 0 if error or unknown.
+ */
+int64_t bdrv_getlength(BlockDriverState *bs)
+{
+ BlockDriver *drv = bs->drv;
+ if (!drv)
+ return -ENOMEDIUM;
+ if (!drv->bdrv_getlength) {
+ /* legacy mode */
+ return bs->total_sectors * SECTOR_SIZE;
+ }
+ return drv->bdrv_getlength(bs);
+}
+
+/* return 0 as number of sectors if no device present or error */
+void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
+{
+ int64_t length;
+ length = bdrv_getlength(bs);
+ if (length < 0)
+ length = 0;
+ else
+ length = length >> SECTOR_BITS;
+ *nb_sectors_ptr = length;
+}
+
+/* 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;
+}
+
+/* XXX: no longer used */
+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->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_flush(BlockDriverState *bs)
+{
+ if (bs->drv->bdrv_flush)
+ bs->drv->bdrv_flush(bs);
+ if (bs->backing_hd)
+ bdrv_flush(bs->backing_hd);
+}
+
+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->drv) {
+ term_printf(" file=");
+ term_print_filename(bs->filename);
+ if (bs->backing_file[0] != '\0') {
+ term_printf(" backing_file=");
+ term_print_filename(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");
+ }
+}
+
+void bdrv_get_backing_filename(BlockDriverState *bs,
+ char *filename, int filename_size)
+{
+ if (!bs->backing_hd) {
+ pstrcpy(filename, filename_size, "");
+ } else {
+ pstrcpy(filename, filename_size, bs->backing_file);
+ }
+}
+
+int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
+ const uint8_t *buf, int nb_sectors)
+{
+ BlockDriver *drv = bs->drv;
+ if (!drv)
+ return -ENOMEDIUM;
+ if (!drv->bdrv_write_compressed)
+ return -ENOTSUP;
+ return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors);
+}
+
+int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
+{
+ BlockDriver *drv = bs->drv;
+ if (!drv)
+ return -ENOMEDIUM;
+ if (!drv->bdrv_get_info)
+ return -ENOTSUP;
+ memset(bdi, 0, sizeof(*bdi));
+ return drv->bdrv_get_info(bs, bdi);
+}
+
+/**************************************************************/
+/* handling of snapshots */
+
+int bdrv_snapshot_create(BlockDriverState *bs,
+ QEMUSnapshotInfo *sn_info)
+{
+ BlockDriver *drv = bs->drv;
+ if (!drv)
+ return -ENOMEDIUM;
+ if (!drv->bdrv_snapshot_create)
+ return -ENOTSUP;
+ return drv->bdrv_snapshot_create(bs, sn_info);
+}
+
+int bdrv_snapshot_goto(BlockDriverState *bs,
+ const char *snapshot_id)
+{
+ BlockDriver *drv = bs->drv;
+ if (!drv)
+ return -ENOMEDIUM;
+ if (!drv->bdrv_snapshot_goto)
+ return -ENOTSUP;
+ return drv->bdrv_snapshot_goto(bs, snapshot_id);
+}
+
+int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
+{
+ BlockDriver *drv = bs->drv;
+ if (!drv)
+ return -ENOMEDIUM;
+ if (!drv->bdrv_snapshot_delete)
+ return -ENOTSUP;
+ return drv->bdrv_snapshot_delete(bs, snapshot_id);
+}
+
+int bdrv_snapshot_list(BlockDriverState *bs,
+ QEMUSnapshotInfo **psn_info)
+{
+ BlockDriver *drv = bs->drv;
+ if (!drv)
+ return -ENOMEDIUM;
+ if (!drv->bdrv_snapshot_list)
+ return -ENOTSUP;
+ return drv->bdrv_snapshot_list(bs, psn_info);
+}
+
+#define NB_SUFFIXES 4
+
+char *get_human_readable_size(char *buf, int buf_size, int64_t size)
+{
+ static const char suffixes[NB_SUFFIXES] = "KMGT";
+ int64_t base;
+ int i;
+
+ if (size <= 999) {
+ snprintf(buf, buf_size, "%" PRId64, size);
+ } else {
+ base = 1024;
+ for(i = 0; i < NB_SUFFIXES; i++) {
+ if (size < (10 * base)) {
+ snprintf(buf, buf_size, "%0.1f%c",
+ (double)size / base,
+ suffixes[i]);
+ break;
+ } else if (size < (1000 * base) || i == (NB_SUFFIXES - 1)) {
+ snprintf(buf, buf_size, "%" PRId64 "%c",
+ ((size + (base >> 1)) / base),
+ suffixes[i]);
+ break;
+ }
+ base = base * 1024;
+ }
+ }
+ return buf;
+}
+
+char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn)
+{
+ char buf1[128], date_buf[128], clock_buf[128];
+#ifdef _WIN32
+ struct tm *ptm;
+#else
+ struct tm tm;
+#endif
+ time_t ti;
+ int64_t secs;
+
+ if (!sn) {
+ snprintf(buf, buf_size,
+ "%-10s%-20s%7s%20s%15s",
+ "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK");
+ } else {
+ ti = sn->date_sec;
+#ifdef _WIN32
+ ptm = localtime(&ti);
+ strftime(date_buf, sizeof(date_buf),
+ "%Y-%m-%d %H:%M:%S", ptm);
+#else
+ localtime_r(&ti, &tm);
+ strftime(date_buf, sizeof(date_buf),
+ "%Y-%m-%d %H:%M:%S", &tm);
+#endif
+ secs = sn->vm_clock_nsec / 1000000000;
+ snprintf(clock_buf, sizeof(clock_buf),
+ "%02d:%02d:%02d.%03d",
+ (int)(secs / 3600),
+ (int)((secs / 60) % 60),
+ (int)(secs % 60),
+ (int)((sn->vm_clock_nsec / 1000000) % 1000));
+ snprintf(buf, buf_size,
+ "%-10s%-20s%7s%20s%15s",
+ sn->id_str, sn->name,
+ get_human_readable_size(buf1, sizeof(buf1), sn->vm_state_size),
+ date_buf,
+ clock_buf);
+ }
+ return buf;
+}
+
+
+/**************************************************************/
+/* async I/Os */
+
+BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num,
+ uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ BlockDriver *drv = bs->drv;
+
+ if (!drv)
+ return NULL;
+
+ /* XXX: we assume that nb_sectors == 0 is suppored by the async read */
+ if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
+ memcpy(buf, bs->boot_sector_data, 512);
+ sector_num++;
+ nb_sectors--;
+ buf += 512;
+ }
+
+ return drv->bdrv_aio_read(bs, sector_num, buf, nb_sectors, cb, opaque);
+}
+
+BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num,
+ const uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ BlockDriver *drv = bs->drv;
+
+ if (!drv)
+ return NULL;
+ if (bs->read_only)
+ return NULL;
+ if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
+ memcpy(bs->boot_sector_data, buf, 512);
+ }
+
+ return drv->bdrv_aio_write(bs, sector_num, buf, nb_sectors, cb, opaque);
+}
+
+void bdrv_aio_cancel(BlockDriverAIOCB *acb)
+{
+ BlockDriver *drv = acb->bs->drv;
+
+ drv->bdrv_aio_cancel(acb);
+}
+
+
+/**************************************************************/
+/* async block device emulation */
+
+#ifdef QEMU_TOOL
+static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs,
+ int64_t sector_num, uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ int ret;
+ ret = bdrv_read(bs, sector_num, buf, nb_sectors);
+ cb(opaque, ret);
+ return NULL;
+}
+
+static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs,
+ int64_t sector_num, const uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ int ret;
+ ret = bdrv_write(bs, sector_num, buf, nb_sectors);
+ cb(opaque, ret);
+ return NULL;
+}
+
+static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb)
+{
+}
+#else
+static void bdrv_aio_bh_cb(void *opaque)
+{
+ BlockDriverAIOCBSync *acb = opaque;
+ acb->common.cb(acb->common.opaque, acb->ret);
+ qemu_aio_release(acb);
+}
+
+static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs,
+ int64_t sector_num, uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ BlockDriverAIOCBSync *acb;
+ int ret;
+
+ acb = qemu_aio_get(bs, cb, opaque);
+ if (!acb->bh)
+ acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
+ ret = bdrv_read(bs, sector_num, buf, nb_sectors);
+ acb->ret = ret;
+ qemu_bh_schedule(acb->bh);
+ return &acb->common;
+}
+
+static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs,
+ int64_t sector_num, const uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ BlockDriverAIOCBSync *acb;
+ int ret;
+
+ acb = qemu_aio_get(bs, cb, opaque);
+ if (!acb->bh)
+ acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
+ ret = bdrv_write(bs, sector_num, buf, nb_sectors);
+ acb->ret = ret;
+ qemu_bh_schedule(acb->bh);
+ return &acb->common;
+}
+
+static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb)
+{
+ BlockDriverAIOCBSync *acb = (BlockDriverAIOCBSync *)blockacb;
+ qemu_bh_cancel(acb->bh);
+ qemu_aio_release(acb);
+}
+#endif /* !QEMU_TOOL */
+
+/**************************************************************/
+/* sync block device emulation */
+
+static void bdrv_rw_em_cb(void *opaque, int ret)
+{
+ *(int *)opaque = ret;
+}
+
+#define NOT_DONE 0x7fffffff
+
+static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
+ uint8_t *buf, int nb_sectors)
+{
+ int async_ret;
+ BlockDriverAIOCB *acb;
+
+ async_ret = NOT_DONE;
+ qemu_aio_wait_start();
+ acb = bdrv_aio_read(bs, sector_num, buf, nb_sectors,
+ bdrv_rw_em_cb, &async_ret);
+ if (acb == NULL) {
+ qemu_aio_wait_end();
+ return -1;
+ }
+ while (async_ret == NOT_DONE) {
+ qemu_aio_wait();
+ }
+ qemu_aio_wait_end();
+ return async_ret;
+}
+
+static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
+ const uint8_t *buf, int nb_sectors)
+{
+ int async_ret;
+ BlockDriverAIOCB *acb;
+
+ async_ret = NOT_DONE;
+ qemu_aio_wait_start();
+ acb = bdrv_aio_write(bs, sector_num, buf, nb_sectors,
+ bdrv_rw_em_cb, &async_ret);
+ if (acb == NULL) {
+ qemu_aio_wait_end();
+ return -1;
+ }
+ while (async_ret == NOT_DONE) {
+ qemu_aio_wait();
+ }
+ qemu_aio_wait_end();
+ return async_ret;
+}
+
+void bdrv_init(void)
+{
+ bdrv_register(&bdrv_raw);
+ bdrv_register(&bdrv_host_device);
+#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);
+ bdrv_register(&bdrv_qcow2);
+}
+
+void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,
+ void *opaque)
+{
+ BlockDriver *drv;
+ BlockDriverAIOCB *acb;
+
+ drv = bs->drv;
+ if (drv->free_aiocb) {
+ acb = drv->free_aiocb;
+ drv->free_aiocb = acb->next;
+ } else {
+ acb = qemu_mallocz(drv->aiocb_size);
+ if (!acb)
+ return NULL;
+ }
+ acb->bs = bs;
+ acb->cb = cb;
+ acb->opaque = opaque;
+ return acb;
+}
+
+void qemu_aio_release(void *p)
+{
+ BlockDriverAIOCB *acb = p;
+ BlockDriver *drv = acb->bs->drv;
+ acb->next = drv->free_aiocb;
+ drv->free_aiocb = acb;
+}
+
+/**************************************************************/
+/* removable device support */
+
+/**
+ * Return TRUE if the media is present
+ */
+int bdrv_is_inserted(BlockDriverState *bs)
+{
+ BlockDriver *drv = bs->drv;
+ int ret;
+ if (!drv)
+ return 0;
+ if (!drv->bdrv_is_inserted)
+ return 1;
+ ret = drv->bdrv_is_inserted(bs);
+ return ret;
+}
+
+/**
+ * Return TRUE if the media changed since the last call to this
+ * function. It is currently only used for floppy disks
+ */
+int bdrv_media_changed(BlockDriverState *bs)
+{
+ BlockDriver *drv = bs->drv;
+ int ret;
+
+ if (!drv || !drv->bdrv_media_changed)
+ ret = -ENOTSUP;
+ else
+ ret = drv->bdrv_media_changed(bs);
+ if (ret == -ENOTSUP)
+ ret = bs->media_changed;
+ bs->media_changed = 0;
+ return ret;
+}
+
+/**
+ * If eject_flag is TRUE, eject the media. Otherwise, close the tray
+ */
+void bdrv_eject(BlockDriverState *bs, int eject_flag)
+{
+ BlockDriver *drv = bs->drv;
+ int ret;
+
+ if (!drv || !drv->bdrv_eject) {
+ ret = -ENOTSUP;
+ } else {
+ ret = drv->bdrv_eject(bs, eject_flag);
+ }
+ if (ret == -ENOTSUP) {
+ if (eject_flag)
+ bdrv_close(bs);
+ }
+}
+
+int bdrv_is_locked(BlockDriverState *bs)
+{
+ return bs->locked;
+}
+
+/**
+ * Lock or unlock the media (if it is locked, the user won't be able
+ * to eject it manually).
+ */
+void bdrv_set_locked(BlockDriverState *bs, int locked)
+{
+ BlockDriver *drv = bs->drv;
+
+ bs->locked = locked;
+ if (drv && drv->bdrv_set_locked) {
+ drv->bdrv_set_locked(bs, locked);
+ }
+}
Added: trunk/src/host/qemu-neo1973/block_int.h
===================================================================
--- trunk/src/host/qemu-neo1973/block_int.h 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/block_int.h 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,132 @@
+/*
+ * 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 flags);
+ 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);
+ void (*bdrv_flush)(BlockDriverState *bs);
+ int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
+ int nb_sectors, int *pnum);
+ int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
+ int (*bdrv_make_empty)(BlockDriverState *bs);
+ /* aio */
+ BlockDriverAIOCB *(*bdrv_aio_read)(BlockDriverState *bs,
+ int64_t sector_num, uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque);
+ BlockDriverAIOCB *(*bdrv_aio_write)(BlockDriverState *bs,
+ int64_t sector_num, const uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque);
+ void (*bdrv_aio_cancel)(BlockDriverAIOCB *acb);
+ int aiocb_size;
+
+ const char *protocol_name;
+ int (*bdrv_pread)(BlockDriverState *bs, int64_t offset,
+ uint8_t *buf, int count);
+ int (*bdrv_pwrite)(BlockDriverState *bs, int64_t offset,
+ const uint8_t *buf, int count);
+ int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
+ int64_t (*bdrv_getlength)(BlockDriverState *bs);
+ int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num,
+ const uint8_t *buf, int nb_sectors);
+
+ int (*bdrv_snapshot_create)(BlockDriverState *bs,
+ QEMUSnapshotInfo *sn_info);
+ int (*bdrv_snapshot_goto)(BlockDriverState *bs,
+ const char *snapshot_id);
+ int (*bdrv_snapshot_delete)(BlockDriverState *bs, const char *snapshot_id);
+ int (*bdrv_snapshot_list)(BlockDriverState *bs,
+ QEMUSnapshotInfo **psn_info);
+ int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
+
+ /* removable device specific */
+ int (*bdrv_is_inserted)(BlockDriverState *bs);
+ int (*bdrv_media_changed)(BlockDriverState *bs);
+ int (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
+ int (*bdrv_set_locked)(BlockDriverState *bs, int locked);
+
+ BlockDriverAIOCB *free_aiocb;
+ struct BlockDriver *next;
+};
+
+struct BlockDriverState {
+ int64_t total_sectors; /* if we are reading a disk image, give its
+ size in sectors */
+ int read_only; /* if true, the media is read only */
+ 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; /* NULL means no media */
+ 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;
+ int media_changed;
+
+ BlockDriverState *backing_hd;
+ /* async read/write emulation */
+
+ void *sync_aiocb;
+
+ /* 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;
+};
+
+struct BlockDriverAIOCB {
+ BlockDriverState *bs;
+ BlockDriverCompletionFunc *cb;
+ void *opaque;
+ BlockDriverAIOCB *next;
+};
+
+void get_tmp_filename(char *filename, int size);
+
+void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,
+ void *opaque);
+void qemu_aio_release(void *p);
+
+#endif /* BLOCK_INT_H */
Added: trunk/src/host/qemu-neo1973/bswap.h
===================================================================
--- trunk/src/host/qemu-neo1973/bswap.h 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/bswap.h 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,202 @@
+#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 */
Added: trunk/src/host/qemu-neo1973/check_ops.sh
===================================================================
--- trunk/src/host/qemu-neo1973/check_ops.sh 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/check_ops.sh 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,47 @@
+#! /bin/sh
+# Script to check for duplicate function prologues in op.o
+# Typically this indicates missing FORCE_RET();
+# This script does not detect other errors that may be present.
+
+# Usage: check_ops.sh [-m machine] [op.o]
+# machine and op.o are guessed if not specified.
+
+if [ "x$1" = "x-m" ]; then
+ machine=$2
+ shift 2
+else
+ machine=`uname -m`
+fi
+if [ -z "$1" ]; then
+ for f in `find . -name op.o`; do
+ /bin/sh "$0" -m $machine $f
+ done
+ exit 0
+fi
+
+case $machine in
+ i?86)
+ ret='\tret'
+ ;;
+ x86_64)
+ ret='\tretq'
+ ;;
+ arm)
+ ret='\tldm.*pc'
+ ;;
+ ppc* | powerpc*)
+ ret='\tblr'
+ ;;
+ mips*)
+ ret='\tjr.*ra'
+ ;;
+ *)
+ echo "Unknown machine `uname -m`"
+ ;;
+esac
+echo $1
+# op_exit_tb causes false positives on some hosts.
+${CROSS}objdump -dr $1 | \
+ sed -e '/>:$\|'"$ret"'/!d' -e 's/.*<\(.*\)>:/~\1:/' -e 's/.*'"$ret"'.*/!/' | \
+ sed -e ':1;N;s/\n//;t1' | sed -e 's/~/\n/g' | grep -v '^op_exit_tb' | \
+ grep '^op_.*!!'
Property changes on: trunk/src/host/qemu-neo1973/check_ops.sh
___________________________________________________________________
Name: svn:executable
+ *
Added: trunk/src/host/qemu-neo1973/cocoa.m
===================================================================
--- trunk/src/host/qemu-neo1973/cocoa.m 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/cocoa.m 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,927 @@
+/*
+ * 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;
+
+int grab = 0;
+int modifiers_state[256];
+
+/* main defined in qemu/vl.c */
+int qemu_main(int argc, char **argv);
+
+/* To deal with miniaturization */
+ at interface QemuWindow : NSWindow
+{ }
+ at 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
+ ------------------------------------------------------
+*/
+
+int keymap[] =
+{
+// SdlI macI macH SdlH 104xtH 104xtC sdl
+ 30, // 0 0x00 0x1e A QZ_a
+ 31, // 1 0x01 0x1f S QZ_s
+ 32, // 2 0x02 0x20 D QZ_d
+ 33, // 3 0x03 0x21 F QZ_f
+ 35, // 4 0x04 0x23 H QZ_h
+ 34, // 5 0x05 0x22 G QZ_g
+ 44, // 6 0x06 0x2c Z QZ_z
+ 45, // 7 0x07 0x2d X QZ_x
+ 46, // 8 0x08 0x2e C QZ_c
+ 47, // 9 0x09 0x2f V QZ_v
+ 0, // 10 0x0A Undefined
+ 48, // 11 0x0B 0x30 B QZ_b
+ 16, // 12 0x0C 0x10 Q QZ_q
+ 17, // 13 0x0D 0x11 W QZ_w
+ 18, // 14 0x0E 0x12 E QZ_e
+ 19, // 15 0x0F 0x13 R QZ_r
+ 21, // 16 0x10 0x15 Y QZ_y
+ 20, // 17 0x11 0x14 T QZ_t
+ 2, // 18 0x12 0x02 1 QZ_1
+ 3, // 19 0x13 0x03 2 QZ_2
+ 4, // 20 0x14 0x04 3 QZ_3
+ 5, // 21 0x15 0x05 4 QZ_4
+ 7, // 22 0x16 0x07 6 QZ_6
+ 6, // 23 0x17 0x06 5 QZ_5
+ 13, // 24 0x18 0x0d = QZ_EQUALS
+ 10, // 25 0x19 0x0a 9 QZ_9
+ 8, // 26 0x1A 0x08 7 QZ_7
+ 12, // 27 0x1B 0x0c - QZ_MINUS
+ 9, // 28 0x1C 0x09 8 QZ_8
+ 11, // 29 0x1D 0x0b 0 QZ_0
+ 27, // 30 0x1E 0x1b ] QZ_RIGHTBRACKET
+ 24, // 31 0x1F 0x18 O QZ_o
+ 22, // 32 0x20 0x16 U QZ_u
+ 26, // 33 0x21 0x1a [ QZ_LEFTBRACKET
+ 23, // 34 0x22 0x17 I QZ_i
+ 25, // 35 0x23 0x19 P QZ_p
+ 28, // 36 0x24 0x1c ENTER QZ_RETURN
+ 38, // 37 0x25 0x26 L QZ_l
+ 36, // 38 0x26 0x24 J QZ_j
+ 40, // 39 0x27 0x28 ' QZ_QUOTE
+ 37, // 40 0x28 0x25 K QZ_k
+ 39, // 41 0x29 0x27 ; QZ_SEMICOLON
+ 43, // 42 0x2A 0x2b \ QZ_BACKSLASH
+ 51, // 43 0x2B 0x33 , QZ_COMMA
+ 53, // 44 0x2C 0x35 / QZ_SLASH
+ 49, // 45 0x2D 0x31 N QZ_n
+ 50, // 46 0x2E 0x32 M QZ_m
+ 52, // 47 0x2F 0x34 . QZ_PERIOD
+ 15, // 48 0x30 0x0f TAB QZ_TAB
+ 57, // 49 0x31 0x39 SPACE QZ_SPACE
+ 41, // 50 0x32 0x29 ` QZ_BACKQUOTE
+ 14, // 51 0x33 0x0e BKSP QZ_BACKSPACE
+ 0, // 52 0x34 Undefined
+ 1, // 53 0x35 0x01 ESC QZ_ESCAPE
+ 0, // 54 0x36 QZ_RMETA
+ 0, // 55 0x37 QZ_LMETA
+ 42, // 56 0x38 0x2a L SHFT QZ_LSHIFT
+ 58, // 57 0x39 0x3a CAPS QZ_CAPSLOCK
+ 56, // 58 0x3A 0x38 L ALT QZ_LALT
+ 29, // 59 0x3B 0x1d L CTRL QZ_LCTRL
+ 54, // 60 0x3C 0x36 R SHFT QZ_RSHIFT
+ 184,// 61 0x3D 0xb8 E0,38 R ALT QZ_RALT
+ 157,// 62 0x3E 0x9d E0,1D R CTRL QZ_RCTRL
+ 0, // 63 0x3F Undefined
+ 0, // 64 0x40 Undefined
+ 0, // 65 0x41 Undefined
+ 0, // 66 0x42 Undefined
+ 55, // 67 0x43 0x37 KP * QZ_KP_MULTIPLY
+ 0, // 68 0x44 Undefined
+ 78, // 69 0x45 0x4e KP + QZ_KP_PLUS
+ 0, // 70 0x46 Undefined
+ 69, // 71 0x47 0x45 NUM QZ_NUMLOCK
+ 0, // 72 0x48 Undefined
+ 0, // 73 0x49 Undefined
+ 0, // 74 0x4A Undefined
+ 181,// 75 0x4B 0xb5 E0,35 KP / QZ_KP_DIVIDE
+ 152,// 76 0x4C 0x9c E0,1C KP EN QZ_KP_ENTER
+ 0, // 77 0x4D undefined
+ 74, // 78 0x4E 0x4a KP - QZ_KP_MINUS
+ 0, // 79 0x4F Undefined
+ 0, // 80 0x50 Undefined
+ 0, // 81 0x51 QZ_KP_EQUALS
+ 82, // 82 0x52 0x52 KP 0 QZ_KP0
+ 79, // 83 0x53 0x4f KP 1 QZ_KP1
+ 80, // 84 0x54 0x50 KP 2 QZ_KP2
+ 81, // 85 0x55 0x51 KP 3 QZ_KP3
+ 75, // 86 0x56 0x4b KP 4 QZ_KP4
+ 76, // 87 0x57 0x4c KP 5 QZ_KP5
+ 77, // 88 0x58 0x4d KP 6 QZ_KP6
+ 71, // 89 0x59 0x47 KP 7 QZ_KP7
+ 0, // 90 0x5A Undefined
+ 72, // 91 0x5B 0x48 KP 8 QZ_KP8
+ 73, // 92 0x5C 0x49 KP 9 QZ_KP9
+ 0, // 93 0x5D Undefined
+ 0, // 94 0x5E Undefined
+ 0, // 95 0x5F Undefined
+ 63, // 96 0x60 0x3f F5 QZ_F5
+ 64, // 97 0x61 0x40 F6 QZ_F6
+ 65, // 98 0x62 0x41 F7 QZ_F7
+ 61, // 99 0x63 0x3d F3 QZ_F3
+ 66, // 100 0x64 0x42 F8 QZ_F8
+ 67, // 101 0x65 0x43 F9 QZ_F9
+ 0, // 102 0x66 Undefined
+ 87, // 103 0x67 0x57 F11 QZ_F11
+ 0, // 104 0x68 Undefined
+ 183,// 105 0x69 0xb7 QZ_PRINT
+ 0, // 106 0x6A Undefined
+ 70, // 107 0x6B 0x46 SCROLL QZ_SCROLLOCK
+ 0, // 108 0x6C Undefined
+ 68, // 109 0x6D 0x44 F10 QZ_F10
+ 0, // 110 0x6E Undefined
+ 88, // 111 0x6F 0x58 F12 QZ_F12
+ 0, // 112 0x70 Undefined
+ 110,// 113 0x71 0x0 QZ_PAUSE
+ 210,// 114 0x72 0xd2 E0,52 INSERT QZ_INSERT
+ 199,// 115 0x73 0xc7 E0,47 HOME QZ_HOME
+ 201,// 116 0x74 0xc9 E0,49 PG UP QZ_PAGEUP
+ 211,// 117 0x75 0xd3 E0,53 DELETE QZ_DELETE
+ 62, // 118 0x76 0x3e F4 QZ_F4
+ 207,// 119 0x77 0xcf E0,4f END QZ_END
+ 60, // 120 0x78 0x3c F2 QZ_F2
+ 209,// 121 0x79 0xd1 E0,51 PG DN QZ_PAGEDOWN
+ 59, // 122 0x7A 0x3b F1 QZ_F1
+ 203,// 123 0x7B 0xcb e0,4B L ARROW QZ_LEFT
+ 205,// 124 0x7C 0xcd e0,4D R ARROW QZ_RIGHT
+ 208,// 125 0x7D 0xd0 E0,50 D ARROW QZ_DOWN
+ 200,// 126 0x7E 0xc8 E0,48 U ARROW QZ_UP
+/* completed according to http://www.libsdl.org/cgi/cvsweb.cgi/SDL12/src/video/quartz/SDL_QuartzKeys.h?rev=1.6&content-type=text/x-cvsweb-markup */
+
+/* Aditional 104 Key XP-Keyboard Scancodes from http://www.computer-engineering.org/ps2keyboard/scancodes1.html */
+/*
+ 219 // 0xdb e0,5b L GUI
+ 220 // 0xdc e0,5c R GUI
+ 221 // 0xdd e0,5d APPS
+ // E0,2A,E0,37 PRNT SCRN
+ // E1,1D,45,E1,9D,C5 PAUSE
+ 83 // 0x53 0x53 KP .
+// ACPI Scan Codes
+ 222 // 0xde E0, 5E Power
+ 223 // 0xdf E0, 5F Sleep
+ 227 // 0xe3 E0, 63 Wake
+// Windows Multimedia Scan Codes
+ 153 // 0x99 E0, 19 Next Track
+ 144 // 0x90 E0, 10 Previous Track
+ 164 // 0xa4 E0, 24 Stop
+ 162 // 0xa2 E0, 22 Play/Pause
+ 160 // 0xa0 E0, 20 Mute
+ 176 // 0xb0 E0, 30 Volume Up
+ 174 // 0xae E0, 2E Volume Down
+ 237 // 0xed E0, 6D Media Select
+ 236 // 0xec E0, 6C E-Mail
+ 161 // 0xa1 E0, 21 Calculator
+ 235 // 0xeb E0, 6B My Computer
+ 229 // 0xe5 E0, 65 WWW Search
+ 178 // 0xb2 E0, 32 WWW Home
+ 234 // 0xea E0, 6A WWW Back
+ 233 // 0xe9 E0, 69 WWW Forward
+ 232 // 0xe8 E0, 68 WWW Stop
+ 231 // 0xe7 E0, 67 WWW Refresh
+ 230 // 0xe6 E0, 66 WWW Favorites
+*/
+};
+
+int cocoa_keycode_to_qemu(int keycode)
+{
+ if((sizeof(keymap)/sizeof(int)) <= 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;
+
+ pool = [ [ NSAutoreleasePool alloc ] init ];
+ distantPast = [ NSDate distantPast ];
+
+ vga_hw_update();
+
+ do {
+ event = [ NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
+ inMode: NSDefaultRunLoopMode dequeue:YES ];
+ if (event != nil) {
+ switch ([event type]) {
+ case NSFlagsChanged:
+ {
+ int keycode = cocoa_keycode_to_qemu([event keyCode]);
+
+ if (keycode)
+ {
+ if (keycode == 58 || keycode == 69) {
+ /* emulate caps lock and num lock keydown and keyup */
+ kbd_put_keycode(keycode);
+ kbd_put_keycode(keycode | 0x80);
+ } else if (is_graphic_console()) {
+ if (keycode & 0x80)
+ kbd_put_keycode(0xe0);
+ if (modifiers_state[keycode] == 0) {
+ /* keydown */
+ kbd_put_keycode(keycode & 0x7f);
+ modifiers_state[keycode] = 1;
+ } else {
+ /* keyup */
+ kbd_put_keycode(keycode | 0x80);
+ modifiers_state[keycode] = 0;
+ }
+ }
+ }
+
+ /* release Mouse grab when pressing ctrl+alt */
+ if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask))
+ {
+ [window setTitle: @"QEMU"];
+ [NSCursor unhide];
+ CGAssociateMouseAndMouseCursorPosition ( TRUE );
+ grab = 0;
+ }
+ }
+ break;
+
+ case NSKeyDown:
+ {
+ int keycode = cocoa_keycode_to_qemu([event keyCode]);
+
+ /* handle command Key Combos */
+ if ([event modifierFlags] & NSCommandKeyMask) {
+ switch ([event keyCode]) {
+ /* quit */
+ case 12: /* q key */
+ /* switch to windowed View */
+ exit(0);
+ return;
+ }
+ }
+
+ /* handle control + alt Key Combos */
+ if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
+ switch (keycode) {
+ /* toggle Monitor */
+ case 0x02 ... 0x0a: /* '1' to '9' keys */
+ console_select(keycode - 0x02);
+ break;
+ }
+ } else {
+ /* handle standard key events */
+ if (is_graphic_console()) {
+ if (keycode & 0x80) //check bit for e0 in front
+ kbd_put_keycode(0xe0);
+ kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front
+ /* handle monitor key events */
+ } else {
+ int keysym = 0;
+
+ switch([event keyCode]) {
+ case 115:
+ keysym = QEMU_KEY_HOME;
+ break;
+ case 117:
+ keysym = QEMU_KEY_DELETE;
+ break;
+ case 119:
+ keysym = QEMU_KEY_END;
+ break;
+ case 123:
+ keysym = QEMU_KEY_LEFT;
+ break;
+ case 124:
+ keysym = QEMU_KEY_RIGHT;
+ break;
+ case 125:
+ keysym = QEMU_KEY_DOWN;
+ break;
+ case 126:
+ keysym = QEMU_KEY_UP;
+ break;
+ default:
+ {
+ NSString *ks = [event characters];
+
+ if ([ks length] > 0)
+ keysym = [ks characterAtIndex:0];
+ }
+ }
+ if (keysym)
+ kbd_put_keysym(keysym);
+ }
+ }
+ }
+ break;
+
+ case NSKeyUp:
+ {
+ int keycode = cocoa_keycode_to_qemu([event keyCode]);
+ if (is_graphic_console()) {
+ if (keycode & 0x80)
+ kbd_put_keycode(0xe0);
+ kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key
+ }
+ }
+ break;
+
+ case NSMouseMoved:
+ if (grab) {
+ int dx = [event deltaX];
+ int dy = [event deltaY];
+ int dz = [event deltaZ];
+ int buttons = 0;
+ kbd_mouse_event(dx, dy, dz, buttons);
+ }
+ break;
+
+ case NSLeftMouseDown:
+ if (grab) {
+ int buttons = 0;
+
+ /* leftclick+command simulates rightclick */
+ if ([event modifierFlags] & NSCommandKeyMask) {
+ buttons |= MOUSE_EVENT_RBUTTON;
+ } else {
+ buttons |= MOUSE_EVENT_LBUTTON;
+ }
+ kbd_mouse_event(0, 0, 0, buttons);
+ } else {
+ [NSApp sendEvent: event];
+ }
+ break;
+
+ case NSLeftMouseDragged:
+ if (grab) {
+ int dx = [event deltaX];
+ int dy = [event deltaY];
+ int dz = [event deltaZ];
+ int buttons = 0;
+ if ([[NSApp currentEvent] modifierFlags] & NSCommandKeyMask) { //leftclick+command simulates rightclick
+ buttons |= MOUSE_EVENT_RBUTTON;
+ } else {
+ buttons |= MOUSE_EVENT_LBUTTON;
+ }
+ kbd_mouse_event(dx, dy, dz, buttons);
+ }
+ break;
+
+ case NSLeftMouseUp:
+ if (grab) {
+ kbd_mouse_event(0, 0, 0, 0);
+ } else {
+ [window setTitle: @"QEMU (Press ctrl + alt to release Mouse)"];
+ [NSCursor hide];
+ CGAssociateMouseAndMouseCursorPosition ( FALSE );
+ grab = 1;
+ //[NSApp sendEvent: event];
+ }
+ break;
+
+ case NSRightMouseDown:
+ if (grab) {
+ int buttons = 0;
+
+ buttons |= MOUSE_EVENT_RBUTTON;
+ kbd_mouse_event(0, 0, 0, buttons);
+ } else {
+ [NSApp sendEvent: event];
+ }
+ break;
+
+ case NSRightMouseDragged:
+ if (grab) {
+ int dx = [event deltaX];
+ int dy = [event deltaY];
+ int dz = [event deltaZ];
+ int buttons = 0;
+ buttons |= MOUSE_EVENT_RBUTTON;
+ kbd_mouse_event(dx, dy, dz, buttons);
+ }
+ break;
+
+ case NSRightMouseUp:
+ if (grab) {
+ kbd_mouse_event(0, 0, 0, 0);
+ } else {
+ [NSApp sendEvent: event];
+ }
+ break;
+
+ case NSOtherMouseDragged:
+ if (grab) {
+ int dx = [event deltaX];
+ int dy = [event deltaY];
+ int dz = [event deltaZ];
+ int buttons = 0;
+ buttons |= MOUSE_EVENT_MBUTTON;
+ kbd_mouse_event(dx, dy, dz, buttons);
+ }
+ break;
+
+ case NSOtherMouseDown:
+ if (grab) {
+ int buttons = 0;
+ buttons |= MOUSE_EVENT_MBUTTON;
+ kbd_mouse_event(0, 0, 0, buttons);
+ } else {
+ [NSApp sendEvent:event];
+ }
+ break;
+
+ case NSOtherMouseUp:
+ if (grab) {
+ kbd_mouse_event(0, 0, 0, 0);
+ } else {
+ [NSApp sendEvent: event];
+ }
+ break;
+
+ case NSScrollWheel:
+ if (grab) {
+ int dz = [event deltaY];
+ kbd_mouse_event(0, 0, -dz, 0);
+ }
+ break;
+
+ 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;
+ }
+ }
+}
+
+ at 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 ];
+}
+
+ at end
+
+
+/*
+ ------------------------------------------------------
+ QemuCocoaGUIController
+ NSApp's delegate - indeed main object
+ ------------------------------------------------------
+*/
+
+ at 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;
+ at end
+
+ at 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(¤t_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);
+}
+ at 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(void)
+{
+ 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();
+
+ return 0;
+}
Added: trunk/src/host/qemu-neo1973/configure
===================================================================
--- trunk/src/host/qemu-neo1973/configure 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/configure 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,953 @@
+#!/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"
+gcc3_search="yes"
+gcc3_list="gcc-3.4 gcc34 gcc-3.3 gcc33 gcc-3.2 gcc32"
+host_cc="gcc"
+ar="ar"
+make="make"
+install="install"
+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|sun4[muv])
+ 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"
+dsound="no"
+coreaudio="no"
+alsa="no"
+fmod="no"
+fmod_lib=""
+fmod_inc=""
+bsd="no"
+linux="no"
+kqemu="no"
+profiler="no"
+cocoa="no"
+check_gfx="yes"
+check_gcc="yes"
+softmmu="yes"
+user="no"
+build_docs="no"
+uname_release=""
+
+# OS specific
+targetos=`uname -s`
+case $targetos in
+CYGWIN*)
+mingw32="yes"
+OS_CFLAGS="-mno-cygwin"
+;;
+MINGW32*)
+mingw32="yes"
+;;
+FreeBSD)
+bsd="yes"
+oss="yes"
+if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
+ kqemu="yes"
+fi
+;;
+NetBSD)
+bsd="yes"
+oss="yes"
+;;
+OpenBSD)
+bsd="yes"
+oss="yes"
+;;
+Darwin)
+bsd="yes"
+darwin="yes"
+OS_CFLAGS="-mdynamic-no-pic"
+;;
+SunOS)
+solaris="yes"
+;;
+*)
+oss="yes"
+linux="yes"
+user="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
+
+if [ "$solaris" = "yes" ] ; then
+ make="gmake"
+ install="ginstall"
+ solarisrev=`uname -r | cut -f2 -d.`
+fi
+
+if [ "$bsd" = "yes" -o "$solaris" = "yes" -o "$mingw32" = "yes" ] ; then
+ AIOLIBS=
+else
+ AIOLIBS="-lrt"
+fi
+
+# find source path
+source_path=`dirname "$0"`
+if [ -z "$source_path" ]; then
+ source_path=`pwd`
+else
+ source_path=`cd "$source_path"; pwd`
+fi
+if test "$source_path" = `pwd` ; then
+ source_path_used="no"
+else
+ source_path_used="yes"
+fi
+
+for opt do
+ optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
+ case "$opt" in
+ --help|-h) show_help=yes
+ ;;
+ --prefix=*) prefix="$optarg"
+ ;;
+ --interp-prefix=*) interp_prefix="$optarg"
+ ;;
+ --source-path=*) source_path="$optarg"
+ source_path_used="yes"
+ ;;
+ --cross-prefix=*) cross_prefix="$optarg"
+ ;;
+ --cc=*) cc="$optarg"
+ gcc3_search="no"
+ ;;
+ --host-cc=*) host_cc="$optarg"
+ ;;
+ --make=*) make="$optarg"
+ ;;
+ --install=*) install="$optarg"
+ ;;
+ --extra-cflags=*) CFLAGS="$optarg"
+ ;;
+ --extra-ldflags=*) LDFLAGS="$optarg"
+ ;;
+ --cpu=*) cpu="$optarg"
+ ;;
+ --target-list=*) target_list="$optarg"
+ ;;
+ --enable-gprof) gprof="yes"
+ ;;
+ --static) static="yes"
+ ;;
+ --disable-sdl) sdl="no"
+ ;;
+ --enable-coreaudio) coreaudio="yes"
+ ;;
+ --enable-alsa) alsa="yes"
+ ;;
+ --enable-dsound) dsound="yes"
+ ;;
+ --enable-fmod) fmod="yes"
+ ;;
+ --fmod-lib=*) fmod_lib="$optarg"
+ ;;
+ --fmod-inc=*) fmod_inc="$optarg"
+ ;;
+ --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; user="no"
+ ;;
+ --disable-slirp) slirp="no"
+ ;;
+ --enable-adlib) adlib="yes"
+ ;;
+ --disable-kqemu) kqemu="no"
+ ;;
+ --enable-profiler) profiler="yes"
+ ;;
+ --enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no"
+ ;;
+ --disable-gfx-check) check_gfx="no"
+ ;;
+ --disable-gcc-check) check_gcc="no"
+ ;;
+ --disable-system) softmmu="no"
+ ;;
+ --enable-system) softmmu="yes"
+ ;;
+ --disable-user) user="no"
+ ;;
+ --enable-user) user="yes"
+ ;;
+ --enable-uname-release=*) uname_release="$optarg"
+ ;;
+ esac
+done
+
+# default flags for all hosts
+CFLAGS="$CFLAGS -Wall -O2 -g -fno-strict-aliasing"
+LDFLAGS="$LDFLAGS -g"
+
+if test x"$show_help" = x"yes" ; 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 support"
+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 [$host_cc] for dyngen etc."
+echo " --make=MAKE use specified make [$make]"
+echo " --install=INSTALL use specified install [$install]"
+echo " --static enable static build [$static]"
+echo " --enable-cocoa enable COCOA (Mac OS X only)"
+echo " --enable-mingw32 enable Win32 cross compilation with mingw32"
+echo " --enable-adlib enable Adlib emulation"
+echo " --enable-coreaudio enable Coreaudio audio driver"
+echo " --enable-alsa enable ALSA audio driver"
+echo " --enable-fmod enable FMOD audio driver"
+echo " --enabled-dsound enable DirectSound audio driver"
+echo " --enable-system enable all system emulation targets"
+echo " --disable-system disable all system emulation targets"
+echo " --enable-user enable all linux usermode emulation targets"
+echo " --disable-user disable all linux usermode emulation targets"
+echo " --fmod-lib path to FMOD library"
+echo " --fmod-inc path to FMOD includes"
+echo " --enable-uname-release=R Return R for uname -r in usermode emulation"
+echo ""
+echo "NOTE: The object files are built at the place where configure is launched"
+exit 1
+fi
+
+cc="${cross_prefix}${cc}"
+ar="${cross_prefix}${ar}"
+strip="${cross_prefix}${strip}"
+
+# check that the C compiler works.
+cat > $TMPC <<EOF
+int main(void) {}
+EOF
+
+if $cc -c -o $TMPO $TMPC 2>/dev/null ; then
+ : C compiler works ok
+else
+ echo "ERROR: \"$cc\" either does not exist or does not work"
+ exit 1
+fi
+
+if test "$mingw32" = "yes" ; then
+ linux="no"
+ EXESUF=".exe"
+ oss="no"
+ if [ "$cpu" = "i386" ] ; then
+ kqemu="yes"
+ fi
+fi
+
+# Check for gcc4, error if pre-gcc4
+if test "$check_gcc" = "yes" ; then
+ cat > $TMPC <<EOF
+#if __GNUC__ < 4
+#error gcc3
+#endif
+int main(){return 0;}
+EOF
+ check_cc() {
+ which "$1" >&/dev/null
+ return $?
+ }
+
+ if "$cc" -o $TMPE $TMPC 2>/dev/null ; then
+ echo "WARNING: \"$cc\" looks like gcc 4.x"
+ found_compat_cc="no"
+ if test "$gcc3_search" = "yes" ; then
+ echo "Looking for gcc 3.x"
+ for compat_cc in $gcc3_list ; do
+ if check_cc "$compat_cc" ; then
+ echo "Found \"$compat_cc\""
+ cc="$compat_cc"
+ found_compat_cc="yes"
+ break
+ fi
+ done
+ if test "$found_compat_cc" = "no" ; then
+ echo "gcc 3.x not found!"
+ fi
+ fi
+ if test "$found_compat_cc" = "no" ; then
+ echo "QEMU is known to have problems when compiled with gcc 4.x"
+ echo "It is recommended that you use gcc 3.x to build QEMU"
+ echo "To use this compiler anyway, configure with --disable-gcc-check"
+ exit 1;
+ fi
+ fi
+fi
+
+#
+# Solaris specific configure tool chain decisions
+#
+if test "$solaris" = "yes" ; then
+ #
+ # gcc for solaris 10/fcs in /usr/sfw/bin doesn't compile qemu correctly
+ # override the check with --disable-gcc-check
+ #
+ if test "$solarisrev" -eq 10 -a "$check_gcc" = "yes" ; then
+ solgcc=`which $cc`
+ if test "$solgcc" = "/usr/sfw/bin/gcc" ; then
+ echo "Solaris 10/FCS gcc in /usr/sfw/bin will not compiled qemu correctly."
+ echo "please get gcc-3.4.3 or later, from www.blastwave.org using pkg-get -i gcc3"
+ echo "or get the latest patch from SunSolve for gcc"
+ exit 1
+ fi
+ fi
+ solinst=`which $install 2> /dev/null | /usr/bin/grep -v "no $install in"`
+ if test -z "$solinst" ; then
+ echo "Solaris install program not found. Use --install=/usr/ucb/install or"
+ echo "install fileutils from www.blastwave.org using pkg-get -i fileutils"
+ echo "to get ginstall which is used by default (which lives in /opt/csw/bin)"
+ exit 1
+ fi
+ if test "$solinst" = "/usr/sbin/install" ; then
+ echo "Error: Solaris /usr/sbin/install is not an appropriate install program."
+ echo "try ginstall from the GNU fileutils available from www.blastwave.org"
+ echo "using pkg-get -i fileutils, or use --install=/usr/ucb/install"
+ exit 1
+ fi
+ sol_ar=`which ar 2> /dev/null | /usr/bin/grep -v "no ar in"`
+ if test -z "$sol_ar" ; then
+ echo "Error: No path includes ar"
+ if test -f /usr/ccs/bin/ar ; then
+ echo "Add /usr/ccs/bin to your path and rerun configure"
+ fi
+ exit 1
+ fi
+fi
+
+
+if test -z "$target_list" ; then
+# these targets are portable
+ if [ "$softmmu" = "yes" ] ; then
+ target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu arm-softmmu"
+ fi
+# the following are Linux specific
+ if [ "$user" = "yes" ] ; then
+ target_list="i386-user arm-user armeb-user sparc-user ppc-user mips-user mipsel-user m68k-user $target_list"
+ fi
+else
+ target_list=`echo "$target_list" | sed -e 's/,/ /g'`
+fi
+if test -z "$target_list" ; then
+ echo "No targets enabled"
+ exit 1
+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
+
+##########################################
+# alsa sound support libraries
+
+if test "$alsa" = "yes" ; then
+ cat > $TMPC << EOF
+#include <alsa/asoundlib.h>
+int main(void) { snd_pcm_t **handle; return snd_pcm_close(*handle); }
+EOF
+ if $cc -o $TMPE $TMPC -lasound 2> /dev/null ; then
+ :
+ else
+ echo
+ echo "Error: Could not find alsa"
+ echo "Make sure to have the alsa libs and headers installed."
+ echo
+ exit 1
+ fi
+fi
+
+# Check if tools are available to build documentation.
+if [ -x "`which texi2html`" ] && [ -x "`which pod2man`" ]; then
+ build_docs="yes"
+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
+
+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 "install $install"
+echo "host CPU $cpu"
+echo "host big endian $bigendian"
+echo "target list $target_list"
+echo "gprof enabled $gprof"
+echo "profiler $profiler"
+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 "CoreAudio support $coreaudio"
+echo "ALSA support $alsa"
+echo "DSound support $dsound"
+if test "$fmod" = "yes"; then
+ if test -z $fmod_lib || test -z $fmod_inc; then
+ echo
+ echo "Error: You must specify path to FMOD library and headers"
+ echo "Example: --fmod-inc=/path/include/fmod --fmod-lib=/path/lib/libfmod-3.74.so"
+ echo
+ exit 1
+ fi
+ fmod_support=" (lib='$fmod_lib' include='$fmod_inc')"
+else
+ fmod_support=""
+fi
+echo "FMOD support $fmod $fmod_support"
+echo "kqemu support $kqemu"
+echo "Documentation $build_docs"
+[ ! -z "$uname_release" ] && \
+echo "uname -r $uname_release"
+
+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 "# Configured with: $0 $@" >> $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 "INSTALL=$install" >> $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 "OS_CFLAGS=$OS_CFLAGS" >> $config_mak
+echo "CFLAGS=$CFLAGS" >> $config_mak
+echo "LDFLAGS=$LDFLAGS" >> $config_mak
+echo "EXESUF=$EXESUF" >> $config_mak
+echo "AIOLIBS=$AIOLIBS" >> $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 "$solaris" = "yes" ; then
+ echo "CONFIG_SOLARIS=yes" >> $config_mak
+ echo "#define HOST_SOLARIS $solarisrev" >> $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 $profiler = "yes" ; then
+ echo "#define CONFIG_PROFILER 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 "$coreaudio" = "yes" ; then
+ echo "CONFIG_COREAUDIO=yes" >> $config_mak
+ echo "#define CONFIG_COREAUDIO 1" >> $config_h
+fi
+if test "$alsa" = "yes" ; then
+ echo "CONFIG_ALSA=yes" >> $config_mak
+ echo "#define CONFIG_ALSA 1" >> $config_h
+fi
+if test "$dsound" = "yes" ; then
+ echo "CONFIG_DSOUND=yes" >> $config_mak
+ echo "#define CONFIG_DSOUND 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
+qemu_version=`head $source_path/VERSION`
+echo "VERSION=$qemu_version" >>$config_mak
+echo "#define QEMU_VERSION \"$qemu_version\"" >> $config_h
+
+echo "SRC_PATH=$source_path" >> $config_mak
+if [ "$source_path_used" = "yes" ]; then
+ echo "VPATH=$source_path" >> $config_mak
+fi
+echo "TARGET_DIRS=$target_list" >> $config_mak
+if [ "$build_docs" = "yes" ] ; then
+ echo "BUILD_DOCS=yes" >> $config_mak
+fi
+
+# 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
+
+echo "#define CONFIG_UNAME_RELEASE \"$uname_release\"" >> $config_h
+
+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_cpu" = "sh4eb" ] && target_bigendian=yes
+[ "$target_cpu" = "m68k" ] && 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 without 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
+
+#
+# don't use ln -sf as not all "ln -sf" over write the file/link
+#
+rm -f $target_dir/Makefile
+ln -s $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
+
+bflt="no"
+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
+ bflt="yes"
+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" -o "$target_cpu" = "mipsel" ; then
+ echo "TARGET_ARCH=mips" >> $config_mak
+ echo "#define TARGET_ARCH \"mips\"" >> $config_h
+ echo "#define TARGET_MIPS 1" >> $config_h
+ echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
+ echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
+elif test "$target_cpu" = "sh4" -o "$target_cpu" = "sh4eb" ; then
+ echo "TARGET_ARCH=sh4" >> $config_mak
+ echo "#define TARGET_ARCH \"sh4\"" >> $config_h
+ echo "#define TARGET_SH4 1" >> $config_h
+ bflt="yes"
+elif test "$target_cpu" = "m68k" ; then
+ echo "TARGET_ARCH=m68k" >> $config_mak
+ echo "#define TARGET_ARCH \"m68k\"" >> $config_h
+ echo "#define TARGET_M68K 1" >> $config_h
+ bflt="yes"
+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" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64" -o "$target_cpu" = "m68k"; then
+ echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
+ echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
+fi
+if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then
+ echo "TARGET_HAS_BFLT=yes" >> $config_mak
+ echo "#define TARGET_HAS_BFLT 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
+ if [ "${aa}" = "yes" ] ; then
+ echo "SDL_CFLAGS=`$sdl_config --cflags` `aalib-config --cflags`" >> $config_mak
+ else
+ echo "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak
+ fi
+ 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
+ # remove the link and recreate it, as not all "ln -sf" overwrite the link
+ for f in $FILES ; do
+ rm -f $f
+ ln -s $source_path/$f $f
+ done
+fi
+
+rm -f $TMPO $TMPC $TMPE $TMPS
Property changes on: trunk/src/host/qemu-neo1973/configure
___________________________________________________________________
Name: svn:executable
+ *
Added: trunk/src/host/qemu-neo1973/console.c
===================================================================
--- trunk/src/host/qemu-neo1973/console.c 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/console.c 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,1092 @@
+/*
+ * 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 DEBUG_CONSOLE
+#define DEFAULT_BACKSCROLL 512
+#define MAX_CONSOLES 12
+
+#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
+#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
+
+typedef struct TextAttributes {
+ uint8_t fgcol:4;
+ uint8_t bgcol:4;
+ uint8_t bold:1;
+ uint8_t uline:1;
+ uint8_t blink:1;
+ uint8_t invers:1;
+ uint8_t unvisible:1;
+} TextAttributes;
+
+typedef struct TextCell {
+ uint8_t ch;
+ TextAttributes t_attrib;
+} TextCell;
+
+#define MAX_ESC_PARAMS 3
+
+enum TTYState {
+ TTY_STATE_NORM,
+ TTY_STATE_ESC,
+ TTY_STATE_CSI,
+};
+
+typedef struct QEMUFIFO {
+ uint8_t *buf;
+ int buf_size;
+ int count, wptr, rptr;
+} QEMUFIFO;
+
+int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
+{
+ int l, len;
+
+ l = f->buf_size - f->count;
+ if (len1 > l)
+ len1 = l;
+ len = len1;
+ while (len > 0) {
+ l = f->buf_size - f->wptr;
+ if (l > len)
+ l = len;
+ memcpy(f->buf + f->wptr, buf, l);
+ f->wptr += l;
+ if (f->wptr >= f->buf_size)
+ f->wptr = 0;
+ buf += l;
+ len -= l;
+ }
+ f->count += len1;
+ return len1;
+}
+
+int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
+{
+ int l, len;
+
+ if (len1 > f->count)
+ len1 = f->count;
+ len = len1;
+ while (len > 0) {
+ l = f->buf_size - f->rptr;
+ if (l > len)
+ l = len;
+ memcpy(buf, f->buf + f->rptr, l);
+ f->rptr += l;
+ if (f->rptr >= f->buf_size)
+ f->rptr = 0;
+ buf += l;
+ len -= l;
+ }
+ f->count -= len1;
+ return len1;
+}
+
+/* ??? This is mis-named.
+ It is used for both text and graphical consoles. */
+struct TextConsole {
+ int text_console; /* true if text console */
+ DisplayState *ds;
+ /* Graphic console state. */
+ vga_hw_update_ptr hw_update;
+ vga_hw_invalidate_ptr hw_invalidate;
+ vga_hw_screen_dump_ptr hw_screen_dump;
+ void *hw;
+
+ int g_width, g_height;
+ int width;
+ int height;
+ int total_height;
+ int backscroll_height;
+ int x, y;
+ int y_displayed;
+ int y_base;
+ TextAttributes t_attrib_default; /* default text attributes */
+ TextAttributes t_attrib; /* currently active text attributes */
+ TextCell *cells;
+
+ enum TTYState state;
+ int esc_params[MAX_ESC_PARAMS];
+ int nb_esc_params;
+
+ /* kbd read handler */
+ IOCanRWHandler *fd_can_read;
+ IOReadHandler *fd_read;
+ void *fd_opaque;
+ /* fifo for key pressed */
+ QEMUFIFO out_fifo;
+ uint8_t out_fifo_buf[16];
+ QEMUTimer *kbd_timer;
+};
+
+static TextConsole *active_console;
+static TextConsole *consoles[MAX_CONSOLES];
+static int nb_consoles = 0;
+
+void vga_hw_update(void)
+{
+ if (active_console->hw_update)
+ active_console->hw_update(active_console->hw);
+}
+
+void vga_hw_invalidate(void)
+{
+ if (active_console->hw_invalidate)
+ active_console->hw_invalidate(active_console->hw);
+}
+
+void vga_hw_screen_dump(const char *filename)
+{
+ /* There is currently no was of specifying which screen we want to dump,
+ so always dump the dirst one. */
+ if (consoles[0]->hw_screen_dump)
+ consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
+}
+
+/* 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[2][8];
+
+enum color_names {
+ COLOR_BLACK = 0,
+ COLOR_RED = 1,
+ COLOR_GREEN = 2,
+ COLOR_YELLOW = 3,
+ COLOR_BLUE = 4,
+ COLOR_MAGENTA = 5,
+ COLOR_CYAN = 6,
+ COLOR_WHITE = 7
+};
+
+static const uint32_t color_table_rgb[2][8] = {
+ { /* dark */
+ QEMU_RGB(0x00, 0x00, 0x00), /* black */
+ QEMU_RGB(0xaa, 0x00, 0x00), /* red */
+ QEMU_RGB(0x00, 0xaa, 0x00), /* green */
+ QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
+ QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
+ QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
+ QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
+ QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
+ },
+ { /* bright */
+ QEMU_RGB(0x00, 0x00, 0x00), /* black */
+ QEMU_RGB(0xff, 0x00, 0x00), /* red */
+ QEMU_RGB(0x00, 0xff, 0x00), /* green */
+ QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
+ QEMU_RGB(0x00, 0x00, 0xff), /* blue */
+ QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
+ QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
+ QEMU_RGB(0xff, 0xff, 0xff), /* white */
+ }
+};
+
+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;
+}
+#ifdef DEBUG_CONSOLE
+static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
+{
+ if (t_attrib->bold) {
+ printf("b");
+ } else {
+ printf(" ");
+ }
+ if (t_attrib->uline) {
+ printf("u");
+ } else {
+ printf(" ");
+ }
+ if (t_attrib->blink) {
+ printf("l");
+ } else {
+ printf(" ");
+ }
+ if (t_attrib->invers) {
+ printf("i");
+ } else {
+ printf(" ");
+ }
+ if (t_attrib->unvisible) {
+ printf("n");
+ } else {
+ printf(" ");
+ }
+
+ printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
+}
+#endif
+
+static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
+ TextAttributes *t_attrib)
+{
+ uint8_t *d;
+ const uint8_t *font_ptr;
+ unsigned int font_data, linesize, xorcol, bpp;
+ int i;
+ unsigned int fgcol, bgcol;
+
+#ifdef DEBUG_CONSOLE
+ printf("x: %2i y: %2i", x, y);
+ console_print_text_attributes(t_attrib, ch);
+#endif
+
+ if (t_attrib->invers) {
+ bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
+ fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
+ } else {
+ fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
+ bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
+ }
+
+ 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++;
+ if (t_attrib->uline
+ && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
+ font_data = 0xFFFF;
+ }
+ ((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++;
+ if (t_attrib->uline
+ && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
+ font_data = 0xFFFF;
+ }
+ ((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++;
+ if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
+ font_data = 0xFFFF;
+ }
+ ((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->t_attrib = s->t_attrib_default;
+ 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,
+ &(c->t_attrib));
+ 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) {
+ TextAttributes t_attrib = s->t_attrib_default;
+ t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
+ vga_putcharxy(s->ds, s->x, y, c->ch, &t_attrib);
+ } else {
+ vga_putcharxy(s->ds, s->x, y, c->ch,
+ &(c->t_attrib));
+ }
+ 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][COLOR_BLACK]);
+ 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,
+ &(c->t_attrib));
+ 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->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->t_attrib = s->t_attrib_default;
+ 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[0][s->t_attrib_default.bgcol]);
+ dpy_update(s->ds, 0, 0,
+ s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
+ }
+ }
+}
+
+/* Set console attributes depending on the current escape codes.
+ * NOTE: I know this code is not very efficient (checking every color for it
+ * self) but it is more readable and better maintainable.
+ */
+static void console_handle_escape(TextConsole *s)
+{
+ int i;
+
+ if (s->nb_esc_params == 0) { /* ESC[m sets all attributes to default */
+ s->t_attrib = s->t_attrib_default;
+ return;
+ }
+ for (i=0; i<s->nb_esc_params; i++) {
+ switch (s->esc_params[i]) {
+ case 0: /* reset all console attributes to default */
+ s->t_attrib = s->t_attrib_default;
+ break;
+ case 1:
+ s->t_attrib.bold = 1;
+ break;
+ case 4:
+ s->t_attrib.uline = 1;
+ break;
+ case 5:
+ s->t_attrib.blink = 1;
+ break;
+ case 7:
+ s->t_attrib.invers = 1;
+ break;
+ case 8:
+ s->t_attrib.unvisible = 1;
+ break;
+ case 22:
+ s->t_attrib.bold = 0;
+ break;
+ case 24:
+ s->t_attrib.uline = 0;
+ break;
+ case 25:
+ s->t_attrib.blink = 0;
+ break;
+ case 27:
+ s->t_attrib.invers = 0;
+ break;
+ case 28:
+ s->t_attrib.unvisible = 0;
+ break;
+ /* set foreground color */
+ case 30:
+ s->t_attrib.fgcol=COLOR_BLACK;
+ break;
+ case 31:
+ s->t_attrib.fgcol=COLOR_RED;
+ break;
+ case 32:
+ s->t_attrib.fgcol=COLOR_GREEN;
+ break;
+ case 33:
+ s->t_attrib.fgcol=COLOR_YELLOW;
+ break;
+ case 34:
+ s->t_attrib.fgcol=COLOR_BLUE;
+ break;
+ case 35:
+ s->t_attrib.fgcol=COLOR_MAGENTA;
+ break;
+ case 36:
+ s->t_attrib.fgcol=COLOR_CYAN;
+ break;
+ case 37:
+ s->t_attrib.fgcol=COLOR_WHITE;
+ break;
+ /* set background color */
+ case 40:
+ s->t_attrib.bgcol=COLOR_BLACK;
+ break;
+ case 41:
+ s->t_attrib.bgcol=COLOR_RED;
+ break;
+ case 42:
+ s->t_attrib.bgcol=COLOR_GREEN;
+ break;
+ case 43:
+ s->t_attrib.bgcol=COLOR_YELLOW;
+ break;
+ case 44:
+ s->t_attrib.bgcol=COLOR_BLUE;
+ break;
+ case 45:
+ s->t_attrib.bgcol=COLOR_MAGENTA;
+ break;
+ case 46:
+ s->t_attrib.bgcol=COLOR_CYAN;
+ break;
+ case 47:
+ s->t_attrib.bgcol=COLOR_WHITE;
+ break;
+ }
+ }
+}
+
+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': /* carriage return */
+ s->x = 0;
+ break;
+ case '\n': /* newline */
+ console_put_lf(s);
+ break;
+ case '\b': /* backspace */
+ if (s->x > 0)
+ s->x--;
+ break;
+ case '\t': /* tabspace */
+ if (s->x + (8 - (s->x % 8)) > s->width) {
+ s->x = 0;
+ console_put_lf(s);
+ } else {
+ s->x = s->x + (8 - (s->x % 8));
+ }
+ break;
+ case '\a': /* alert aka. bell */
+ /* TODO: has to be implemented */
+ break;
+ case 27: /* esc (introducing an escape sequence) */
+ 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->t_attrib = s->t_attrib;
+ update_xy(s, s->x, s->y);
+ s->x++;
+ if (s->x >= s->width) {
+ s->x = 0;
+ console_put_lf(s);
+ }
+ break;
+ }
+ break;
+ case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
+ 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: /* handle escape sequence parameters */
+ 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->t_attrib = s->t_attrib_default;
+ c++;
+ update_xy(s, x, s->y);
+ }
+ break;
+ default:
+ break;
+ }
+ console_handle_escape(s);
+ 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);
+ } else {
+ vga_hw_invalidate();
+ }
+ }
+}
+
+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_can_read = fd_can_read;
+ 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;
+ }
+ }
+ }
+}
+
+static void kbd_send_chars(void *opaque)
+{
+ TextConsole *s = opaque;
+ int len;
+ uint8_t buf[16];
+
+ len = s->fd_can_read(s->fd_opaque);
+ if (len > s->out_fifo.count)
+ len = s->out_fifo.count;
+ if (len > 0) {
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+ qemu_fifo_read(&s->out_fifo, buf, len);
+ s->fd_read(s->fd_opaque, buf, len);
+ }
+ /* characters are pending: we send them a bit later (XXX:
+ horrible, should change char device API) */
+ if (s->out_fifo.count > 0) {
+ qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
+ }
+}
+
+/* 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:
+ /* 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;
+ }
+ if (s->fd_read) {
+ qemu_fifo_write(&s->out_fifo, buf, q - buf);
+ kbd_send_chars(s);
+ }
+ break;
+ }
+}
+
+static TextConsole *new_console(DisplayState *ds, int text)
+{
+ TextConsole *s;
+ int i;
+
+ if (nb_consoles >= MAX_CONSOLES)
+ return NULL;
+ s = qemu_mallocz(sizeof(TextConsole));
+ if (!s) {
+ return NULL;
+ }
+ if (!active_console || (active_console->text_console && !text))
+ active_console = s;
+ s->ds = ds;
+ s->text_console = text;
+ if (text) {
+ consoles[nb_consoles++] = s;
+ } else {
+ /* HACK: Put graphical consoles before text consoles. */
+ for (i = nb_consoles; i > 0; i--) {
+ if (!consoles[i - 1]->text_console)
+ break;
+ consoles[i] = consoles[i - 1];
+ }
+ consoles[i] = s;
+ }
+ return s;
+}
+
+TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
+ vga_hw_invalidate_ptr invalidate,
+ vga_hw_screen_dump_ptr screen_dump,
+ void *opaque)
+{
+ TextConsole *s;
+
+ s = new_console(ds, 0);
+ if (!s)
+ return NULL;
+ s->hw_update = update;
+ s->hw_invalidate = invalidate;
+ s->hw_screen_dump = screen_dump;
+ s->hw = opaque;
+ return s;
+}
+
+int is_graphic_console(void)
+{
+ return !active_console->text_console;
+}
+
+CharDriverState *text_console_init(DisplayState *ds)
+{
+ CharDriverState *chr;
+ TextConsole *s;
+ int i,j;
+ static int color_inited;
+
+ chr = qemu_mallocz(sizeof(CharDriverState));
+ if (!chr)
+ return NULL;
+ s = new_console(ds, 1);
+ if (!s) {
+ free(chr);
+ return NULL;
+ }
+ 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;
+
+ s->out_fifo.buf = s->out_fifo_buf;
+ s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
+ s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
+
+ if (!color_inited) {
+ color_inited = 1;
+ for(j = 0; j < 2; j++) {
+ for(i = 0; i < 8; i++) {
+ color_table[j][i] = col_expand(s->ds,
+ vga_get_color(s->ds, color_table_rgb[j][i]));
+ }
+ }
+ }
+ s->y_displayed = 0;
+ s->y_base = 0;
+ s->total_height = DEFAULT_BACKSCROLL;
+ s->x = 0;
+ s->y = 0;
+ s->g_width = s->ds->width;
+ s->g_height = s->ds->height;
+
+ /* Set text attribute defaults */
+ s->t_attrib_default.bold = 0;
+ s->t_attrib_default.uline = 0;
+ s->t_attrib_default.blink = 0;
+ s->t_attrib_default.invers = 0;
+ s->t_attrib_default.unvisible = 0;
+ s->t_attrib_default.fgcol = COLOR_WHITE;
+ s->t_attrib_default.bgcol = COLOR_BLACK;
+
+ /* set current text attributes to default */
+ s->t_attrib = s->t_attrib_default;
+ text_console_resize(s);
+
+ qemu_chr_reset(chr);
+
+ return chr;
+}
Added: trunk/src/host/qemu-neo1973/cpu-all.h
===================================================================
--- trunk/src/host/qemu-neo1973/cpu-all.h 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/cpu-all.h 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,1033 @@
+/*
+ * 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(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
+
+/* conservative code for little endian unaligned accesses */
+static inline int lduw_le_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_le_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_le_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_le_p(void *ptr)
+{
+ uint8_t *p = ptr;
+ uint32_t v1, v2;
+ v1 = ldl_le_p(p);
+ v2 = ldl_le_p(p + 4);
+ return v1 | ((uint64_t)v2 << 32);
+}
+
+static inline void stw_le_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_le_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_le_p(void *ptr, uint64_t v)
+{
+ uint8_t *p = ptr;
+ stl_le_p(p, (uint32_t)v);
+ stl_le_p(p + 4, v >> 32);
+}
+
+/* float access */
+
+static inline float32 ldfl_le_p(void *ptr)
+{
+ union {
+ float32 f;
+ uint32_t i;
+ } u;
+ u.i = ldl_le_p(ptr);
+ return u.f;
+}
+
+static inline void stfl_le_p(void *ptr, float32 v)
+{
+ union {
+ float32 f;
+ uint32_t i;
+ } u;
+ u.f = v;
+ stl_le_p(ptr, u.i);
+}
+
+static inline float64 ldfq_le_p(void *ptr)
+{
+ CPU_DoubleU u;
+ u.l.lower = ldl_le_p(ptr);
+ u.l.upper = ldl_le_p(ptr + 4);
+ return u.d;
+}
+
+static inline void stfq_le_p(void *ptr, float64 v)
+{
+ CPU_DoubleU u;
+ u.d = v;
+ stl_le_p(ptr, u.l.lower);
+ stl_le_p(ptr + 4, u.l.upper);
+}
+
+#else
+
+static inline int lduw_le_p(void *ptr)
+{
+ return *(uint16_t *)ptr;
+}
+
+static inline int ldsw_le_p(void *ptr)
+{
+ return *(int16_t *)ptr;
+}
+
+static inline int ldl_le_p(void *ptr)
+{
+ return *(uint32_t *)ptr;
+}
+
+static inline uint64_t ldq_le_p(void *ptr)
+{
+ return *(uint64_t *)ptr;
+}
+
+static inline void stw_le_p(void *ptr, int v)
+{
+ *(uint16_t *)ptr = v;
+}
+
+static inline void stl_le_p(void *ptr, int v)
+{
+ *(uint32_t *)ptr = v;
+}
+
+static inline void stq_le_p(void *ptr, uint64_t v)
+{
+ *(uint64_t *)ptr = v;
+}
+
+/* float access */
+
+static inline float32 ldfl_le_p(void *ptr)
+{
+ return *(float32 *)ptr;
+}
+
+static inline float64 ldfq_le_p(void *ptr)
+{
+ return *(float64 *)ptr;
+}
+
+static inline void stfl_le_p(void *ptr, float32 v)
+{
+ *(float32 *)ptr = v;
+}
+
+static inline void stfq_le_p(void *ptr, float64 v)
+{
+ *(float64 *)ptr = v;
+}
+#endif
+
+#if !defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
+
+static inline int lduw_be_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_be_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_be_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_be_p(void *ptr)
+{
+ uint32_t a,b;
+ a = ldl_be_p(ptr);
+ b = ldl_be_p(ptr+4);
+ return (((uint64_t)a<<32)|b);
+}
+
+static inline void stw_be_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_be_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_be_p(void *ptr, uint64_t v)
+{
+ stl_be_p(ptr, v >> 32);
+ stl_be_p(ptr + 4, v);
+}
+
+/* float access */
+
+static inline float32 ldfl_be_p(void *ptr)
+{
+ union {
+ float32 f;
+ uint32_t i;
+ } u;
+ u.i = ldl_be_p(ptr);
+ return u.f;
+}
+
+static inline void stfl_be_p(void *ptr, float32 v)
+{
+ union {
+ float32 f;
+ uint32_t i;
+ } u;
+ u.f = v;
+ stl_be_p(ptr, u.i);
+}
+
+static inline float64 ldfq_be_p(void *ptr)
+{
+ CPU_DoubleU u;
+ u.l.upper = ldl_be_p(ptr);
+ u.l.lower = ldl_be_p(ptr + 4);
+ return u.d;
+}
+
+static inline void stfq_be_p(void *ptr, float64 v)
+{
+ CPU_DoubleU u;
+ u.d = v;
+ stl_be_p(ptr, u.l.upper);
+ stl_be_p(ptr + 4, u.l.lower);
+}
+
+#else
+
+static inline int lduw_be_p(void *ptr)
+{
+ return *(uint16_t *)ptr;
+}
+
+static inline int ldsw_be_p(void *ptr)
+{
+ return *(int16_t *)ptr;
+}
+
+static inline int ldl_be_p(void *ptr)
+{
+ return *(uint32_t *)ptr;
+}
+
+static inline uint64_t ldq_be_p(void *ptr)
+{
+ return *(uint64_t *)ptr;
+}
+
+static inline void stw_be_p(void *ptr, int v)
+{
+ *(uint16_t *)ptr = v;
+}
+
+static inline void stl_be_p(void *ptr, int v)
+{
+ *(uint32_t *)ptr = v;
+}
+
+static inline void stq_be_p(void *ptr, uint64_t v)
+{
+ *(uint64_t *)ptr = v;
+}
+
+/* float access */
+
+static inline float32 ldfl_be_p(void *ptr)
+{
+ return *(float32 *)ptr;
+}
+
+static inline float64 ldfq_be_p(void *ptr)
+{
+ return *(float64 *)ptr;
+}
+
+static inline void stfl_be_p(void *ptr, float32 v)
+{
+ *(float32 *)ptr = v;
+}
+
+static inline void stfq_be_p(void *ptr, float64 v)
+{
+ *(float64 *)ptr = v;
+}
+
+#endif
+
+/* target CPU memory access functions */
+#if defined(TARGET_WORDS_BIGENDIAN)
+#define lduw_p(p) lduw_be_p(p)
+#define ldsw_p(p) ldsw_be_p(p)
+#define ldl_p(p) ldl_be_p(p)
+#define ldq_p(p) ldq_be_p(p)
+#define ldfl_p(p) ldfl_be_p(p)
+#define ldfq_p(p) ldfq_be_p(p)
+#define stw_p(p, v) stw_be_p(p, v)
+#define stl_p(p, v) stl_be_p(p, v)
+#define stq_p(p, v) stq_be_p(p, v)
+#define stfl_p(p, v) stfl_be_p(p, v)
+#define stfq_p(p, v) stfq_be_p(p, v)
+#else
+#define lduw_p(p) lduw_le_p(p)
+#define ldsw_p(p) ldsw_le_p(p)
+#define ldl_p(p) ldl_le_p(p)
+#define ldq_p(p) ldq_le_p(p)
+#define ldfl_p(p) ldfl_le_p(p)
+#define ldfq_p(p) ldfq_le_p(p)
+#define stw_p(p, v) stw_le_p(p, v)
+#define stl_p(p, v) stl_le_p(p, v)
+#define stq_p(p, v) stq_le_p(p, v)
+#define stfl_p(p, v) stfl_le_p(p, v)
+#define stfq_p(p, v) stfq_le_p(p, v)
+#endif
+
+/* MMU memory access macros */
+
+#if defined(CONFIG_USER_ONLY)
+/* On some host systems the guest address space is reserved on the host.
+ * This allows the guest address space to be offset to a convenient location.
+ */
+//#define GUEST_BASE 0x20000000
+#define GUEST_BASE 0
+
+/* All direct uses of g2h and h2g need to go away for usermode softmmu. */
+#define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE))
+#define h2g(x) ((target_ulong)(x - GUEST_BASE))
+
+#define saddr(x) g2h(x)
+#define laddr(x) g2h(x)
+
+#else /* !CONFIG_USER_ONLY */
+/* NOTE: we use double casts if pointers and target_ulong have
+ different sizes */
+#define saddr(x) (uint8_t *)(long)(x)
+#define laddr(x) (uint8_t *)(long)(x)
+#endif
+
+#define ldub_raw(p) ldub_p(laddr((p)))
+#define ldsb_raw(p) ldsb_p(laddr((p)))
+#define lduw_raw(p) lduw_p(laddr((p)))
+#define ldsw_raw(p) ldsw_p(laddr((p)))
+#define ldl_raw(p) ldl_p(laddr((p)))
+#define ldq_raw(p) ldq_p(laddr((p)))
+#define ldfl_raw(p) ldfl_p(laddr((p)))
+#define ldfq_raw(p) ldfq_p(laddr((p)))
+#define stb_raw(p, v) stb_p(saddr((p)), v)
+#define stw_raw(p, v) stw_p(saddr((p)), v)
+#define stl_raw(p, v) stl_p(saddr((p)), v)
+#define stq_raw(p, v) stq_p(saddr((p)), v)
+#define stfl_raw(p, v) stfl_p(saddr((p)), v)
+#define stfq_raw(p, v) stfq_p(saddr((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)
+
+/* ??? These should be the larger of unsigned long and target_ulong. */
+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(target_ulong address);
+void page_set_flags(target_ulong start, target_ulong end, int flags);
+void page_unprotect_range(target_ulong data, target_ulong 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_M68K)
+#define CPUState CPUM68KState
+#define cpu_init cpu_m68k_init
+#define cpu_exec cpu_m68k_exec
+#define cpu_gen_code cpu_m68k_gen_code
+#define cpu_signal_handler cpu_m68k_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
+
+#elif defined(TARGET_SH4)
+#define CPUState CPUSH4State
+#define cpu_init cpu_sh4_init
+#define cpu_exec cpu_sh4_exec
+#define cpu_gen_code cpu_sh4_gen_code
+#define cpu_signal_handler cpu_sh4_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 *first_cpu;
+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 */
+#define CPU_INTERRUPT_FIQ 0x10 /* Fast interrupt pending. */
+#define CPU_INTERRUPT_HALT 0x20 /* CPU halt wanted */
+#define CPU_INTERRUPT_SMI 0x40 /* (x86 only) SMI interrupt 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 TLB_INVALID_MASK (1 << 3)
+#define IO_MEM_SHIFT 4
+#define IO_MEM_NB_ENTRIES (1 << (TARGET_PAGE_BITS - IO_MEM_SHIFT))
+
+#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_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */
+/* acts like a ROM when read and like a device when written. As an
+ exception, the write memory callback gets the ram offset instead of
+ the physical address */
+#define IO_MEM_ROMD (1)
+
+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);
+uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr);
+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 ldub_phys(target_phys_addr_t addr);
+uint32_t lduw_phys(target_phys_addr_t addr);
+uint32_t ldl_phys(target_phys_addr_t addr);
+uint64_t ldq_phys(target_phys_addr_t addr);
+void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val);
+void stb_phys(target_phys_addr_t addr, uint32_t val);
+void stw_phys(target_phys_addr_t addr, uint32_t val);
+void stl_phys(target_phys_addr_t addr, uint32_t val);
+void stq_phys(target_phys_addr_t addr, uint64_t val);
+
+void cpu_physical_memory_write_rom(target_phys_addr_t addr,
+ const uint8_t *buf, int len);
+int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
+ uint8_t *buf, int len, int is_write);
+
+#define VGA_DIRTY_FLAG 0x01
+#define CODE_DIRTY_FLAG 0x02
+
+/* read dirty bit (return 0 or 1) */
+static inline int cpu_physical_memory_is_dirty(ram_addr_t addr)
+{
+ return phys_ram_dirty[addr >> TARGET_PAGE_BITS] == 0xff;
+}
+
+static inline int cpu_physical_memory_get_dirty(ram_addr_t addr,
+ int dirty_flags)
+{
+ return phys_ram_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags;
+}
+
+static inline void cpu_physical_memory_set_dirty(ram_addr_t addr)
+{
+ phys_ram_dirty[addr >> TARGET_PAGE_BITS] = 0xff;
+}
+
+void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
+ int dirty_flags);
+void cpu_tlb_update_dirty(CPUState *env);
+
+void dump_exec_info(FILE *f,
+ int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+
+/*******************************************/
+/* host CPU ticks (if available) */
+
+#if defined(__powerpc__)
+
+static inline uint32_t get_tbl(void)
+{
+ uint32_t tbl;
+ asm volatile("mftb %0" : "=r" (tbl));
+ return tbl;
+}
+
+static inline uint32_t get_tbu(void)
+{
+ uint32_t tbl;
+ asm volatile("mftbu %0" : "=r" (tbl));
+ return tbl;
+}
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+ uint32_t l, h, h1;
+ /* NOTE: we test if wrapping has occurred */
+ do {
+ h = get_tbu();
+ l = get_tbl();
+ h1 = get_tbu();
+ } while (h != h1);
+ return ((int64_t)h << 32) | l;
+}
+
+#elif defined(__i386__)
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+ int64_t val;
+ asm volatile ("rdtsc" : "=A" (val));
+ return val;
+}
+
+#elif defined(__x86_64__)
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+ uint32_t low,high;
+ int64_t val;
+ asm volatile("rdtsc" : "=a" (low), "=d" (high));
+ val = high;
+ val <<= 32;
+ val |= low;
+ return val;
+}
+
+#elif defined(__ia64)
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+ int64_t val;
+ asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory");
+ return val;
+}
+
+#elif defined(__s390__)
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+ int64_t val;
+ asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc");
+ return val;
+}
+
+#elif defined(__sparc_v9__)
+
+static inline int64_t cpu_get_real_ticks (void)
+{
+#if defined(_LP64)
+ uint64_t rval;
+ asm volatile("rd %%tick,%0" : "=r"(rval));
+ return rval;
+#else
+ union {
+ uint64_t i64;
+ struct {
+ uint32_t high;
+ uint32_t low;
+ } i32;
+ } rval;
+ asm volatile("rd %%tick,%1; srlx %1,32,%0"
+ : "=r"(rval.i32.high), "=r"(rval.i32.low));
+ return rval.i64;
+#endif
+}
+#else
+/* The host CPU doesn't have an easily accessible cycle counter.
+ Just return a monotonically increasing vlue. This will be totally wrong,
+ but hopefully better than nothing. */
+static inline int64_t cpu_get_real_ticks (void)
+{
+ static int64_t ticks = 0;
+ return ticks++;
+}
+#endif
+
+/* profiling */
+#ifdef CONFIG_PROFILER
+static inline int64_t profile_getclock(void)
+{
+ return cpu_get_real_ticks();
+}
+
+extern int64_t kqemu_time, kqemu_time_start;
+extern int64_t qemu_time, qemu_time_start;
+extern int64_t tlb_flush_time;
+extern int64_t kqemu_exec_count;
+extern int64_t dev_time;
+extern int64_t kqemu_ret_int_count;
+extern int64_t kqemu_ret_excp_count;
+extern int64_t kqemu_ret_intr_count;
+
+#endif
+
+#endif /* CPU_ALL_H */
Added: trunk/src/host/qemu-neo1973/cpu-defs.h
===================================================================
--- trunk/src/host/qemu-neo1973/cpu-defs.h 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/cpu-defs.h 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,133 @@
+/*
+ * 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 "%016" PRIx64
+#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
+
+/* address in the RAM (different from a physical address) */
+typedef unsigned long ram_addr_t;
+
+#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 EXCP_HALTED 0x10003 /* cpu is halted (waiting for external event) */
+#define MAX_BREAKPOINTS 32
+
+#define TB_JMP_CACHE_BITS 12
+#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
+
+/* Only the bottom TB_JMP_PAGE_BITS of the jump cache hash bits vary for
+ addresses on the same page. The top bits are the same. This allows
+ TLB invalidation to quickly clear a subset of the hash table. */
+#define TB_JMP_PAGE_BITS (TB_JMP_CACHE_BITS / 2)
+#define TB_JMP_PAGE_SIZE (1 << TB_JMP_PAGE_BITS)
+#define TB_JMP_ADDR_MASK (TB_JMP_PAGE_SIZE - 1)
+#define TB_JMP_PAGE_MASK (TB_JMP_CACHE_SIZE - TB_JMP_PAGE_SIZE)
+
+#define CPU_TLB_BITS 8
+#define CPU_TLB_SIZE (1 << CPU_TLB_BITS)
+
+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 addr_read;
+ target_ulong addr_write;
+ target_ulong addr_code;
+ /* addend to virtual address to get physical address */
+ target_phys_addr_t addend;
+} CPUTLBEntry;
+
+#define CPU_COMMON \
+ struct TranslationBlock *current_tb; /* currently executing TB */ \
+ /* soft mmu support */ \
+ /* in order to avoid passing too many arguments to the memory \
+ write helpers, we store some rarely used information in the CPU \
+ context) */ \
+ unsigned long mem_write_pc; /* host pc at which the memory was \
+ written */ \
+ target_ulong mem_write_vaddr; /* target virtual addr at which the \
+ memory was written */ \
+ /* 0 = kernel, 1 = user */ \
+ CPUTLBEntry tlb_table[2][CPU_TLB_SIZE]; \
+ struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \
+ \
+ /* from this point: preserved by CPU reset */ \
+ /* ice debug support */ \
+ target_ulong breakpoints[MAX_BREAKPOINTS]; \
+ int nb_breakpoints; \
+ int singlestep_enabled; \
+ \
+ void *next_cpu; /* next CPU sharing TB cache */ \
+ int cpu_index; /* CPU index (informative) */ \
+ /* user data */ \
+ void *opaque;
+
+#endif
Added: trunk/src/host/qemu-neo1973/cpu-exec.c
===================================================================
--- trunk/src/host/qemu-neo1973/cpu-exec.c 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/cpu-exec.c 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,1557 @@
+/*
+ * i386 emulator main execution loop
+ *
+ * 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
+ */
+#include "config.h"
+#include "exec.h"
+#include "disas.h"
+
+#if !defined(CONFIG_SOFTMMU)
+#undef EAX
+#undef ECX
+#undef EDX
+#undef EBX
+#undef ESP
+#undef EBP
+#undef ESI
+#undef EDI
+#undef EIP
+#include <signal.h>
+#include <sys/ucontext.h>
+#endif
+
+int tb_invalidated_flag;
+
+//#define DEBUG_EXEC
+//#define DEBUG_SIGNAL
+
+#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_M68K)
+/* XXX: unify with i386 target */
+void cpu_loop_exit(void)
+{
+ longjmp(env->jmp_env, 1);
+}
+#endif
+#if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K))
+#define reg_T2
+#endif
+
+/* exit the current TB from a signal handler. The host registers are
+ restored in a state compatible with the CPU emulator
+ */
+void cpu_resume_from_signal(CPUState *env1, void *puc)
+{
+#if !defined(CONFIG_SOFTMMU)
+ struct ucontext *uc = puc;
+#endif
+
+ env = env1;
+
+ /* XXX: restore cpu registers saved in host registers */
+
+#if !defined(CONFIG_SOFTMMU)
+ if (puc) {
+ /* XXX: use siglongjmp ? */
+ sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
+ }
+#endif
+ longjmp(env->jmp_env, 1);
+}
+
+
+static TranslationBlock *tb_find_slow(target_ulong pc,
+ target_ulong cs_base,
+ unsigned int flags)
+{
+ TranslationBlock *tb, **ptb1;
+ int code_gen_size;
+ unsigned int h;
+ target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
+ uint8_t *tc_ptr;
+
+ spin_lock(&tb_lock);
+
+ tb_invalidated_flag = 0;
+
+ regs_to_env(); /* XXX: do it just before cpu_gen_code() */
+
+ /* find translated block using physical mappings */
+ phys_pc = get_phys_addr_code(env, pc);
+ phys_page1 = phys_pc & TARGET_PAGE_MASK;
+ phys_page2 = -1;
+ h = tb_phys_hash_func(phys_pc);
+ ptb1 = &tb_phys_hash[h];
+ for(;;) {
+ tb = *ptb1;
+ if (!tb)
+ goto not_found;
+ if (tb->pc == pc &&
+ tb->page_addr[0] == phys_page1 &&
+ tb->cs_base == cs_base &&
+ tb->flags == flags) {
+ /* check next page if needed */
+ if (tb->page_addr[1] != -1) {
+ virt_page2 = (pc & TARGET_PAGE_MASK) +
+ TARGET_PAGE_SIZE;
+ phys_page2 = get_phys_addr_code(env, virt_page2);
+ if (tb->page_addr[1] == phys_page2)
+ goto found;
+ } else {
+ goto found;
+ }
+ }
+ ptb1 = &tb->phys_hash_next;
+ }
+ not_found:
+ /* if no translated code available, then translate it now */
+ tb = tb_alloc(pc);
+ if (!tb) {
+ /* flush must be done */
+ tb_flush(env);
+ /* cannot fail at this point */
+ tb = tb_alloc(pc);
+ /* don't forget to invalidate previous TB info */
+ tb_invalidated_flag = 1;
+ }
+ tc_ptr = code_gen_ptr;
+ tb->tc_ptr = tc_ptr;
+ tb->cs_base = cs_base;
+ tb->flags = flags;
+ cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
+ code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
+
+ /* check next page if needed */
+ virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
+ phys_page2 = -1;
+ if ((pc & TARGET_PAGE_MASK) != virt_page2) {
+ phys_page2 = get_phys_addr_code(env, virt_page2);
+ }
+ tb_link_phys(tb, phys_pc, phys_page2);
+
+ found:
+ /* we add the TB in the virtual pc hash table */
+ env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
+ spin_unlock(&tb_lock);
+ return tb;
+}
+
+static inline TranslationBlock *tb_find_fast(void)
+{
+ TranslationBlock *tb;
+ target_ulong cs_base, pc;
+ unsigned int flags;
+
+ /* we record a subset of the CPU state. It will
+ always be the same before a given translated block
+ is executed. */
+#if defined(TARGET_I386)
+ flags = env->hflags;
+ flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
+ cs_base = env->segs[R_CS].base;
+ pc = cs_base + env->eip;
+#elif defined(TARGET_ARM)
+ flags = env->thumb | (env->vfp.vec_len << 1)
+ | (env->vfp.vec_stride << 4);
+ if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
+ flags |= (1 << 6);
+ if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
+ flags |= (1 << 7);
+ cs_base = 0;
+ pc = env->regs[15];
+#elif defined(TARGET_SPARC)
+#ifdef TARGET_SPARC64
+ // Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
+ flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
+ | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
+#else
+ // FPU enable . MMU enabled . MMU no-fault . Supervisor
+ flags = (env->psref << 3) | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1)
+ | env->psrs;
+#endif
+ cs_base = env->npc;
+ pc = env->pc;
+#elif defined(TARGET_PPC)
+ flags = (msr_pr << MSR_PR) | (msr_fp << MSR_FP) |
+ (msr_se << MSR_SE) | (msr_le << MSR_LE);
+ cs_base = 0;
+ pc = env->nip;
+#elif defined(TARGET_MIPS)
+ flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
+ cs_base = 0;
+ pc = env->PC;
+#elif defined(TARGET_M68K)
+ flags = env->fpcr & M68K_FPCR_PREC;
+ cs_base = 0;
+ pc = env->pc;
+#elif defined(TARGET_SH4)
+ flags = env->sr & (SR_MD | SR_RB);
+ cs_base = 0; /* XXXXX */
+ pc = env->pc;
+#else
+#error unsupported CPU
+#endif
+ tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
+ if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
+ tb->flags != flags, 0)) {
+ tb = tb_find_slow(pc, cs_base, flags);
+ /* Note: we do it here to avoid a gcc bug on Mac OS X when
+ doing it in tb_find_slow */
+ if (tb_invalidated_flag) {
+ /* as some TB could have been invalidated because
+ of memory exceptions while generating the code, we
+ must recompute the hash index here */
+ T0 = 0;
+ }
+ }
+ return tb;
+}
+
+
+/* main execution loop */
+
+int cpu_exec(CPUState *env1)
+{
+ int saved_T0, saved_T1;
+#if defined(reg_T2)
+ int saved_T2;
+#endif
+ CPUState *saved_env;
+#if defined(TARGET_I386)
+#ifdef reg_EAX
+ int saved_EAX;
+#endif
+#ifdef reg_ECX
+ int saved_ECX;
+#endif
+#ifdef reg_EDX
+ int saved_EDX;
+#endif
+#ifdef reg_EBX
+ int saved_EBX;
+#endif
+#ifdef reg_ESP
+ int saved_ESP;
+#endif
+#ifdef reg_EBP
+ int saved_EBP;
+#endif
+#ifdef reg_ESI
+ int saved_ESI;
+#endif
+#ifdef reg_EDI
+ int saved_EDI;
+#endif
+#elif defined(TARGET_SPARC)
+#if defined(reg_REGWPTR)
+ uint32_t *saved_regwptr;
+#endif
+#endif
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
+ int saved_i7, tmp_T0;
+#endif
+ int ret, interrupt_request;
+ void (*gen_func)(void);
+ TranslationBlock *tb;
+ uint8_t *tc_ptr;
+
+#if defined(TARGET_I386)
+ /* handle exit of HALTED state */
+ if (env1->hflags & HF_HALTED_MASK) {
+ /* disable halt condition */
+ if ((env1->interrupt_request & CPU_INTERRUPT_HARD) &&
+ (env1->eflags & IF_MASK)) {
+ env1->hflags &= ~HF_HALTED_MASK;
+ } else {
+ return EXCP_HALTED;
+ }
+ }
+#elif defined(TARGET_PPC)
+ if (env1->halted) {
+ if (env1->msr[MSR_EE] &&
+ (env1->interrupt_request &
+ (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER))) {
+ env1->halted = 0;
+ } else {
+ return EXCP_HALTED;
+ }
+ }
+#elif defined(TARGET_SPARC)
+ if (env1->halted) {
+ if ((env1->interrupt_request & CPU_INTERRUPT_HARD) &&
+ (env1->psret != 0)) {
+ env1->halted = 0;
+ } else {
+ return EXCP_HALTED;
+ }
+ }
+#elif defined(TARGET_ARM)
+ if (env1->halted) {
+ /* An interrupt wakes the CPU even if the I and F CPSR bits are
+ set. */
+ if (env1->interrupt_request &
+ (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB)) {
+ env1->halted = 0;
+ } else {
+ return EXCP_HALTED;
+ }
+ }
+#elif defined(TARGET_MIPS)
+ if (env1->halted) {
+ if (env1->interrupt_request &
+ (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER)) {
+ env1->halted = 0;
+ } else {
+ return EXCP_HALTED;
+ }
+ }
+#endif
+
+ cpu_single_env = env1;
+
+ /* first we save global registers */
+ saved_env = env;
+ env = env1;
+ saved_T0 = T0;
+ saved_T1 = T1;
+#if defined(reg_T2)
+ saved_T2 = T2;
+#endif
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
+ /* we also save i7 because longjmp may not restore it */
+ asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
+#endif
+
+#if defined(TARGET_I386)
+#ifdef reg_EAX
+ saved_EAX = EAX;
+#endif
+#ifdef reg_ECX
+ saved_ECX = ECX;
+#endif
+#ifdef reg_EDX
+ saved_EDX = EDX;
+#endif
+#ifdef reg_EBX
+ saved_EBX = EBX;
+#endif
+#ifdef reg_ESP
+ saved_ESP = ESP;
+#endif
+#ifdef reg_EBP
+ saved_EBP = EBP;
+#endif
+#ifdef reg_ESI
+ saved_ESI = ESI;
+#endif
+#ifdef reg_EDI
+ saved_EDI = EDI;
+#endif
+
+ env_to_regs();
+ /* put eflags in CPU temporary format */
+ CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+ DF = 1 - (2 * ((env->eflags >> 10) & 1));
+ CC_OP = CC_OP_EFLAGS;
+ env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+#elif defined(TARGET_ARM)
+#elif defined(TARGET_SPARC)
+#if defined(reg_REGWPTR)
+ saved_regwptr = REGWPTR;
+#endif
+#elif defined(TARGET_PPC)
+#elif defined(TARGET_M68K)
+ env->cc_op = CC_OP_FLAGS;
+ env->cc_dest = env->sr & 0xf;
+ env->cc_x = (env->sr >> 4) & 1;
+#elif defined(TARGET_MIPS)
+#elif defined(TARGET_SH4)
+ /* XXXXX */
+#else
+#error unsupported target CPU
+#endif
+ env->exception_index = -1;
+
+ /* prepare setjmp context for exception handling */
+ for(;;) {
+ if (setjmp(env->jmp_env) == 0) {
+ env->current_tb = NULL;
+ /* if an exception is pending, we execute it here */
+ if (env->exception_index >= 0) {
+ if (env->exception_index >= EXCP_INTERRUPT) {
+ /* exit request from the cpu execution loop */
+ ret = env->exception_index;
+ break;
+ } else if (env->user_mode_only) {
+ /* if user mode only, we simulate a fake exception
+ which will be handled outside the cpu execution
+ loop */
+#if defined(TARGET_I386)
+ do_interrupt_user(env->exception_index,
+ env->exception_is_int,
+ env->error_code,
+ env->exception_next_eip);
+#endif
+ ret = env->exception_index;
+ break;
+ } else {
+#if defined(TARGET_I386)
+ /* simulate a real cpu exception. On i386, it can
+ trigger new exceptions, but we do not handle
+ double or triple faults yet. */
+ do_interrupt(env->exception_index,
+ env->exception_is_int,
+ env->error_code,
+ env->exception_next_eip, 0);
+#elif defined(TARGET_PPC)
+ do_interrupt(env);
+#elif defined(TARGET_MIPS)
+ do_interrupt(env);
+#elif defined(TARGET_SPARC)
+ do_interrupt(env->exception_index);
+#elif defined(TARGET_ARM)
+ do_interrupt(env);
+#elif defined(TARGET_SH4)
+ do_interrupt(env);
+#endif
+ }
+ env->exception_index = -1;
+ }
+#ifdef USE_KQEMU
+ if (kqemu_is_ok(env) && env->interrupt_request == 0) {
+ int ret;
+ env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
+ ret = kqemu_cpu_exec(env);
+ /* put eflags in CPU temporary format */
+ CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+ DF = 1 - (2 * ((env->eflags >> 10) & 1));
+ CC_OP = CC_OP_EFLAGS;
+ env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+ if (ret == 1) {
+ /* exception */
+ longjmp(env->jmp_env, 1);
+ } else if (ret == 2) {
+ /* softmmu execution needed */
+ } else {
+ if (env->interrupt_request != 0) {
+ /* hardware interrupt will be executed just after */
+ } else {
+ /* otherwise, we restart */
+ longjmp(env->jmp_env, 1);
+ }
+ }
+ }
+#endif
+
+ T0 = 0; /* force lookup of first TB */
+ for(;;) {
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
+ /* g1 can be modified by some libc? functions */
+ tmp_T0 = T0;
+#endif
+ interrupt_request = env->interrupt_request;
+ if (__builtin_expect(interrupt_request, 0)) {
+#if defined(TARGET_I386)
+ if ((interrupt_request & CPU_INTERRUPT_SMI) &&
+ !(env->hflags & HF_SMM_MASK)) {
+ env->interrupt_request &= ~CPU_INTERRUPT_SMI;
+ do_smm_enter();
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
+ tmp_T0 = 0;
+#else
+ T0 = 0;
+#endif
+ } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
+ (env->eflags & IF_MASK) &&
+ !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
+ int intno;
+ env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+ intno = cpu_get_pic_interrupt(env);
+ if (loglevel & CPU_LOG_TB_IN_ASM) {
+ fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
+ }
+ do_interrupt(intno, 0, 0, 0, 1);
+ /* ensure that no TB jump will be modified as
+ the program flow was changed */
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
+ tmp_T0 = 0;
+#else
+ T0 = 0;
+#endif
+ }
+#elif defined(TARGET_PPC)
+#if 0
+ if ((interrupt_request & CPU_INTERRUPT_RESET)) {
+ cpu_ppc_reset(env);
+ }
+#endif
+ if (msr_ee != 0) {
+ if ((interrupt_request & CPU_INTERRUPT_HARD)) {
+ /* Raise it */
+ env->exception_index = EXCP_EXTERNAL;
+ env->error_code = 0;
+ do_interrupt(env);
+ env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
+ tmp_T0 = 0;
+#else
+ T0 = 0;
+#endif
+ } else if ((interrupt_request & CPU_INTERRUPT_TIMER)) {
+ /* Raise it */
+ env->exception_index = EXCP_DECR;
+ env->error_code = 0;
+ do_interrupt(env);
+ env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
+ tmp_T0 = 0;
+#else
+ T0 = 0;
+#endif
+ }
+ }
+#elif defined(TARGET_MIPS)
+ if ((interrupt_request & CPU_INTERRUPT_HARD) &&
+ (env->CP0_Status & (1 << CP0St_IE)) &&
+ (env->CP0_Status & env->CP0_Cause & 0x0000FF00) &&
+ !(env->hflags & MIPS_HFLAG_EXL) &&
+ !(env->hflags & MIPS_HFLAG_ERL) &&
+ !(env->hflags & MIPS_HFLAG_DM)) {
+ /* Raise it */
+ env->exception_index = EXCP_EXT_INTERRUPT;
+ env->error_code = 0;
+ do_interrupt(env);
+ env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
+ tmp_T0 = 0;
+#else
+ T0 = 0;
+#endif
+ }
+#elif defined(TARGET_SPARC)
+ if ((interrupt_request & CPU_INTERRUPT_HARD) &&
+ (env->psret != 0)) {
+ int pil = env->interrupt_index & 15;
+ int type = env->interrupt_index & 0xf0;
+
+ if (((type == TT_EXTINT) &&
+ (pil == 15 || pil > env->psrpil)) ||
+ type != TT_EXTINT) {
+ env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+ do_interrupt(env->interrupt_index);
+ env->interrupt_index = 0;
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
+ tmp_T0 = 0;
+#else
+ T0 = 0;
+#endif
+ }
+ } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
+ //do_interrupt(0, 0, 0, 0, 0);
+ env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
+ } else if (interrupt_request & CPU_INTERRUPT_HALT) {
+ env->interrupt_request &= ~CPU_INTERRUPT_HALT;
+ env->halted = 1;
+ env->exception_index = EXCP_HLT;
+ cpu_loop_exit();
+ }
+#elif defined(TARGET_ARM)
+ if (interrupt_request & CPU_INTERRUPT_FIQ
+ && !(env->uncached_cpsr & CPSR_F)) {
+ env->exception_index = EXCP_FIQ;
+ do_interrupt(env);
+ }
+ if (interrupt_request & CPU_INTERRUPT_HARD
+ && !(env->uncached_cpsr & CPSR_I)) {
+ env->exception_index = EXCP_IRQ;
+ do_interrupt(env);
+ }
+ if (interrupt_request & CPU_INTERRUPT_HALT) {
+ env->interrupt_request &= ~CPU_INTERRUPT_HALT;
+ env->halted = 1;
+ env->exception_index = EXCP_HLT;
+ cpu_loop_exit();
+ }
+#elif defined(TARGET_SH4)
+ /* XXXXX */
+#endif
+ /* Don't use the cached interupt_request value,
+ do_interrupt may have updated the EXITTB flag. */
+ if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
+ env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
+ /* ensure that no TB jump will be modified as
+ the program flow was changed */
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
+ tmp_T0 = 0;
+#else
+ T0 = 0;
+#endif
+ }
+ if (interrupt_request & CPU_INTERRUPT_EXIT) {
+ env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
+ env->exception_index = EXCP_INTERRUPT;
+ cpu_loop_exit();
+ }
+ }
+#ifdef DEBUG_EXEC
+ if ((loglevel & CPU_LOG_TB_CPU)) {
+#if defined(TARGET_I386)
+ /* restore flags in standard format */
+#ifdef reg_EAX
+ env->regs[R_EAX] = EAX;
+#endif
+#ifdef reg_EBX
+ env->regs[R_EBX] = EBX;
+#endif
+#ifdef reg_ECX
+ env->regs[R_ECX] = ECX;
+#endif
+#ifdef reg_EDX
+ env->regs[R_EDX] = EDX;
+#endif
+#ifdef reg_ESI
+ env->regs[R_ESI] = ESI;
+#endif
+#ifdef reg_EDI
+ env->regs[R_EDI] = EDI;
+#endif
+#ifdef reg_EBP
+ env->regs[R_EBP] = EBP;
+#endif
+#ifdef reg_ESP
+ env->regs[R_ESP] = ESP;
+#endif
+ env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
+ cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
+ env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+#elif defined(TARGET_ARM)
+ cpu_dump_state(env, logfile, fprintf, 0);
+#elif defined(TARGET_SPARC)
+ REGWPTR = env->regbase + (env->cwp * 16);
+ env->regwptr = REGWPTR;
+ cpu_dump_state(env, logfile, fprintf, 0);
+#elif defined(TARGET_PPC)
+ cpu_dump_state(env, logfile, fprintf, 0);
+#elif defined(TARGET_M68K)
+ cpu_m68k_flush_flags(env, env->cc_op);
+ env->cc_op = CC_OP_FLAGS;
+ env->sr = (env->sr & 0xffe0)
+ | env->cc_dest | (env->cc_x << 4);
+ cpu_dump_state(env, logfile, fprintf, 0);
+#elif defined(TARGET_MIPS)
+ cpu_dump_state(env, logfile, fprintf, 0);
+#elif defined(TARGET_SH4)
+ cpu_dump_state(env, logfile, fprintf, 0);
+#else
+#error unsupported target CPU
+#endif
+ }
+#endif
+ tb = tb_find_fast();
+#ifdef DEBUG_EXEC
+ if ((loglevel & CPU_LOG_EXEC)) {
+ fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
+ (long)tb->tc_ptr, tb->pc,
+ lookup_symbol(tb->pc));
+ }
+#endif
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
+ T0 = tmp_T0;
+#endif
+ /* see if we can patch the calling TB. When the TB
+ spans two pages, we cannot safely do a direct
+ jump. */
+ {
+ if (T0 != 0 &&
+#if USE_KQEMU
+ (env->kqemu_enabled != 2) &&
+#endif
+ tb->page_addr[1] == -1
+#if defined(TARGET_I386) && defined(USE_CODE_COPY)
+ && (tb->cflags & CF_CODE_COPY) ==
+ (((TranslationBlock *)(T0 & ~3))->cflags & CF_CODE_COPY)
+#endif
+ ) {
+ spin_lock(&tb_lock);
+ tb_add_jump((TranslationBlock *)(long)(T0 & ~3), T0 & 3, tb);
+#if defined(USE_CODE_COPY)
+ /* propagates the FP use info */
+ ((TranslationBlock *)(T0 & ~3))->cflags |=
+ (tb->cflags & CF_FP_USED);
+#endif
+ spin_unlock(&tb_lock);
+ }
+ }
+ tc_ptr = tb->tc_ptr;
+ env->current_tb = tb;
+ /* execute the generated code */
+ gen_func = (void *)tc_ptr;
+#if defined(__sparc__)
+ __asm__ __volatile__("call %0\n\t"
+ "mov %%o7,%%i0"
+ : /* no outputs */
+ : "r" (gen_func)
+ : "i0", "i1", "i2", "i3", "i4", "i5",
+ "l0", "l1", "l2", "l3", "l4", "l5",
+ "l6", "l7");
+#elif defined(__arm__)
+ asm volatile ("mov pc, %0\n\t"
+ ".global exec_loop\n\t"
+ "exec_loop:\n\t"
+ : /* no outputs */
+ : "r" (gen_func)
+ : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
+#elif defined(TARGET_I386) && defined(USE_CODE_COPY)
+{
+ if (!(tb->cflags & CF_CODE_COPY)) {
+ if ((tb->cflags & CF_FP_USED) && env->native_fp_regs) {
+ save_native_fp_state(env);
+ }
+ gen_func();
+ } else {
+ if ((tb->cflags & CF_FP_USED) && !env->native_fp_regs) {
+ restore_native_fp_state(env);
+ }
+ /* we work with native eflags */
+ CC_SRC = cc_table[CC_OP].compute_all();
+ CC_OP = CC_OP_EFLAGS;
+ asm(".globl exec_loop\n"
+ "\n"
+ "debug1:\n"
+ " pushl %%ebp\n"
+ " fs movl %10, %9\n"
+ " fs movl %11, %%eax\n"
+ " andl $0x400, %%eax\n"
+ " fs orl %8, %%eax\n"
+ " pushl %%eax\n"
+ " popf\n"
+ " fs movl %%esp, %12\n"
+ " fs movl %0, %%eax\n"
+ " fs movl %1, %%ecx\n"
+ " fs movl %2, %%edx\n"
+ " fs movl %3, %%ebx\n"
+ " fs movl %4, %%esp\n"
+ " fs movl %5, %%ebp\n"
+ " fs movl %6, %%esi\n"
+ " fs movl %7, %%edi\n"
+ " fs jmp *%9\n"
+ "exec_loop:\n"
+ " fs movl %%esp, %4\n"
+ " fs movl %12, %%esp\n"
+ " fs movl %%eax, %0\n"
+ " fs movl %%ecx, %1\n"
+ " fs movl %%edx, %2\n"
+ " fs movl %%ebx, %3\n"
+ " fs movl %%ebp, %5\n"
+ " fs movl %%esi, %6\n"
+ " fs movl %%edi, %7\n"
+ " pushf\n"
+ " popl %%eax\n"
+ " movl %%eax, %%ecx\n"
+ " andl $0x400, %%ecx\n"
+ " shrl $9, %%ecx\n"
+ " andl $0x8d5, %%eax\n"
+ " fs movl %%eax, %8\n"
+ " movl $1, %%eax\n"
+ " subl %%ecx, %%eax\n"
+ " fs movl %%eax, %11\n"
+ " fs movl %9, %%ebx\n" /* get T0 value */
+ " popl %%ebp\n"
+ :
+ : "m" (*(uint8_t *)offsetof(CPUState, regs[0])),
+ "m" (*(uint8_t *)offsetof(CPUState, regs[1])),
+ "m" (*(uint8_t *)offsetof(CPUState, regs[2])),
+ "m" (*(uint8_t *)offsetof(CPUState, regs[3])),
+ "m" (*(uint8_t *)offsetof(CPUState, regs[4])),
+ "m" (*(uint8_t *)offsetof(CPUState, regs[5])),
+ "m" (*(uint8_t *)offsetof(CPUState, regs[6])),
+ "m" (*(uint8_t *)offsetof(CPUState, regs[7])),
+ "m" (*(uint8_t *)offsetof(CPUState, cc_src)),
+ "m" (*(uint8_t *)offsetof(CPUState, tmp0)),
+ "a" (gen_func),
+ "m" (*(uint8_t *)offsetof(CPUState, df)),
+ "m" (*(uint8_t *)offsetof(CPUState, saved_esp))
+ : "%ecx", "%edx"
+ );
+ }
+}
+#elif defined(__ia64)
+ struct fptr {
+ void *ip;
+ void *gp;
+ } fp;
+
+ fp.ip = tc_ptr;
+ fp.gp = code_gen_buffer + 2 * (1 << 20);
+ (*(void (*)(void)) &fp)();
+#else
+ gen_func();
+#endif
+ env->current_tb = NULL;
+ /* reset soft MMU for next block (it can currently
+ only be set by a memory fault) */
+#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
+ if (env->hflags & HF_SOFTMMU_MASK) {
+ env->hflags &= ~HF_SOFTMMU_MASK;
+ /* do not allow linking to another block */
+ T0 = 0;
+ }
+#endif
+#if defined(USE_KQEMU)
+#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
+ if (kqemu_is_ok(env) &&
+ (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
+ cpu_loop_exit();
+ }
+#endif
+ }
+ } else {
+ env_to_regs();
+ }
+ } /* for(;;) */
+
+
+#if defined(TARGET_I386)
+#if defined(USE_CODE_COPY)
+ if (env->native_fp_regs) {
+ save_native_fp_state(env);
+ }
+#endif
+ /* restore flags in standard format */
+ env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
+
+ /* restore global registers */
+#ifdef reg_EAX
+ EAX = saved_EAX;
+#endif
+#ifdef reg_ECX
+ ECX = saved_ECX;
+#endif
+#ifdef reg_EDX
+ EDX = saved_EDX;
+#endif
+#ifdef reg_EBX
+ EBX = saved_EBX;
+#endif
+#ifdef reg_ESP
+ ESP = saved_ESP;
+#endif
+#ifdef reg_EBP
+ EBP = saved_EBP;
+#endif
+#ifdef reg_ESI
+ ESI = saved_ESI;
+#endif
+#ifdef reg_EDI
+ EDI = saved_EDI;
+#endif
+#elif defined(TARGET_ARM)
+ /* XXX: Save/restore host fpu exception state?. */
+#elif defined(TARGET_SPARC)
+#if defined(reg_REGWPTR)
+ REGWPTR = saved_regwptr;
+#endif
+#elif defined(TARGET_PPC)
+#elif defined(TARGET_M68K)
+ cpu_m68k_flush_flags(env, env->cc_op);
+ env->cc_op = CC_OP_FLAGS;
+ env->sr = (env->sr & 0xffe0)
+ | env->cc_dest | (env->cc_x << 4);
+#elif defined(TARGET_MIPS)
+#elif defined(TARGET_SH4)
+ /* XXXXX */
+#else
+#error unsupported target CPU
+#endif
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
+ asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
+#endif
+ T0 = saved_T0;
+ T1 = saved_T1;
+#if defined(reg_T2)
+ T2 = saved_T2;
+#endif
+ env = saved_env;
+ /* fail safe : never use cpu_single_env outside cpu_exec() */
+ cpu_single_env = NULL;
+ return ret;
+}
+
+/* must only be called from the generated code as an exception can be
+ generated */
+void tb_invalidate_page_range(target_ulong start, target_ulong end)
+{
+ /* XXX: cannot enable it yet because it yields to MMU exception
+ where NIP != read address on PowerPC */
+#if 0
+ target_ulong phys_addr;
+ phys_addr = get_phys_addr_code(env, start);
+ tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
+#endif
+}
+
+#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
+
+void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
+{
+ CPUX86State *saved_env;
+
+ saved_env = env;
+ env = s;
+ if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
+ selector &= 0xffff;
+ cpu_x86_load_seg_cache(env, seg_reg, selector,
+ (selector << 4), 0xffff, 0);
+ } else {
+ load_seg(seg_reg, selector);
+ }
+ env = saved_env;
+}
+
+void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32)
+{
+ CPUX86State *saved_env;
+
+ saved_env = env;
+ env = s;
+
+ helper_fsave((target_ulong)ptr, data32);
+
+ env = saved_env;
+}
+
+void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
+{
+ CPUX86State *saved_env;
+
+ saved_env = env;
+ env = s;
+
+ helper_frstor((target_ulong)ptr, data32);
+
+ env = saved_env;
+}
+
+#endif /* TARGET_I386 */
+
+#if !defined(CONFIG_SOFTMMU)
+
+#if defined(TARGET_I386)
+
+/* 'pc' is the host PC at which the exception was raised. 'address' is
+ the effective address of the memory exception. 'is_write' is 1 if a
+ write caused the exception and otherwise 0'. 'old_set' is the
+ signal set which should be restored */
+static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
+ int is_write, sigset_t *old_set,
+ void *puc)
+{
+ TranslationBlock *tb;
+ int ret;
+
+ if (cpu_single_env)
+ env = cpu_single_env; /* XXX: find a correct solution for multithread */
+#if defined(DEBUG_SIGNAL)
+ qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
+ pc, address, is_write, *(unsigned long *)old_set);
+#endif
+ /* XXX: locking issue */
+ if (is_write && page_unprotect(h2g(address), pc, puc)) {
+ return 1;
+ }
+
+ /* see if it is an MMU fault */
+ ret = cpu_x86_handle_mmu_fault(env, address, is_write,
+ ((env->hflags & HF_CPL_MASK) == 3), 0);
+ if (ret < 0)
+ return 0; /* not an MMU fault */
+ if (ret == 0)
+ return 1; /* the MMU fault was handled without causing real CPU fault */
+ /* now we have a real cpu fault */
+ tb = tb_find_pc(pc);
+ if (tb) {
+ /* the PC is inside the translated code. It means that we have
+ a virtual CPU fault */
+ cpu_restore_state(tb, env, pc, puc);
+ }
+ if (ret == 1) {
+#if 0
+ printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
+ env->eip, env->cr[2], env->error_code);
+#endif
+ /* we restore the process signal mask as the sigreturn should
+ do it (XXX: use sigsetjmp) */
+ sigprocmask(SIG_SETMASK, old_set, NULL);
+ raise_exception_err(env->exception_index, env->error_code);
+ } else {
+ /* activate soft MMU for this block */
+ env->hflags |= HF_SOFTMMU_MASK;
+ cpu_resume_from_signal(env, puc);
+ }
+ /* never comes here */
+ return 1;
+}
+
+#elif defined(TARGET_ARM)
+static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
+ int is_write, sigset_t *old_set,
+ void *puc)
+{
+ TranslationBlock *tb;
+ int ret;
+
+ if (cpu_single_env)
+ env = cpu_single_env; /* XXX: find a correct solution for multithread */
+#if defined(DEBUG_SIGNAL)
+ printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
+ pc, address, is_write, *(unsigned long *)old_set);
+#endif
+ /* XXX: locking issue */
+ if (is_write && page_unprotect(h2g(address), pc, puc)) {
+ return 1;
+ }
+ /* see if it is an MMU fault */
+ ret = cpu_arm_handle_mmu_fault(env, address, is_write, 1, 0);
+ if (ret < 0)
+ return 0; /* not an MMU fault */
+ if (ret == 0)
+ return 1; /* the MMU fault was handled without causing real CPU fault */
+ /* now we have a real cpu fault */
+ tb = tb_find_pc(pc);
+ if (tb) {
+ /* the PC is inside the translated code. It means that we have
+ a virtual CPU fault */
+ cpu_restore_state(tb, env, pc, puc);
+ }
+ /* we restore the process signal mask as the sigreturn should
+ do it (XXX: use sigsetjmp) */
+ sigprocmask(SIG_SETMASK, old_set, NULL);
+ cpu_loop_exit();
+}
+#elif defined(TARGET_SPARC)
+static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
+ int is_write, sigset_t *old_set,
+ void *puc)
+{
+ TranslationBlock *tb;
+ int ret;
+
+ if (cpu_single_env)
+ env = cpu_single_env; /* XXX: find a correct solution for multithread */
+#if defined(DEBUG_SIGNAL)
+ printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
+ pc, address, is_write, *(unsigned long *)old_set);
+#endif
+ /* XXX: locking issue */
+ if (is_write && page_unprotect(h2g(address), pc, puc)) {
+ return 1;
+ }
+ /* see if it is an MMU fault */
+ ret = cpu_sparc_handle_mmu_fault(env, address, is_write, 1, 0);
+ if (ret < 0)
+ return 0; /* not an MMU fault */
+ if (ret == 0)
+ return 1; /* the MMU fault was handled without causing real CPU fault */
+ /* now we have a real cpu fault */
+ tb = tb_find_pc(pc);
+ if (tb) {
+ /* the PC is inside the translated code. It means that we have
+ a virtual CPU fault */
+ cpu_restore_state(tb, env, pc, puc);
+ }
+ /* we restore the process signal mask as the sigreturn should
+ do it (XXX: use sigsetjmp) */
+ sigprocmask(SIG_SETMASK, old_set, NULL);
+ cpu_loop_exit();
+}
+#elif defined (TARGET_PPC)
+static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
+ int is_write, sigset_t *old_set,
+ void *puc)
+{
+ TranslationBlock *tb;
+ int ret;
+
+ if (cpu_single_env)
+ env = cpu_single_env; /* XXX: find a correct solution for multithread */
+#if defined(DEBUG_SIGNAL)
+ printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
+ pc, address, is_write, *(unsigned long *)old_set);
+#endif
+ /* XXX: locking issue */
+ if (is_write && page_unprotect(h2g(address), pc, puc)) {
+ return 1;
+ }
+
+ /* see if it is an MMU fault */
+ ret = cpu_ppc_handle_mmu_fault(env, address, is_write, msr_pr, 0);
+ if (ret < 0)
+ return 0; /* not an MMU fault */
+ if (ret == 0)
+ return 1; /* the MMU fault was handled without causing real CPU fault */
+
+ /* now we have a real cpu fault */
+ tb = tb_find_pc(pc);
+ if (tb) {
+ /* the PC is inside the translated code. It means that we have
+ a virtual CPU fault */
+ cpu_restore_state(tb, env, pc, puc);
+ }
+ if (ret == 1) {
+#if 0
+ printf("PF exception: NIP=0x%08x error=0x%x %p\n",
+ env->nip, env->error_code, tb);
+#endif
+ /* we restore the process signal mask as the sigreturn should
+ do it (XXX: use sigsetjmp) */
+ sigprocmask(SIG_SETMASK, old_set, NULL);
+ do_raise_exception_err(env->exception_index, env->error_code);
+ } else {
+ /* activate soft MMU for this block */
+ cpu_resume_from_signal(env, puc);
+ }
+ /* never comes here */
+ return 1;
+}
+
+#elif defined(TARGET_M68K)
+static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
+ int is_write, sigset_t *old_set,
+ void *puc)
+{
+ TranslationBlock *tb;
+ int ret;
+
+ if (cpu_single_env)
+ env = cpu_single_env; /* XXX: find a correct solution for multithread */
+#if defined(DEBUG_SIGNAL)
+ printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
+ pc, address, is_write, *(unsigned long *)old_set);
+#endif
+ /* XXX: locking issue */
+ if (is_write && page_unprotect(address, pc, puc)) {
+ return 1;
+ }
+ /* see if it is an MMU fault */
+ ret = cpu_m68k_handle_mmu_fault(env, address, is_write, 1, 0);
+ if (ret < 0)
+ return 0; /* not an MMU fault */
+ if (ret == 0)
+ return 1; /* the MMU fault was handled without causing real CPU fault */
+ /* now we have a real cpu fault */
+ tb = tb_find_pc(pc);
+ if (tb) {
+ /* the PC is inside the translated code. It means that we have
+ a virtual CPU fault */
+ cpu_restore_state(tb, env, pc, puc);
+ }
+ /* we restore the process signal mask as the sigreturn should
+ do it (XXX: use sigsetjmp) */
+ sigprocmask(SIG_SETMASK, old_set, NULL);
+ cpu_loop_exit();
+ /* never comes here */
+ return 1;
+}
+
+#elif defined (TARGET_MIPS)
+static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
+ int is_write, sigset_t *old_set,
+ void *puc)
+{
+ TranslationBlock *tb;
+ int ret;
+
+ if (cpu_single_env)
+ env = cpu_single_env; /* XXX: find a correct solution for multithread */
+#if defined(DEBUG_SIGNAL)
+ printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
+ pc, address, is_write, *(unsigned long *)old_set);
+#endif
+ /* XXX: locking issue */
+ if (is_write && page_unprotect(h2g(address), pc, puc)) {
+ return 1;
+ }
+
+ /* see if it is an MMU fault */
+ ret = cpu_mips_handle_mmu_fault(env, address, is_write, 1, 0);
+ if (ret < 0)
+ return 0; /* not an MMU fault */
+ if (ret == 0)
+ return 1; /* the MMU fault was handled without causing real CPU fault */
+
+ /* now we have a real cpu fault */
+ tb = tb_find_pc(pc);
+ if (tb) {
+ /* the PC is inside the translated code. It means that we have
+ a virtual CPU fault */
+ cpu_restore_state(tb, env, pc, puc);
+ }
+ if (ret == 1) {
+#if 0
+ printf("PF exception: NIP=0x%08x error=0x%x %p\n",
+ env->nip, env->error_code, tb);
+#endif
+ /* we restore the process signal mask as the sigreturn should
+ do it (XXX: use sigsetjmp) */
+ sigprocmask(SIG_SETMASK, old_set, NULL);
+ do_raise_exception_err(env->exception_index, env->error_code);
+ } else {
+ /* activate soft MMU for this block */
+ cpu_resume_from_signal(env, puc);
+ }
+ /* never comes here */
+ return 1;
+}
+
+#elif defined (TARGET_SH4)
+static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
+ int is_write, sigset_t *old_set,
+ void *puc)
+{
+ TranslationBlock *tb;
+ int ret;
+
+ if (cpu_single_env)
+ env = cpu_single_env; /* XXX: find a correct solution for multithread */
+#if defined(DEBUG_SIGNAL)
+ printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
+ pc, address, is_write, *(unsigned long *)old_set);
+#endif
+ /* XXX: locking issue */
+ if (is_write && page_unprotect(h2g(address), pc, puc)) {
+ return 1;
+ }
+
+ /* see if it is an MMU fault */
+ ret = cpu_sh4_handle_mmu_fault(env, address, is_write, 1, 0);
+ if (ret < 0)
+ return 0; /* not an MMU fault */
+ if (ret == 0)
+ return 1; /* the MMU fault was handled without causing real CPU fault */
+
+ /* now we have a real cpu fault */
+ tb = tb_find_pc(pc);
+ if (tb) {
+ /* the PC is inside the translated code. It means that we have
+ a virtual CPU fault */
+ cpu_restore_state(tb, env, pc, puc);
+ }
+#if 0
+ printf("PF exception: NIP=0x%08x error=0x%x %p\n",
+ env->nip, env->error_code, tb);
+#endif
+ /* we restore the process signal mask as the sigreturn should
+ do it (XXX: use sigsetjmp) */
+ sigprocmask(SIG_SETMASK, old_set, NULL);
+ cpu_loop_exit();
+ /* never comes here */
+ return 1;
+}
+#else
+#error unsupported target CPU
+#endif
+
+#if defined(__i386__)
+
+#if defined(USE_CODE_COPY)
+static void cpu_send_trap(unsigned long pc, int trap,
+ struct ucontext *uc)
+{
+ TranslationBlock *tb;
+
+ if (cpu_single_env)
+ env = cpu_single_env; /* XXX: find a correct solution for multithread */
+ /* now we have a real cpu fault */
+ tb = tb_find_pc(pc);
+ if (tb) {
+ /* the PC is inside the translated code. It means that we have
+ a virtual CPU fault */
+ cpu_restore_state(tb, env, pc, uc);
+ }
+ sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
+ raise_exception_err(trap, env->error_code);
+}
+#endif
+
+int cpu_signal_handler(int host_signum, struct siginfo *info,
+ void *puc)
+{
+ struct ucontext *uc = puc;
+ unsigned long pc;
+ int trapno;
+
+#ifndef REG_EIP
+/* for glibc 2.1 */
+#define REG_EIP EIP
+#define REG_ERR ERR
+#define REG_TRAPNO TRAPNO
+#endif
+ pc = uc->uc_mcontext.gregs[REG_EIP];
+ trapno = uc->uc_mcontext.gregs[REG_TRAPNO];
+#if defined(TARGET_I386) && defined(USE_CODE_COPY)
+ if (trapno == 0x00 || trapno == 0x05) {
+ /* send division by zero or bound exception */
+ cpu_send_trap(pc, trapno, uc);
+ return 1;
+ } else
+#endif
+ return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+ trapno == 0xe ?
+ (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
+ &uc->uc_sigmask, puc);
+}
+
+#elif defined(__x86_64__)
+
+int cpu_signal_handler(int host_signum, struct siginfo *info,
+ void *puc)
+{
+ struct ucontext *uc = puc;
+ unsigned long pc;
+
+ pc = uc->uc_mcontext.gregs[REG_RIP];
+ return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+ uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
+ (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
+ &uc->uc_sigmask, puc);
+}
+
+#elif defined(__powerpc__)
+
+/***********************************************************************
+ * signal context platform-specific definitions
+ * From Wine
+ */
+#ifdef linux
+/* All Registers access - only for local access */
+# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
+/* Gpr Registers access */
+# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
+# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
+# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
+# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
+# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
+# define LR_sig(context) REG_sig(link, context) /* Link register */
+# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
+/* Float Registers access */
+# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
+# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
+/* Exception Registers access */
+# define DAR_sig(context) REG_sig(dar, context)
+# define DSISR_sig(context) REG_sig(dsisr, context)
+# define TRAP_sig(context) REG_sig(trap, context)
+#endif /* linux */
+
+#ifdef __APPLE__
+# include <sys/ucontext.h>
+typedef struct ucontext SIGCONTEXT;
+/* All Registers access - only for local access */
+# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
+# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
+# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
+# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
+/* Gpr Registers access */
+# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
+# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
+# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
+# define CTR_sig(context) REG_sig(ctr, context)
+# define XER_sig(context) REG_sig(xer, context) /* Link register */
+# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
+# define CR_sig(context) REG_sig(cr, context) /* Condition register */
+/* Float Registers access */
+# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
+# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
+/* Exception Registers access */
+# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
+# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
+# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
+#endif /* __APPLE__ */
+
+int cpu_signal_handler(int host_signum, struct siginfo *info,
+ void *puc)
+{
+ struct ucontext *uc = puc;
+ unsigned long pc;
+ int is_write;
+
+ pc = IAR_sig(uc);
+ is_write = 0;
+#if 0
+ /* ppc 4xx case */
+ if (DSISR_sig(uc) & 0x00800000)
+ is_write = 1;
+#else
+ if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
+ is_write = 1;
+#endif
+ return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+ is_write, &uc->uc_sigmask, puc);
+}
+
+#elif defined(__alpha__)
+
+int cpu_signal_handler(int host_signum, struct siginfo *info,
+ void *puc)
+{
+ struct ucontext *uc = puc;
+ uint32_t *pc = uc->uc_mcontext.sc_pc;
+ uint32_t insn = *pc;
+ int is_write = 0;
+
+ /* XXX: need kernel patch to get write flag faster */
+ switch (insn >> 26) {
+ case 0x0d: // stw
+ case 0x0e: // stb
+ case 0x0f: // stq_u
+ case 0x24: // stf
+ case 0x25: // stg
+ case 0x26: // sts
+ case 0x27: // stt
+ case 0x2c: // stl
+ case 0x2d: // stq
+ case 0x2e: // stl_c
+ case 0x2f: // stq_c
+ is_write = 1;
+ }
+
+ return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+ is_write, &uc->uc_sigmask, puc);
+}
+#elif defined(__sparc__)
+
+int cpu_signal_handler(int host_signum, struct siginfo *info,
+ void *puc)
+{
+ uint32_t *regs = (uint32_t *)(info + 1);
+ void *sigmask = (regs + 20);
+ unsigned long pc;
+ int is_write;
+ uint32_t insn;
+
+ /* XXX: is there a standard glibc define ? */
+ pc = regs[1];
+ /* XXX: need kernel patch to get write flag faster */
+ is_write = 0;
+ insn = *(uint32_t *)pc;
+ if ((insn >> 30) == 3) {
+ switch((insn >> 19) & 0x3f) {
+ case 0x05: // stb
+ case 0x06: // sth
+ case 0x04: // st
+ case 0x07: // std
+ case 0x24: // stf
+ case 0x27: // stdf
+ case 0x25: // stfsr
+ is_write = 1;
+ break;
+ }
+ }
+ return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+ is_write, sigmask, NULL);
+}
+
+#elif defined(__arm__)
+
+int cpu_signal_handler(int host_signum, struct siginfo *info,
+ void *puc)
+{
+ struct ucontext *uc = puc;
+ unsigned long pc;
+ int is_write;
+
+ pc = uc->uc_mcontext.gregs[R15];
+ /* XXX: compute is_write */
+ is_write = 0;
+ return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+ is_write,
+ &uc->uc_sigmask, puc);
+}
+
+#elif defined(__mc68000)
+
+int cpu_signal_handler(int host_signum, struct siginfo *info,
+ void *puc)
+{
+ struct ucontext *uc = puc;
+ unsigned long pc;
+ int is_write;
+
+ pc = uc->uc_mcontext.gregs[16];
+ /* XXX: compute is_write */
+ is_write = 0;
+ return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+ is_write,
+ &uc->uc_sigmask, puc);
+}
+
+#elif defined(__ia64)
+
+#ifndef __ISR_VALID
+ /* This ought to be in <bits/siginfo.h>... */
+# define __ISR_VALID 1
+#endif
+
+int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc)
+{
+ struct ucontext *uc = puc;
+ unsigned long ip;
+ int is_write = 0;
+
+ ip = uc->uc_mcontext.sc_ip;
+ switch (host_signum) {
+ case SIGILL:
+ case SIGFPE:
+ case SIGSEGV:
+ case SIGBUS:
+ case SIGTRAP:
+ if (info->si_code && (info->si_segvflags & __ISR_VALID))
+ /* ISR.W (write-access) is bit 33: */
+ is_write = (info->si_isr >> 33) & 1;
+ break;
+
+ default:
+ break;
+ }
+ return handle_cpu_signal(ip, (unsigned long)info->si_addr,
+ is_write,
+ &uc->uc_sigmask, puc);
+}
+
+#elif defined(__s390__)
+
+int cpu_signal_handler(int host_signum, struct siginfo *info,
+ void *puc)
+{
+ struct ucontext *uc = puc;
+ unsigned long pc;
+ int is_write;
+
+ pc = uc->uc_mcontext.psw.addr;
+ /* XXX: compute is_write */
+ is_write = 0;
+ return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+ is_write,
+ &uc->uc_sigmask, puc);
+}
+
+#else
+
+#error host CPU specific signal handler needed
+
+#endif
+
+#endif /* !defined(CONFIG_SOFTMMU) */
Added: trunk/src/host/qemu-neo1973/cutils.c
===================================================================
--- trunk/src/host/qemu-neo1973/cutils.c 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/cutils.c 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,83 @@
+/*
+ * Simple C functions to supplement the C library
+ *
+ * Copyright (c) 2006 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"
+
+void pstrcpy(char *buf, int buf_size, const char *str)
+{
+ int c;
+ char *q = buf;
+
+ if (buf_size <= 0)
+ return;
+
+ for(;;) {
+ c = *str++;
+ if (c == 0 || q >= buf + buf_size - 1)
+ break;
+ *q++ = c;
+ }
+ *q = '\0';
+}
+
+/* strcat and truncate. */
+char *pstrcat(char *buf, int buf_size, const char *s)
+{
+ int len;
+ len = strlen(buf);
+ if (len < buf_size)
+ pstrcpy(buf + len, buf_size - len, s);
+ return buf;
+}
+
+int strstart(const char *str, const char *val, const char **ptr)
+{
+ const char *p, *q;
+ p = str;
+ q = val;
+ while (*q != '\0') {
+ if (*p != *q)
+ return 0;
+ p++;
+ q++;
+ }
+ if (ptr)
+ *ptr = p;
+ return 1;
+}
+
+int stristart(const char *str, const char *val, const char **ptr)
+{
+ const char *p, *q;
+ p = str;
+ q = val;
+ while (*q != '\0') {
+ if (toupper(*p) != toupper(*q))
+ return 0;
+ p++;
+ q++;
+ }
+ if (ptr)
+ *ptr = p;
+ return 1;
+}
Added: trunk/src/host/qemu-neo1973/dis-asm.h
===================================================================
--- trunk/src/host/qemu-neo1973/dis-asm.h 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/dis-asm.h 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,455 @@
+/* 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
+#define bfd_mach_cpu32 8
+#define bfd_mach_mcf5200 9
+#define bfd_mach_mcf5206e 10
+#define bfd_mach_mcf5307 11
+#define bfd_mach_mcf5407 12
+#define bfd_mach_mcf528x 13
+#define bfd_mach_mcfv4e 14
+#define bfd_mach_mcf521x 15
+#define bfd_mach_mcf5249 16
+#define bfd_mach_mcf547x 17
+#define bfd_mach_mcf548x 18
+ 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 1
+#define bfd_mach_sh2 0x20
+#define bfd_mach_sh_dsp 0x2d
+#define bfd_mach_sh2a 0x2a
+#define bfd_mach_sh2a_nofpu 0x2b
+#define bfd_mach_sh2e 0x2e
+#define bfd_mach_sh3 0x30
+#define bfd_mach_sh3_nommu 0x31
+#define bfd_mach_sh3_dsp 0x3d
+#define bfd_mach_sh3e 0x3e
+#define bfd_mach_sh4 0x40
+#define bfd_mach_sh4_nofpu 0x41
+#define bfd_mach_sh4_nommu_nofpu 0x42
+#define bfd_mach_sh4a 0x4a
+#define bfd_mach_sh4a_nofpu 0x4b
+#define bfd_mach_sh4al_dsp 0x4d
+#define bfd_mach_sh5 0x50
+ 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
+#define ATTRIBUTE_UNUSED __attribute__((unused))
+
+/* 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;
+typedef boolean bfd_boolean;
+
+#endif /* ! defined (DIS_ASM_H) */
Added: trunk/src/host/qemu-neo1973/disas.c
===================================================================
--- trunk/src/host/qemu-neo1973/disas.c 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/disas.c 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,411 @@
+/* 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%" PRIx64 " 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%" PRIx64, 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
+ ppc - nonzero means little endian
+ 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 (flags)
+ 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_M68K)
+ print_insn = print_insn_m68k;
+#elif defined(TARGET_MIPS)
+#ifdef TARGET_WORDS_BIGENDIAN
+ print_insn = print_insn_big_mips;
+#else
+ print_insn = print_insn_little_mips;
+#endif
+#elif defined(TARGET_SH4)
+ disasm_info.mach = bfd_mach_sh4;
+ print_insn = print_insn_sh;
+#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;
+#elif defined(__m68k__)
+ print_insn = print_insn_m68k;
+#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 is included in the code, it is better to
+ display code data too */
+ 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;
+ target_ulong addr;
+
+ 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;
+
+ addr = sym[i].st_value;
+#ifdef TARGET_ARM
+ /* The bottom address bit marks a Thumb symbol. */
+ addr &= ~(target_ulong)1;
+#endif
+ if (orig_addr >= addr
+ && orig_addr < addr + 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 CPUState *monitor_disas_env;
+
+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(monitor_disas_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(CPUState *env,
+ 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_env = env;
+ 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_M68K)
+ print_insn = print_insn_m68k;
+#elif defined(TARGET_MIPS)
+#ifdef TARGET_WORDS_BIGENDIAN
+ print_insn = print_insn_big_mips;
+#else
+ print_insn = print_insn_little_mips;
+#endif
+#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
Added: trunk/src/host/qemu-neo1973/disas.h
===================================================================
--- trunk/src/host/qemu-neo1973/disas.h 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/disas.h 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,21 @@
+#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(CPUState *env,
+ 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 */
Added: trunk/src/host/qemu-neo1973/dyngen-exec.h
===================================================================
--- trunk/src/host/qemu-neo1973/dyngen-exec.h 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/dyngen-exec.h 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,276 @@
+/*
+ * 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__
+
+/* prevent Solaris from trying to typedef FILE in gcc's
+ include/floatingpoint.h which will conflict with the
+ definition down below */
+#ifdef __sun__
+#define _FILEDEFED
+#endif
+
+/* 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;
+// Linux/Sparc64 defines uint64_t
+#if !(defined (__sparc_v9__) && defined(__linux__))
+/* 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
+#endif
+
+/* if Solaris/__sun__, don't typedef int8_t, as it will be typedef'd
+ prior to this and will cause an error in compliation, conflicting
+ with /usr/include/sys/int_types.h, line 75 */
+#ifndef __sun__
+typedef signed char int8_t;
+#endif
+typedef signed short int16_t;
+typedef signed int int32_t;
+// Linux/Sparc64 defines int64_t
+#if !(defined (__sparc_v9__) && defined(__linux__))
+#if defined (__x86_64__) || defined(__ia64)
+typedef signed long int64_t;
+#else
+typedef signed long long int64_t;
+#endif
+#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__
+#ifdef HOST_SOLARIS
+#define AREG0 "g2"
+#define AREG1 "g3"
+#define AREG2 "g4"
+#define AREG3 "g5"
+#define AREG4 "g6"
+#else
+#ifdef __sparc_v9__
+#define AREG0 "g1"
+#define AREG1 "g4"
+#define AREG2 "g5"
+#define AREG3 "g7"
+#else
+#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"
+#endif
+#endif
+#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__("" : : : "memory");
+
+#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; nop")
+#define GOTO_LABEL_PARAM(n) asm volatile ("ba " ASM_NAME(__op_gen_label) #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__) */
Added: trunk/src/host/qemu-neo1973/dyngen-op.h
===================================================================
--- trunk/src/host/qemu-neo1973/dyngen-op.h 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/dyngen-op.h 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,9 @@
+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;
+}
Added: trunk/src/host/qemu-neo1973/dyngen.c
===================================================================
--- trunk/src/host/qemu-neo1973/dyngen.c 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/dyngen.c 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,2783 @@
+/*
+ * Generic Dynamic compiler generator
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * The COFF object format support was extracted from Kazu's QEMU port
+ * to Win32.
+ *
+ * Mach-O Support by Matt Reda and Pierre d'Herbemont
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "config-host.h"
+
+/* NOTE: we test CONFIG_WIN32 instead of _WIN32 to enabled cross
+ compilation */
+#if defined(CONFIG_WIN32)
+#define CONFIG_FORMAT_COFF
+#elif defined(CONFIG_DARWIN)
+#define CONFIG_FORMAT_MACH
+#else
+#define CONFIG_FORMAT_ELF
+#endif
+
+#ifdef CONFIG_FORMAT_ELF
+
+/* elf format definitions. We use these macros to test the CPU to
+ allow cross compilation (this tool must be ran on the build
+ platform) */
+#if defined(HOST_I386)
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_ARCH EM_386
+#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
+#undef ELF_USES_RELOCA
+
+#elif defined(HOST_X86_64)
+
+#define ELF_CLASS ELFCLASS64
+#define ELF_ARCH EM_X86_64
+#define elf_check_arch(x) ((x) == EM_X86_64)
+#define ELF_USES_RELOCA
+
+#elif defined(HOST_PPC)
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_ARCH EM_PPC
+#define elf_check_arch(x) ((x) == EM_PPC)
+#define ELF_USES_RELOCA
+
+#elif defined(HOST_S390)
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_ARCH EM_S390
+#define elf_check_arch(x) ((x) == EM_S390)
+#define ELF_USES_RELOCA
+
+#elif defined(HOST_ALPHA)
+
+#define ELF_CLASS ELFCLASS64
+#define ELF_ARCH EM_ALPHA
+#define elf_check_arch(x) ((x) == EM_ALPHA)
+#define ELF_USES_RELOCA
+
+#elif defined(HOST_IA64)
+
+#define ELF_CLASS ELFCLASS64
+#define ELF_ARCH EM_IA_64
+#define elf_check_arch(x) ((x) == EM_IA_64)
+#define ELF_USES_RELOCA
+
+#elif defined(HOST_SPARC)
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_ARCH EM_SPARC
+#define elf_check_arch(x) ((x) == EM_SPARC || (x) == EM_SPARC32PLUS)
+#define ELF_USES_RELOCA
+
+#elif defined(HOST_SPARC64)
+
+#define ELF_CLASS ELFCLASS64
+#define ELF_ARCH EM_SPARCV9
+#define elf_check_arch(x) ((x) == EM_SPARCV9)
+#define ELF_USES_RELOCA
+
+#elif defined(HOST_ARM)
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_ARCH EM_ARM
+#define elf_check_arch(x) ((x) == EM_ARM)
+#define ELF_USES_RELOC
+
+#elif defined(HOST_M68K)
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_ARCH EM_68K
+#define elf_check_arch(x) ((x) == EM_68K)
+#define ELF_USES_RELOCA
+
+#else
+#error unsupported CPU - please update the code
+#endif
+
+#include "elf.h"
+
+#if ELF_CLASS == ELFCLASS32
+typedef int32_t host_long;
+typedef uint32_t host_ulong;
+#define swabls(x) swab32s(x)
+#define swablss(x) swab32ss(x)
+#else
+typedef int64_t host_long;
+typedef uint64_t host_ulong;
+#define swabls(x) swab64s(x)
+#define swablss(x) swab64ss(x)
+#endif
+
+#ifdef ELF_USES_RELOCA
+#define SHT_RELOC SHT_RELA
+#else
+#define SHT_RELOC SHT_REL
+#endif
+
+#define EXE_RELOC ELF_RELOC
+#define EXE_SYM ElfW(Sym)
+
+#endif /* CONFIG_FORMAT_ELF */
+
+#ifdef CONFIG_FORMAT_COFF
+
+#include "a.out.h"
+
+typedef int32_t host_long;
+typedef uint32_t host_ulong;
+
+#define FILENAMELEN 256
+
+typedef struct coff_sym {
+ struct external_syment *st_syment;
+ char st_name[FILENAMELEN];
+ uint32_t st_value;
+ int st_size;
+ uint8_t st_type;
+ uint8_t st_shndx;
+} coff_Sym;
+
+typedef struct coff_rel {
+ struct external_reloc *r_reloc;
+ int r_offset;
+ uint8_t r_type;
+} coff_Rel;
+
+#define EXE_RELOC struct coff_rel
+#define EXE_SYM struct coff_sym
+
+#endif /* CONFIG_FORMAT_COFF */
+
+#ifdef CONFIG_FORMAT_MACH
+
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
+#include <mach-o/reloc.h>
+#include <mach-o/ppc/reloc.h>
+
+# define check_mach_header(x) (x.magic == MH_MAGIC)
+typedef int32_t host_long;
+typedef uint32_t host_ulong;
+
+struct nlist_extended
+{
+ union {
+ char *n_name;
+ long n_strx;
+ } n_un;
+ unsigned char n_type;
+ unsigned char n_sect;
+ short st_desc;
+ unsigned long st_value;
+ unsigned long st_size;
+};
+
+#define EXE_RELOC struct relocation_info
+#define EXE_SYM struct nlist_extended
+
+#endif /* CONFIG_FORMAT_MACH */
+
+#include "bswap.h"
+
+enum {
+ OUT_GEN_OP,
+ OUT_CODE,
+ OUT_INDEX_OP,
+};
+
+/* all dynamically generated functions begin with this code */
+#define OP_PREFIX "op_"
+
+int do_swap;
+
+void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "dyngen: ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ exit(1);
+}
+
+void *load_data(int fd, long offset, unsigned int size)
+{
+ char *data;
+
+ data = malloc(size);
+ if (!data)
+ return NULL;
+ lseek(fd, offset, SEEK_SET);
+ if (read(fd, data, size) != size) {
+ free(data);
+ return NULL;
+ }
+ return data;
+}
+
+int strstart(const char *str, const char *val, const char **ptr)
+{
+ const char *p, *q;
+ p = str;
+ q = val;
+ while (*q != '\0') {
+ if (*p != *q)
+ return 0;
+ p++;
+ q++;
+ }
+ if (ptr)
+ *ptr = p;
+ return 1;
+}
+
+void pstrcpy(char *buf, int buf_size, const char *str)
+{
+ int c;
+ char *q = buf;
+
+ if (buf_size <= 0)
+ return;
+
+ for(;;) {
+ c = *str++;
+ if (c == 0 || q >= buf + buf_size - 1)
+ break;
+ *q++ = c;
+ }
+ *q = '\0';
+}
+
+void swab16s(uint16_t *p)
+{
+ *p = bswap16(*p);
+}
+
+void swab32s(uint32_t *p)
+{
+ *p = bswap32(*p);
+}
+
+void swab32ss(int32_t *p)
+{
+ *p = bswap32(*p);
+}
+
+void swab64s(uint64_t *p)
+{
+ *p = bswap64(*p);
+}
+
+void swab64ss(int64_t *p)
+{
+ *p = bswap64(*p);
+}
+
+uint16_t get16(uint16_t *p)
+{
+ uint16_t val;
+ val = *p;
+ if (do_swap)
+ val = bswap16(val);
+ return val;
+}
+
+uint32_t get32(uint32_t *p)
+{
+ uint32_t val;
+ val = *p;
+ if (do_swap)
+ val = bswap32(val);
+ return val;
+}
+
+void put16(uint16_t *p, uint16_t val)
+{
+ if (do_swap)
+ val = bswap16(val);
+ *p = val;
+}
+
+void put32(uint32_t *p, uint32_t val)
+{
+ if (do_swap)
+ val = bswap32(val);
+ *p = val;
+}
+
+/* executable information */
+EXE_SYM *symtab;
+int nb_syms;
+int text_shndx;
+uint8_t *text;
+EXE_RELOC *relocs;
+int nb_relocs;
+
+#ifdef CONFIG_FORMAT_ELF
+
+/* ELF file info */
+struct elf_shdr *shdr;
+uint8_t **sdata;
+struct elfhdr ehdr;
+char *strtab;
+
+int elf_must_swap(struct elfhdr *h)
+{
+ union {
+ uint32_t i;
+ uint8_t b[4];
+ } swaptest;
+
+ swaptest.i = 1;
+ return (h->e_ident[EI_DATA] == ELFDATA2MSB) !=
+ (swaptest.b[0] == 0);
+}
+
+void elf_swap_ehdr(struct elfhdr *h)
+{
+ swab16s(&h->e_type); /* Object file type */
+ swab16s(&h-> e_machine); /* Architecture */
+ swab32s(&h-> e_version); /* Object file version */
+ swabls(&h-> e_entry); /* Entry point virtual address */
+ swabls(&h-> e_phoff); /* Program header table file offset */
+ swabls(&h-> e_shoff); /* Section header table file offset */
+ swab32s(&h-> e_flags); /* Processor-specific flags */
+ swab16s(&h-> e_ehsize); /* ELF header size in bytes */
+ swab16s(&h-> e_phentsize); /* Program header table entry size */
+ swab16s(&h-> e_phnum); /* Program header table entry count */
+ swab16s(&h-> e_shentsize); /* Section header table entry size */
+ swab16s(&h-> e_shnum); /* Section header table entry count */
+ swab16s(&h-> e_shstrndx); /* Section header string table index */
+}
+
+void elf_swap_shdr(struct elf_shdr *h)
+{
+ swab32s(&h-> sh_name); /* Section name (string tbl index) */
+ swab32s(&h-> sh_type); /* Section type */
+ swabls(&h-> sh_flags); /* Section flags */
+ swabls(&h-> sh_addr); /* Section virtual addr at execution */
+ swabls(&h-> sh_offset); /* Section file offset */
+ swabls(&h-> sh_size); /* Section size in bytes */
+ swab32s(&h-> sh_link); /* Link to another section */
+ swab32s(&h-> sh_info); /* Additional section information */
+ swabls(&h-> sh_addralign); /* Section alignment */
+ swabls(&h-> sh_entsize); /* Entry size if section holds table */
+}
+
+void elf_swap_phdr(struct elf_phdr *h)
+{
+ swab32s(&h->p_type); /* Segment type */
+ swabls(&h->p_offset); /* Segment file offset */
+ swabls(&h->p_vaddr); /* Segment virtual address */
+ swabls(&h->p_paddr); /* Segment physical address */
+ swabls(&h->p_filesz); /* Segment size in file */
+ swabls(&h->p_memsz); /* Segment size in memory */
+ swab32s(&h->p_flags); /* Segment flags */
+ swabls(&h->p_align); /* Segment alignment */
+}
+
+void elf_swap_rel(ELF_RELOC *rel)
+{
+ swabls(&rel->r_offset);
+ swabls(&rel->r_info);
+#ifdef ELF_USES_RELOCA
+ swablss(&rel->r_addend);
+#endif
+}
+
+struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *shstr,
+ const char *name)
+{
+ int i;
+ const char *shname;
+ struct elf_shdr *sec;
+
+ for(i = 0; i < shnum; i++) {
+ sec = &shdr[i];
+ if (!sec->sh_name)
+ continue;
+ shname = shstr + sec->sh_name;
+ if (!strcmp(shname, name))
+ return sec;
+ }
+ return NULL;
+}
+
+int find_reloc(int sh_index)
+{
+ struct elf_shdr *sec;
+ int i;
+
+ for(i = 0; i < ehdr.e_shnum; i++) {
+ sec = &shdr[i];
+ if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index)
+ return i;
+ }
+ return 0;
+}
+
+static host_ulong get_rel_offset(EXE_RELOC *rel)
+{
+ return rel->r_offset;
+}
+
+static char *get_rel_sym_name(EXE_RELOC *rel)
+{
+ return strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
+}
+
+static char *get_sym_name(EXE_SYM *sym)
+{
+ return strtab + sym->st_name;
+}
+
+/* load an elf object file */
+int load_object(const char *filename)
+{
+ int fd;
+ struct elf_shdr *sec, *symtab_sec, *strtab_sec, *text_sec;
+ int i, j;
+ ElfW(Sym) *sym;
+ char *shstr;
+ ELF_RELOC *rel;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ error("can't open file '%s'", filename);
+
+ /* Read ELF header. */
+ if (read(fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr))
+ error("unable to read file header");
+
+ /* Check ELF identification. */
+ if (ehdr.e_ident[EI_MAG0] != ELFMAG0
+ || ehdr.e_ident[EI_MAG1] != ELFMAG1
+ || ehdr.e_ident[EI_MAG2] != ELFMAG2
+ || ehdr.e_ident[EI_MAG3] != ELFMAG3
+ || ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
+ error("bad ELF header");
+ }
+
+ do_swap = elf_must_swap(&ehdr);
+ if (do_swap)
+ elf_swap_ehdr(&ehdr);
+ if (ehdr.e_ident[EI_CLASS] != ELF_CLASS)
+ error("Unsupported ELF class");
+ if (ehdr.e_type != ET_REL)
+ error("ELF object file expected");
+ if (ehdr.e_version != EV_CURRENT)
+ error("Invalid ELF version");
+ if (!elf_check_arch(ehdr.e_machine))
+ error("Unsupported CPU (e_machine=%d)", ehdr.e_machine);
+
+ /* read section headers */
+ shdr = load_data(fd, ehdr.e_shoff, ehdr.e_shnum * sizeof(struct elf_shdr));
+ if (do_swap) {
+ for(i = 0; i < ehdr.e_shnum; i++) {
+ elf_swap_shdr(&shdr[i]);
+ }
+ }
+
+ /* read all section data */
+ sdata = malloc(sizeof(void *) * ehdr.e_shnum);
+ memset(sdata, 0, sizeof(void *) * ehdr.e_shnum);
+
+ for(i = 0;i < ehdr.e_shnum; i++) {
+ sec = &shdr[i];
+ if (sec->sh_type != SHT_NOBITS)
+ sdata[i] = load_data(fd, sec->sh_offset, sec->sh_size);
+ }
+
+ sec = &shdr[ehdr.e_shstrndx];
+ shstr = (char *)sdata[ehdr.e_shstrndx];
+
+ /* swap relocations */
+ for(i = 0; i < ehdr.e_shnum; i++) {
+ sec = &shdr[i];
+ if (sec->sh_type == SHT_RELOC) {
+ nb_relocs = sec->sh_size / sec->sh_entsize;
+ if (do_swap) {
+ for(j = 0, rel = (ELF_RELOC *)sdata[i]; j < nb_relocs; j++, rel++)
+ elf_swap_rel(rel);
+ }
+ }
+ }
+ /* text section */
+
+ text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text");
+ if (!text_sec)
+ error("could not find .text section");
+ text_shndx = text_sec - shdr;
+ text = sdata[text_shndx];
+
+ /* find text relocations, if any */
+ relocs = NULL;
+ nb_relocs = 0;
+ i = find_reloc(text_shndx);
+ if (i != 0) {
+ relocs = (ELF_RELOC *)sdata[i];
+ nb_relocs = shdr[i].sh_size / shdr[i].sh_entsize;
+ }
+
+ symtab_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".symtab");
+ if (!symtab_sec)
+ error("could not find .symtab section");
+ strtab_sec = &shdr[symtab_sec->sh_link];
+
+ symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr];
+ strtab = (char *)sdata[symtab_sec->sh_link];
+
+ nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym));
+ if (do_swap) {
+ for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
+ swab32s(&sym->st_name);
+ swabls(&sym->st_value);
+ swabls(&sym->st_size);
+ swab16s(&sym->st_shndx);
+ }
+ }
+ close(fd);
+ return 0;
+}
+
+#endif /* CONFIG_FORMAT_ELF */
+
+#ifdef CONFIG_FORMAT_COFF
+
+/* COFF file info */
+struct external_scnhdr *shdr;
+uint8_t **sdata;
+struct external_filehdr fhdr;
+struct external_syment *coff_symtab;
+char *strtab;
+int coff_text_shndx, coff_data_shndx;
+
+int data_shndx;
+
+#define STRTAB_SIZE 4
+
+#define DIR32 0x06
+#define DISP32 0x14
+
+#define T_FUNCTION 0x20
+#define C_EXTERNAL 2
+
+void sym_ent_name(struct external_syment *ext_sym, EXE_SYM *sym)
+{
+ char *q;
+ int c, i, len;
+
+ if (ext_sym->e.e.e_zeroes != 0) {
+ q = sym->st_name;
+ for(i = 0; i < 8; i++) {
+ c = ext_sym->e.e_name[i];
+ if (c == '\0')
+ break;
+ *q++ = c;
+ }
+ *q = '\0';
+ } else {
+ pstrcpy(sym->st_name, sizeof(sym->st_name), strtab + ext_sym->e.e.e_offset);
+ }
+
+ /* now convert the name to a C name (suppress the leading '_') */
+ if (sym->st_name[0] == '_') {
+ len = strlen(sym->st_name);
+ memmove(sym->st_name, sym->st_name + 1, len - 1);
+ sym->st_name[len - 1] = '\0';
+ }
+}
+
+char *name_for_dotdata(struct coff_rel *rel)
+{
+ int i;
+ struct coff_sym *sym;
+ uint32_t text_data;
+
+ text_data = *(uint32_t *)(text + rel->r_offset);
+
+ for (i = 0, sym = symtab; i < nb_syms; i++, sym++) {
+ if (sym->st_syment->e_scnum == data_shndx &&
+ text_data >= sym->st_value &&
+ text_data < sym->st_value + sym->st_size) {
+
+ return sym->st_name;
+
+ }
+ }
+ return NULL;
+}
+
+static char *get_sym_name(EXE_SYM *sym)
+{
+ return sym->st_name;
+}
+
+static char *get_rel_sym_name(EXE_RELOC *rel)
+{
+ char *name;
+ name = get_sym_name(symtab + *(uint32_t *)(rel->r_reloc->r_symndx));
+ if (!strcmp(name, ".data"))
+ name = name_for_dotdata(rel);
+ if (name[0] == '.')
+ return NULL;
+ return name;
+}
+
+static host_ulong get_rel_offset(EXE_RELOC *rel)
+{
+ return rel->r_offset;
+}
+
+struct external_scnhdr *find_coff_section(struct external_scnhdr *shdr, int shnum, const char *name)
+{
+ int i;
+ const char *shname;
+ struct external_scnhdr *sec;
+
+ for(i = 0; i < shnum; i++) {
+ sec = &shdr[i];
+ if (!sec->s_name)
+ continue;
+ shname = sec->s_name;
+ if (!strcmp(shname, name))
+ return sec;
+ }
+ return NULL;
+}
+
+/* load a coff object file */
+int load_object(const char *filename)
+{
+ int fd;
+ struct external_scnhdr *sec, *text_sec, *data_sec;
+ int i;
+ struct external_syment *ext_sym;
+ struct external_reloc *coff_relocs;
+ struct external_reloc *ext_rel;
+ uint32_t *n_strtab;
+ EXE_SYM *sym;
+ EXE_RELOC *rel;
+
+ fd = open(filename, O_RDONLY
+#ifdef _WIN32
+ | O_BINARY
+#endif
+ );
+ if (fd < 0)
+ error("can't open file '%s'", filename);
+
+ /* Read COFF header. */
+ if (read(fd, &fhdr, sizeof (fhdr)) != sizeof (fhdr))
+ error("unable to read file header");
+
+ /* Check COFF identification. */
+ if (fhdr.f_magic != I386MAGIC) {
+ error("bad COFF header");
+ }
+ do_swap = 0;
+
+ /* read section headers */
+ shdr = load_data(fd, sizeof(struct external_filehdr) + fhdr.f_opthdr, fhdr.f_nscns * sizeof(struct external_scnhdr));
+
+ /* read all section data */
+ sdata = malloc(sizeof(void *) * fhdr.f_nscns);
+ memset(sdata, 0, sizeof(void *) * fhdr.f_nscns);
+
+ const char *p;
+ for(i = 0;i < fhdr.f_nscns; i++) {
+ sec = &shdr[i];
+ if (!strstart(sec->s_name, ".bss", &p))
+ sdata[i] = load_data(fd, sec->s_scnptr, sec->s_size);
+ }
+
+
+ /* text section */
+ text_sec = find_coff_section(shdr, fhdr.f_nscns, ".text");
+ if (!text_sec)
+ error("could not find .text section");
+ coff_text_shndx = text_sec - shdr;
+ text = sdata[coff_text_shndx];
+
+ /* data section */
+ data_sec = find_coff_section(shdr, fhdr.f_nscns, ".data");
+ if (!data_sec)
+ error("could not find .data section");
+ coff_data_shndx = data_sec - shdr;
+
+ coff_symtab = load_data(fd, fhdr.f_symptr, fhdr.f_nsyms*SYMESZ);
+ for (i = 0, ext_sym = coff_symtab; i < nb_syms; i++, ext_sym++) {
+ for(i=0;i<8;i++)
+ printf(" %02x", ((uint8_t *)ext_sym->e.e_name)[i]);
+ printf("\n");
+ }
+
+
+ n_strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), STRTAB_SIZE);
+ strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), *n_strtab);
+
+ nb_syms = fhdr.f_nsyms;
+
+ for (i = 0, ext_sym = coff_symtab; i < nb_syms; i++, ext_sym++) {
+ if (strstart(ext_sym->e.e_name, ".text", NULL))
+ text_shndx = ext_sym->e_scnum;
+ if (strstart(ext_sym->e.e_name, ".data", NULL))
+ data_shndx = ext_sym->e_scnum;
+ }
+
+ /* set coff symbol */
+ symtab = malloc(sizeof(struct coff_sym) * nb_syms);
+
+ int aux_size, j;
+ for (i = 0, ext_sym = coff_symtab, sym = symtab; i < nb_syms; i++, ext_sym++, sym++) {
+ memset(sym, 0, sizeof(*sym));
+ sym->st_syment = ext_sym;
+ sym_ent_name(ext_sym, sym);
+ sym->st_value = ext_sym->e_value;
+
+ aux_size = *(int8_t *)ext_sym->e_numaux;
+ if (ext_sym->e_scnum == text_shndx && ext_sym->e_type == T_FUNCTION) {
+ for (j = aux_size + 1; j < nb_syms - i; j++) {
+ if ((ext_sym + j)->e_scnum == text_shndx &&
+ (ext_sym + j)->e_type == T_FUNCTION ){
+ sym->st_size = (ext_sym + j)->e_value - ext_sym->e_value;
+ break;
+ } else if (j == nb_syms - i - 1) {
+ sec = &shdr[coff_text_shndx];
+ sym->st_size = sec->s_size - ext_sym->e_value;
+ break;
+ }
+ }
+ } else if (ext_sym->e_scnum == data_shndx && *(uint8_t *)ext_sym->e_sclass == C_EXTERNAL) {
+ for (j = aux_size + 1; j < nb_syms - i; j++) {
+ if ((ext_sym + j)->e_scnum == data_shndx) {
+ sym->st_size = (ext_sym + j)->e_value - ext_sym->e_value;
+ break;
+ } else if (j == nb_syms - i - 1) {
+ sec = &shdr[coff_data_shndx];
+ sym->st_size = sec->s_size - ext_sym->e_value;
+ break;
+ }
+ }
+ } else {
+ sym->st_size = 0;
+ }
+
+ sym->st_type = ext_sym->e_type;
+ sym->st_shndx = ext_sym->e_scnum;
+ }
+
+
+ /* find text relocations, if any */
+ sec = &shdr[coff_text_shndx];
+ coff_relocs = load_data(fd, sec->s_relptr, sec->s_nreloc*RELSZ);
+ nb_relocs = sec->s_nreloc;
+
+ /* set coff relocation */
+ relocs = malloc(sizeof(struct coff_rel) * nb_relocs);
+ for (i = 0, ext_rel = coff_relocs, rel = relocs; i < nb_relocs;
+ i++, ext_rel++, rel++) {
+ memset(rel, 0, sizeof(*rel));
+ rel->r_reloc = ext_rel;
+ rel->r_offset = *(uint32_t *)ext_rel->r_vaddr;
+ rel->r_type = *(uint16_t *)ext_rel->r_type;
+ }
+ return 0;
+}
+
+#endif /* CONFIG_FORMAT_COFF */
+
+#ifdef CONFIG_FORMAT_MACH
+
+/* File Header */
+struct mach_header mach_hdr;
+
+/* commands */
+struct segment_command *segment = 0;
+struct dysymtab_command *dysymtabcmd = 0;
+struct symtab_command *symtabcmd = 0;
+
+/* section */
+struct section *section_hdr;
+struct section *text_sec_hdr;
+uint8_t **sdata;
+
+/* relocs */
+struct relocation_info *relocs;
+
+/* symbols */
+EXE_SYM *symtab;
+struct nlist *symtab_std;
+char *strtab;
+
+/* indirect symbols */
+uint32_t *tocdylib;
+
+/* Utility functions */
+
+static inline char *find_str_by_index(int index)
+{
+ return strtab+index;
+}
+
+/* Used by dyngen common code */
+static char *get_sym_name(EXE_SYM *sym)
+{
+ char *name = find_str_by_index(sym->n_un.n_strx);
+
+ if ( sym->n_type & N_STAB ) /* Debug symbols are ignored */
+ return "debug";
+
+ if(!name)
+ return name;
+ if(name[0]=='_')
+ return name + 1;
+ else
+ return name;
+}
+
+/* find a section index given its segname, sectname */
+static int find_mach_sec_index(struct section *section_hdr, int shnum, const char *segname,
+ const char *sectname)
+{
+ int i;
+ struct section *sec = section_hdr;
+
+ for(i = 0; i < shnum; i++, sec++) {
+ if (!sec->segname || !sec->sectname)
+ continue;
+ if (!strcmp(sec->sectname, sectname) && !strcmp(sec->segname, segname))
+ return i;
+ }
+ return -1;
+}
+
+/* find a section header given its segname, sectname */
+struct section *find_mach_sec_hdr(struct section *section_hdr, int shnum, const char *segname,
+ const char *sectname)
+{
+ int index = find_mach_sec_index(section_hdr, shnum, segname, sectname);
+ if(index == -1)
+ return NULL;
+ return section_hdr+index;
+}
+
+
+static inline void fetch_next_pair_value(struct relocation_info * rel, unsigned int *value)
+{
+ struct scattered_relocation_info * scarel;
+
+ if(R_SCATTERED & rel->r_address) {
+ scarel = (struct scattered_relocation_info*)rel;
+ if(scarel->r_type != PPC_RELOC_PAIR)
+ error("fetch_next_pair_value: looking for a pair which was not found (1)");
+ *value = scarel->r_value;
+ } else {
+ if(rel->r_type != PPC_RELOC_PAIR)
+ error("fetch_next_pair_value: looking for a pair which was not found (2)");
+ *value = rel->r_address;
+ }
+}
+
+/* find a sym name given its value, in a section number */
+static const char * find_sym_with_value_and_sec_number( int value, int sectnum, int * offset )
+{
+ int i, ret = -1;
+
+ for( i = 0 ; i < nb_syms; i++ )
+ {
+ if( !(symtab[i].n_type & N_STAB) && (symtab[i].n_type & N_SECT) &&
+ (symtab[i].n_sect == sectnum) && (symtab[i].st_value <= value) )
+ {
+ if( (ret<0) || (symtab[i].st_value >= symtab[ret].st_value) )
+ ret = i;
+ }
+ }
+ if( ret < 0 ) {
+ *offset = 0;
+ return 0;
+ } else {
+ *offset = value - symtab[ret].st_value;
+ return get_sym_name(&symtab[ret]);
+ }
+}
+
+/*
+ * Find symbol name given a (virtual) address, and a section which is of type
+ * S_NON_LAZY_SYMBOL_POINTERS or S_LAZY_SYMBOL_POINTERS or S_SYMBOL_STUBS
+ */
+static const char * find_reloc_name_in_sec_ptr(int address, struct section * sec_hdr)
+{
+ unsigned int tocindex, symindex, size;
+ const char *name = 0;
+
+ /* Sanity check */
+ if(!( address >= sec_hdr->addr && address < (sec_hdr->addr + sec_hdr->size) ) )
+ return (char*)0;
+
+ if( sec_hdr->flags & S_SYMBOL_STUBS ){
+ size = sec_hdr->reserved2;
+ if(size == 0)
+ error("size = 0");
+
+ }
+ else if( sec_hdr->flags & S_LAZY_SYMBOL_POINTERS ||
+ sec_hdr->flags & S_NON_LAZY_SYMBOL_POINTERS)
+ size = sizeof(unsigned long);
+ else
+ return 0;
+
+ /* Compute our index in toc */
+ tocindex = (address - sec_hdr->addr)/size;
+ symindex = tocdylib[sec_hdr->reserved1 + tocindex];
+
+ name = get_sym_name(&symtab[symindex]);
+
+ return name;
+}
+
+static const char * find_reloc_name_given_its_address(int address)
+{
+ unsigned int i;
+ for(i = 0; i < segment->nsects ; i++)
+ {
+ const char * name = find_reloc_name_in_sec_ptr(address, §ion_hdr[i]);
+ if((long)name != -1)
+ return name;
+ }
+ return 0;
+}
+
+static const char * get_reloc_name(EXE_RELOC * rel, int * sslide)
+{
+ char * name = 0;
+ struct scattered_relocation_info * sca_rel = (struct scattered_relocation_info*)rel;
+ int sectnum = rel->r_symbolnum;
+ int sectoffset;
+ int other_half=0;
+
+ /* init the slide value */
+ *sslide = 0;
+
+ if(R_SCATTERED & rel->r_address)
+ return (char *)find_reloc_name_given_its_address(sca_rel->r_value);
+
+ if(rel->r_extern)
+ {
+ /* ignore debug sym */
+ if ( symtab[rel->r_symbolnum].n_type & N_STAB )
+ return 0;
+ return get_sym_name(&symtab[rel->r_symbolnum]);
+ }
+
+ /* Intruction contains an offset to the symbols pointed to, in the rel->r_symbolnum section */
+ sectoffset = *(uint32_t *)(text + rel->r_address) & 0xffff;
+
+ if(sectnum==0xffffff)
+ return 0;
+
+ /* Sanity Check */
+ if(sectnum > segment->nsects)
+ error("sectnum > segment->nsects");
+
+ switch(rel->r_type)
+ {
+ case PPC_RELOC_LO16: fetch_next_pair_value(rel+1, &other_half); sectoffset |= (other_half << 16);
+ break;
+ case PPC_RELOC_HI16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (sectoffset << 16) | (uint16_t)(other_half & 0xffff);
+ break;
+ case PPC_RELOC_HA16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (sectoffset << 16) + (int16_t)(other_half & 0xffff);
+ break;
+ case PPC_RELOC_BR24:
+ sectoffset = ( *(uint32_t *)(text + rel->r_address) & 0x03fffffc );
+ if (sectoffset & 0x02000000) sectoffset |= 0xfc000000;
+ break;
+ default:
+ error("switch(rel->type) not found");
+ }
+
+ if(rel->r_pcrel)
+ sectoffset += rel->r_address;
+
+ if (rel->r_type == PPC_RELOC_BR24)
+ name = (char *)find_reloc_name_in_sec_ptr((int)sectoffset, §ion_hdr[sectnum-1]);
+
+ /* search it in the full symbol list, if not found */
+ if(!name)
+ name = (char *)find_sym_with_value_and_sec_number(sectoffset, sectnum, sslide);
+
+ return name;
+}
+
+/* Used by dyngen common code */
+static const char * get_rel_sym_name(EXE_RELOC * rel)
+{
+ int sslide;
+ return get_reloc_name( rel, &sslide);
+}
+
+/* Used by dyngen common code */
+static host_ulong get_rel_offset(EXE_RELOC *rel)
+{
+ struct scattered_relocation_info * sca_rel = (struct scattered_relocation_info*)rel;
+ if(R_SCATTERED & rel->r_address)
+ return sca_rel->r_address;
+ else
+ return rel->r_address;
+}
+
+/* load a mach-o object file */
+int load_object(const char *filename)
+{
+ int fd;
+ unsigned int offset_to_segment = 0;
+ unsigned int offset_to_dysymtab = 0;
+ unsigned int offset_to_symtab = 0;
+ struct load_command lc;
+ unsigned int i, j;
+ EXE_SYM *sym;
+ struct nlist *syment;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ error("can't open file '%s'", filename);
+
+ /* Read Mach header. */
+ if (read(fd, &mach_hdr, sizeof (mach_hdr)) != sizeof (mach_hdr))
+ error("unable to read file header");
+
+ /* Check Mach identification. */
+ if (!check_mach_header(mach_hdr)) {
+ error("bad Mach header");
+ }
+
+ if (mach_hdr.cputype != CPU_TYPE_POWERPC)
+ error("Unsupported CPU");
+
+ if (mach_hdr.filetype != MH_OBJECT)
+ error("Unsupported Mach Object");
+
+ /* read segment headers */
+ for(i=0, j=sizeof(mach_hdr); i<mach_hdr.ncmds ; i++)
+ {
+ if(read(fd, &lc, sizeof(struct load_command)) != sizeof(struct load_command))
+ error("unable to read load_command");
+ if(lc.cmd == LC_SEGMENT)
+ {
+ offset_to_segment = j;
+ lseek(fd, offset_to_segment, SEEK_SET);
+ segment = malloc(sizeof(struct segment_command));
+ if(read(fd, segment, sizeof(struct segment_command)) != sizeof(struct segment_command))
+ error("unable to read LC_SEGMENT");
+ }
+ if(lc.cmd == LC_DYSYMTAB)
+ {
+ offset_to_dysymtab = j;
+ lseek(fd, offset_to_dysymtab, SEEK_SET);
+ dysymtabcmd = malloc(sizeof(struct dysymtab_command));
+ if(read(fd, dysymtabcmd, sizeof(struct dysymtab_command)) != sizeof(struct dysymtab_command))
+ error("unable to read LC_DYSYMTAB");
+ }
+ if(lc.cmd == LC_SYMTAB)
+ {
+ offset_to_symtab = j;
+ lseek(fd, offset_to_symtab, SEEK_SET);
+ symtabcmd = malloc(sizeof(struct symtab_command));
+ if(read(fd, symtabcmd, sizeof(struct symtab_command)) != sizeof(struct symtab_command))
+ error("unable to read LC_SYMTAB");
+ }
+ j+=lc.cmdsize;
+
+ lseek(fd, j, SEEK_SET);
+ }
+
+ if(!segment)
+ error("unable to find LC_SEGMENT");
+
+ /* read section headers */
+ section_hdr = load_data(fd, offset_to_segment + sizeof(struct segment_command), segment->nsects * sizeof(struct section));
+
+ /* read all section data */
+ sdata = (uint8_t **)malloc(sizeof(void *) * segment->nsects);
+ memset(sdata, 0, sizeof(void *) * segment->nsects);
+
+ /* Load the data in section data */
+ for(i = 0; i < segment->nsects; i++) {
+ sdata[i] = load_data(fd, section_hdr[i].offset, section_hdr[i].size);
+ }
+
+ /* text section */
+ text_sec_hdr = find_mach_sec_hdr(section_hdr, segment->nsects, SEG_TEXT, SECT_TEXT);
+ i = find_mach_sec_index(section_hdr, segment->nsects, SEG_TEXT, SECT_TEXT);
+ if (i == -1 || !text_sec_hdr)
+ error("could not find __TEXT,__text section");
+ text = sdata[i];
+
+ /* Make sure dysym was loaded */
+ if(!(int)dysymtabcmd)
+ error("could not find __DYSYMTAB segment");
+
+ /* read the table of content of the indirect sym */
+ tocdylib = load_data( fd, dysymtabcmd->indirectsymoff, dysymtabcmd->nindirectsyms * sizeof(uint32_t) );
+
+ /* Make sure symtab was loaded */
+ if(!(int)symtabcmd)
+ error("could not find __SYMTAB segment");
+ nb_syms = symtabcmd->nsyms;
+
+ symtab_std = load_data(fd, symtabcmd->symoff, symtabcmd->nsyms * sizeof(struct nlist));
+ strtab = load_data(fd, symtabcmd->stroff, symtabcmd->strsize);
+
+ symtab = malloc(sizeof(EXE_SYM) * nb_syms);
+
+ /* Now transform the symtab, to an extended version, with the sym size, and the C name */
+ for(i = 0, sym = symtab, syment = symtab_std; i < nb_syms; i++, sym++, syment++) {
+ struct nlist *sym_follow, *sym_next = 0;
+ unsigned int j;
+ memset(sym, 0, sizeof(*sym));
+
+ if ( syment->n_type & N_STAB ) /* Debug symbols are skipped */
+ continue;
+
+ memcpy(sym, syment, sizeof(*syment));
+
+ /* Find the following symbol in order to get the current symbol size */
+ for(j = 0, sym_follow = symtab_std; j < nb_syms; j++, sym_follow++) {
+ if ( sym_follow->n_sect != 1 || sym_follow->n_type & N_STAB || !(sym_follow->n_value > sym->st_value))
+ continue;
+ if(!sym_next) {
+ sym_next = sym_follow;
+ continue;
+ }
+ if(!(sym_next->n_value > sym_follow->n_value))
+ continue;
+ sym_next = sym_follow;
+ }
+ if(sym_next)
+ sym->st_size = sym_next->n_value - sym->st_value;
+ else
+ sym->st_size = text_sec_hdr->size - sym->st_value;
+ }
+
+ /* Find Reloc */
+ relocs = load_data(fd, text_sec_hdr->reloff, text_sec_hdr->nreloc * sizeof(struct relocation_info));
+ nb_relocs = text_sec_hdr->nreloc;
+
+ close(fd);
+ return 0;
+}
+
+#endif /* CONFIG_FORMAT_MACH */
+
+void get_reloc_expr(char *name, int name_size, const char *sym_name)
+{
+ const char *p;
+
+ if (strstart(sym_name, "__op_param", &p)) {
+ snprintf(name, name_size, "param%s", p);
+ } else if (strstart(sym_name, "__op_gen_label", &p)) {
+ snprintf(name, name_size, "gen_labels[param%s]", p);
+ } else {
+#ifdef HOST_SPARC
+ if (sym_name[0] == '.')
+ snprintf(name, name_size,
+ "(long)(&__dot_%s)",
+ sym_name + 1);
+ else
+#endif
+ snprintf(name, name_size, "(long)(&%s)", sym_name);
+ }
+}
+
+#ifdef HOST_IA64
+
+#define PLT_ENTRY_SIZE 16 /* 1 bundle containing "brl" */
+
+struct plt_entry {
+ struct plt_entry *next;
+ const char *name;
+ unsigned long addend;
+} *plt_list;
+
+static int
+get_plt_index (const char *name, unsigned long addend)
+{
+ struct plt_entry *plt, *prev= NULL;
+ int index = 0;
+
+ /* see if we already have an entry for this target: */
+ for (plt = plt_list; plt; ++index, prev = plt, plt = plt->next)
+ if (strcmp(plt->name, name) == 0 && plt->addend == addend)
+ return index;
+
+ /* nope; create a new PLT entry: */
+
+ plt = malloc(sizeof(*plt));
+ if (!plt) {
+ perror("malloc");
+ exit(1);
+ }
+ memset(plt, 0, sizeof(*plt));
+ plt->name = strdup(name);
+ plt->addend = addend;
+
+ /* append to plt-list: */
+ if (prev)
+ prev->next = plt;
+ else
+ plt_list = plt;
+ return index;
+}
+
+#endif
+
+#ifdef HOST_ARM
+
+int arm_emit_ldr_info(const char *name, unsigned long start_offset,
+ FILE *outfile, uint8_t *p_start, uint8_t *p_end,
+ ELF_RELOC *relocs, int nb_relocs)
+{
+ uint8_t *p;
+ uint32_t insn;
+ int offset, min_offset, pc_offset, data_size, spare, max_pool;
+ uint8_t data_allocated[1024];
+ unsigned int data_index;
+ int type;
+
+ memset(data_allocated, 0, sizeof(data_allocated));
+
+ p = p_start;
+ min_offset = p_end - p_start;
+ spare = 0x7fffffff;
+ while (p < p_start + min_offset) {
+ insn = get32((uint32_t *)p);
+ /* TODO: Armv5e ldrd. */
+ /* TODO: VFP load. */
+ if ((insn & 0x0d5f0000) == 0x051f0000) {
+ /* ldr reg, [pc, #im] */
+ offset = insn & 0xfff;
+ if (!(insn & 0x00800000))
+ offset = -offset;
+ max_pool = 4096;
+ type = 0;
+ } else if ((insn & 0x0e5f0f00) == 0x0c1f0100) {
+ /* FPA ldf. */
+ offset = (insn & 0xff) << 2;
+ if (!(insn & 0x00800000))
+ offset = -offset;
+ max_pool = 1024;
+ type = 1;
+ } else if ((insn & 0x0fff0000) == 0x028f0000) {
+ /* Some gcc load a doubleword immediate with
+ add regN, pc, #imm
+ ldmia regN, {regN, regM}
+ Hope and pray the compiler never generates somethin like
+ add reg, pc, #imm1; ldr reg, [reg, #-imm2]; */
+ int r;
+
+ r = (insn & 0xf00) >> 7;
+ offset = ((insn & 0xff) >> r) | ((insn & 0xff) << (32 - r));
+ max_pool = 1024;
+ type = 2;
+ } else {
+ max_pool = 0;
+ type = -1;
+ }
+ if (type >= 0) {
+ /* PC-relative load needs fixing up. */
+ if (spare > max_pool - offset)
+ spare = max_pool - offset;
+ if ((offset & 3) !=0)
+ error("%s:%04x: pc offset must be 32 bit aligned",
+ name, start_offset + p - p_start);
+ if (offset < 0)
+ error("%s:%04x: Embedded literal value",
+ name, start_offset + p - p_start);
+ pc_offset = p - p_start + offset + 8;
+ if (pc_offset <= (p - p_start) ||
+ pc_offset >= (p_end - p_start))
+ error("%s:%04x: pc offset must point inside the function code",
+ name, start_offset + p - p_start);
+ if (pc_offset < min_offset)
+ min_offset = pc_offset;
+ if (outfile) {
+ /* The intruction position */
+ fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n",
+ p - p_start);
+ /* The position of the constant pool data. */
+ data_index = ((p_end - p_start) - pc_offset) >> 2;
+ fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr - %d;\n",
+ data_index);
+ fprintf(outfile, " arm_ldr_ptr->type = %d;\n", type);
+ fprintf(outfile, " arm_ldr_ptr++;\n");
+ }
+ }
+ p += 4;
+ }
+
+ /* Copy and relocate the constant pool data. */
+ data_size = (p_end - p_start) - min_offset;
+ if (data_size > 0 && outfile) {
+ spare += min_offset;
+ fprintf(outfile, " arm_data_ptr -= %d;\n", data_size >> 2);
+ fprintf(outfile, " arm_pool_ptr -= %d;\n", data_size);
+ fprintf(outfile, " if (arm_pool_ptr > gen_code_ptr + %d)\n"
+ " arm_pool_ptr = gen_code_ptr + %d;\n",
+ spare, spare);
+
+ data_index = 0;
+ for (pc_offset = min_offset;
+ pc_offset < p_end - p_start;
+ pc_offset += 4) {
+
+ ELF_RELOC *rel;
+ int i, addend, type;
+ const char *sym_name;
+ char relname[1024];
+
+ /* data value */
+ addend = get32((uint32_t *)(p_start + pc_offset));
+ relname[0] = '\0';
+ for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+ if (rel->r_offset == (pc_offset + start_offset)) {
+ sym_name = get_rel_sym_name(rel);
+ /* the compiler leave some unnecessary references to the code */
+ get_reloc_expr(relname, sizeof(relname), sym_name);
+ type = ELF32_R_TYPE(rel->r_info);
+ if (type != R_ARM_ABS32)
+ error("%s: unsupported data relocation", name);
+ break;
+ }
+ }
+ fprintf(outfile, " arm_data_ptr[%d] = 0x%x",
+ data_index, addend);
+ if (relname[0] != '\0')
+ fprintf(outfile, " + %s", relname);
+ fprintf(outfile, ";\n");
+
+ data_index++;
+ }
+ }
+
+ if (p == p_start)
+ goto arm_ret_error;
+ p -= 4;
+ insn = get32((uint32_t *)p);
+ /* The last instruction must be an ldm instruction. There are several
+ forms generated by gcc:
+ ldmib sp, {..., pc} (implies a sp adjustment of +4)
+ ldmia sp, {..., pc}
+ ldmea fp, {..., pc} */
+ if ((insn & 0xffff8000) == 0xe99d8000) {
+ if (outfile) {
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + %d) = 0xe28dd004;\n",
+ p - p_start);
+ }
+ p += 4;
+ } else if ((insn & 0xffff8000) != 0xe89d8000
+ && (insn & 0xffff8000) != 0xe91b8000) {
+ arm_ret_error:
+ if (!outfile)
+ printf("%s: invalid epilog\n", name);
+ }
+ return p - p_start;
+}
+#endif
+
+
+#define MAX_ARGS 3
+
+/* generate op code */
+void gen_code(const char *name, host_ulong offset, host_ulong size,
+ FILE *outfile, int gen_switch)
+{
+ int copy_size = 0;
+ uint8_t *p_start, *p_end;
+ host_ulong start_offset;
+ int nb_args, i, n;
+ uint8_t args_present[MAX_ARGS];
+ const char *sym_name, *p;
+ EXE_RELOC *rel;
+
+ /* Compute exact size excluding prologue and epilogue instructions.
+ * Increment start_offset to skip epilogue instructions, then compute
+ * copy_size the indicate the size of the remaining instructions (in
+ * bytes).
+ */
+ p_start = text + offset;
+ p_end = p_start + size;
+ start_offset = offset;
+#if defined(HOST_I386) || defined(HOST_X86_64)
+#ifdef CONFIG_FORMAT_COFF
+ {
+ uint8_t *p;
+ p = p_end - 1;
+ if (p == p_start)
+ error("empty code for %s", name);
+ while (*p != 0xc3) {
+ p--;
+ if (p <= p_start)
+ error("ret or jmp expected at the end of %s", name);
+ }
+ copy_size = p - p_start;
+ }
+#else
+ {
+ int len;
+ len = p_end - p_start;
+ if (len == 0)
+ error("empty code for %s", name);
+ if (p_end[-1] == 0xc3) {
+ len--;
+ } else {
+ error("ret or jmp expected at the end of %s", name);
+ }
+ copy_size = len;
+ }
+#endif
+#elif defined(HOST_PPC)
+ {
+ uint8_t *p;
+ p = (void *)(p_end - 4);
+ if (p == p_start)
+ error("empty code for %s", name);
+ if (get32((uint32_t *)p) != 0x4e800020)
+ error("blr expected at the end of %s", name);
+ copy_size = p - p_start;
+ }
+#elif defined(HOST_S390)
+ {
+ uint8_t *p;
+ p = (void *)(p_end - 2);
+ if (p == p_start)
+ error("empty code for %s", name);
+ if (get16((uint16_t *)p) != 0x07fe && get16((uint16_t *)p) != 0x07f4)
+ error("br %%r14 expected at the end of %s", name);
+ copy_size = p - p_start;
+ }
+#elif defined(HOST_ALPHA)
+ {
+ uint8_t *p;
+ p = p_end - 4;
+#if 0
+ /* XXX: check why it occurs */
+ if (p == p_start)
+ error("empty code for %s", name);
+#endif
+ if (get32((uint32_t *)p) != 0x6bfa8001)
+ error("ret expected at the end of %s", name);
+ copy_size = p - p_start;
+ }
+#elif defined(HOST_IA64)
+ {
+ uint8_t *p;
+ p = (void *)(p_end - 4);
+ if (p == p_start)
+ error("empty code for %s", name);
+ /* br.ret.sptk.many b0;; */
+ /* 08 00 84 00 */
+ if (get32((uint32_t *)p) != 0x00840008)
+ error("br.ret.sptk.many b0;; expected at the end of %s", name);
+ copy_size = p_end - p_start;
+ }
+#elif defined(HOST_SPARC)
+ {
+#define INSN_SAVE 0x9de3a000
+#define INSN_RET 0x81c7e008
+#define INSN_RETL 0x81c3e008
+#define INSN_RESTORE 0x81e80000
+#define INSN_RETURN 0x81cfe008
+#define INSN_NOP 0x01000000
+#define INSN_ADD_SP 0x9c03a000 // add %sp, nn, %sp
+#define INSN_SUB_SP 0x9c23a000 // sub %sp, nn, %sp
+
+ uint32_t start_insn, end_insn1, end_insn2;
+ uint8_t *p;
+ p = (void *)(p_end - 8);
+ if (p <= p_start)
+ error("empty code for %s", name);
+ start_insn = get32((uint32_t *)(p_start + 0x0));
+ end_insn1 = get32((uint32_t *)(p + 0x0));
+ end_insn2 = get32((uint32_t *)(p + 0x4));
+ if (((start_insn & ~0x1fff) == INSN_SAVE) ||
+ (start_insn & ~0x1fff) == INSN_ADD_SP) {
+ p_start += 0x4;
+ start_offset += 0x4;
+ if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
+ /* SPARC v7: ret; restore; */ ;
+ else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
+ /* SPARC v9: return; nop; */ ;
+ else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP)
+ /* SPARC v7: retl; sub %sp, nn, %sp; */ ;
+ else
+
+ error("ret; restore; not found at end of %s", name);
+ } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
+ ;
+ } else {
+ error("No save at the beginning of %s", name);
+ }
+#if 0
+ /* Skip a preceeding nop, if present. */
+ if (p > p_start) {
+ skip_insn = get32((uint32_t *)(p - 0x4));
+ if (skip_insn == INSN_NOP)
+ p -= 4;
+ }
+#endif
+ copy_size = p - p_start;
+ }
+#elif defined(HOST_SPARC64)
+ {
+#define INSN_SAVE 0x9de3a000
+#define INSN_RET 0x81c7e008
+#define INSN_RETL 0x81c3e008
+#define INSN_RESTORE 0x81e80000
+#define INSN_RETURN 0x81cfe008
+#define INSN_NOP 0x01000000
+#define INSN_ADD_SP 0x9c03a000 // add %sp, nn, %sp
+#define INSN_SUB_SP 0x9c23a000 // sub %sp, nn, %sp
+
+ uint32_t start_insn, end_insn1, end_insn2, skip_insn;
+ uint8_t *p;
+ p = (void *)(p_end - 8);
+#if 0
+ /* XXX: check why it occurs */
+ if (p <= p_start)
+ error("empty code for %s", name);
+#endif
+ start_insn = get32((uint32_t *)(p_start + 0x0));
+ end_insn1 = get32((uint32_t *)(p + 0x0));
+ end_insn2 = get32((uint32_t *)(p + 0x4));
+ if (((start_insn & ~0x1fff) == INSN_SAVE) ||
+ (start_insn & ~0x1fff) == INSN_ADD_SP) {
+ p_start += 0x4;
+ start_offset += 0x4;
+ if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
+ /* SPARC v7: ret; restore; */ ;
+ else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
+ /* SPARC v9: return; nop; */ ;
+ else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP)
+ /* SPARC v7: retl; sub %sp, nn, %sp; */ ;
+ else
+
+ error("ret; restore; not found at end of %s", name);
+ } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
+ ;
+ } else {
+ error("No save at the beginning of %s", name);
+ }
+
+ /* Skip a preceeding nop, if present. */
+ if (p > p_start) {
+ skip_insn = get32((uint32_t *)(p - 0x4));
+ if (skip_insn == 0x01000000)
+ p -= 4;
+ }
+
+ copy_size = p - p_start;
+ }
+#elif defined(HOST_ARM)
+ {
+ uint32_t insn;
+
+ if ((p_end - p_start) <= 16)
+ error("%s: function too small", name);
+ if (get32((uint32_t *)p_start) != 0xe1a0c00d ||
+ (get32((uint32_t *)(p_start + 4)) & 0xffff0000) != 0xe92d0000 ||
+ get32((uint32_t *)(p_start + 8)) != 0xe24cb004)
+ error("%s: invalid prolog", name);
+ p_start += 12;
+ start_offset += 12;
+ insn = get32((uint32_t *)p_start);
+ if ((insn & 0xffffff00) == 0xe24dd000) {
+ /* Stack adjustment. Assume op uses the frame pointer. */
+ p_start -= 4;
+ start_offset -= 4;
+ }
+ copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end,
+ relocs, nb_relocs);
+ }
+#elif defined(HOST_M68K)
+ {
+ uint8_t *p;
+ p = (void *)(p_end - 2);
+ if (p == p_start)
+ error("empty code for %s", name);
+ // remove NOP's, probably added for alignment
+ while ((get16((uint16_t *)p) == 0x4e71) &&
+ (p>p_start))
+ p -= 2;
+ if (get16((uint16_t *)p) != 0x4e75)
+ error("rts expected at the end of %s", name);
+ copy_size = p - p_start;
+ }
+#else
+#error unsupported CPU
+#endif
+
+ /* compute the number of arguments by looking at the relocations */
+ for(i = 0;i < MAX_ARGS; i++)
+ args_present[i] = 0;
+
+ for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+ host_ulong offset = get_rel_offset(rel);
+ if (offset >= start_offset &&
+ offset < start_offset + (p_end - p_start)) {
+ sym_name = get_rel_sym_name(rel);
+ if(!sym_name)
+ continue;
+ if (strstart(sym_name, "__op_param", &p) ||
+ strstart(sym_name, "__op_gen_label", &p)) {
+ n = strtoul(p, NULL, 10);
+ if (n > MAX_ARGS)
+ error("too many arguments in %s", name);
+ args_present[n - 1] = 1;
+ }
+ }
+ }
+
+ nb_args = 0;
+ while (nb_args < MAX_ARGS && args_present[nb_args])
+ nb_args++;
+ for(i = nb_args; i < MAX_ARGS; i++) {
+ if (args_present[i])
+ error("inconsistent argument numbering in %s", name);
+ }
+
+ if (gen_switch == 2) {
+ fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size);
+ } else if (gen_switch == 1) {
+
+ /* output C code */
+ fprintf(outfile, "case INDEX_%s: {\n", name);
+ if (nb_args > 0) {
+ fprintf(outfile, " long ");
+ for(i = 0; i < nb_args; i++) {
+ if (i != 0)
+ fprintf(outfile, ", ");
+ fprintf(outfile, "param%d", i + 1);
+ }
+ fprintf(outfile, ";\n");
+ }
+#if defined(HOST_IA64)
+ fprintf(outfile, " extern char %s;\n", name);
+#else
+ fprintf(outfile, " extern void %s();\n", name);
+#endif
+
+ for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+ host_ulong offset = get_rel_offset(rel);
+ if (offset >= start_offset &&
+ offset < start_offset + (p_end - p_start)) {
+ sym_name = get_rel_sym_name(rel);
+ if(!sym_name)
+ continue;
+ if (*sym_name &&
+ !strstart(sym_name, "__op_param", NULL) &&
+ !strstart(sym_name, "__op_jmp", NULL) &&
+ !strstart(sym_name, "__op_gen_label", NULL)) {
+#if defined(HOST_SPARC)
+ if (sym_name[0] == '.') {
+ fprintf(outfile,
+ "extern char __dot_%s __asm__(\"%s\");\n",
+ sym_name+1, sym_name);
+ continue;
+ }
+#endif
+#if defined(__APPLE__)
+/* set __attribute((unused)) on darwin because we wan't to avoid warning when we don't use the symbol */
+ fprintf(outfile, "extern char %s __attribute__((unused));\n", sym_name);
+#elif defined(HOST_IA64)
+ if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
+ /*
+ * PCREL21 br.call targets generally
+ * are out of range and need to go
+ * through an "import stub".
+ */
+ fprintf(outfile, " extern char %s;\n",
+ sym_name);
+#else
+ fprintf(outfile, "extern char %s;\n", sym_name);
+#endif
+ }
+ }
+ }
+
+ fprintf(outfile, " memcpy(gen_code_ptr, (void *)((char *)&%s+%d), %d);\n",
+ name, (int)(start_offset - offset), copy_size);
+
+ /* emit code offset information */
+ {
+ EXE_SYM *sym;
+ const char *sym_name, *p;
+ unsigned long val;
+ int n;
+
+ for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
+ sym_name = get_sym_name(sym);
+ if (strstart(sym_name, "__op_label", &p)) {
+ uint8_t *ptr;
+ unsigned long offset;
+
+ /* test if the variable refers to a label inside
+ the code we are generating */
+#ifdef CONFIG_FORMAT_COFF
+ if (sym->st_shndx == text_shndx) {
+ ptr = sdata[coff_text_shndx];
+ } else if (sym->st_shndx == data_shndx) {
+ ptr = sdata[coff_data_shndx];
+ } else {
+ ptr = NULL;
+ }
+#elif defined(CONFIG_FORMAT_MACH)
+ if(!sym->n_sect)
+ continue;
+ ptr = sdata[sym->n_sect-1];
+#else
+ ptr = sdata[sym->st_shndx];
+#endif
+ if (!ptr)
+ error("__op_labelN in invalid section");
+ offset = sym->st_value;
+#ifdef CONFIG_FORMAT_MACH
+ offset -= section_hdr[sym->n_sect-1].addr;
+#endif
+ val = *(unsigned long *)(ptr + offset);
+#ifdef ELF_USES_RELOCA
+ {
+ int reloc_shndx, nb_relocs1, j;
+
+ /* try to find a matching relocation */
+ reloc_shndx = find_reloc(sym->st_shndx);
+ if (reloc_shndx) {
+ nb_relocs1 = shdr[reloc_shndx].sh_size /
+ shdr[reloc_shndx].sh_entsize;
+ rel = (ELF_RELOC *)sdata[reloc_shndx];
+ for(j = 0; j < nb_relocs1; j++) {
+ if (rel->r_offset == offset) {
+ val = rel->r_addend;
+ break;
+ }
+ rel++;
+ }
+ }
+ }
+#endif
+ if (val >= start_offset && val <= start_offset + copy_size) {
+ n = strtol(p, NULL, 10);
+ fprintf(outfile, " label_offsets[%d] = %ld + (gen_code_ptr - gen_code_buf);\n", n, (long)(val - start_offset));
+ }
+ }
+ }
+ }
+
+ /* load parameres in variables */
+ for(i = 0; i < nb_args; i++) {
+ fprintf(outfile, " param%d = *opparam_ptr++;\n", i + 1);
+ }
+
+ /* patch relocations */
+#if defined(HOST_I386)
+ {
+ char name[256];
+ int type;
+ int addend;
+ int reloc_offset;
+ for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+ if (rel->r_offset >= start_offset &&
+ rel->r_offset < start_offset + copy_size) {
+ sym_name = get_rel_sym_name(rel);
+ if (!sym_name)
+ continue;
+ reloc_offset = rel->r_offset - start_offset;
+ if (strstart(sym_name, "__op_jmp", &p)) {
+ int n;
+ n = strtol(p, NULL, 10);
+ /* __op_jmp relocations are done at
+ runtime to do translated block
+ chaining: the offset of the instruction
+ needs to be stored */
+ fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
+ n, reloc_offset);
+ continue;
+ }
+
+ get_reloc_expr(name, sizeof(name), sym_name);
+ addend = get32((uint32_t *)(text + rel->r_offset));
+#ifdef CONFIG_FORMAT_ELF
+ type = ELF32_R_TYPE(rel->r_info);
+ switch(type) {
+ case R_386_32:
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+ reloc_offset, name, addend);
+ break;
+ case R_386_PC32:
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
+ reloc_offset, name, reloc_offset, addend);
+ break;
+ default:
+ error("unsupported i386 relocation (%d)", type);
+ }
+#elif defined(CONFIG_FORMAT_COFF)
+ {
+ char *temp_name;
+ int j;
+ EXE_SYM *sym;
+ temp_name = get_sym_name(symtab + *(uint32_t *)(rel->r_reloc->r_symndx));
+ if (!strcmp(temp_name, ".data")) {
+ for (j = 0, sym = symtab; j < nb_syms; j++, sym++) {
+ if (strstart(sym->st_name, sym_name, NULL)) {
+ addend -= sym->st_value;
+ }
+ }
+ }
+ }
+ type = rel->r_type;
+ switch(type) {
+ case DIR32:
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+ reloc_offset, name, addend);
+ break;
+ case DISP32:
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n",
+ reloc_offset, name, reloc_offset, addend);
+ break;
+ default:
+ error("unsupported i386 relocation (%d)", type);
+ }
+#else
+#error unsupport object format
+#endif
+ }
+ }
+ }
+#elif defined(HOST_X86_64)
+ {
+ char name[256];
+ int type;
+ int addend;
+ int reloc_offset;
+ for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+ if (rel->r_offset >= start_offset &&
+ rel->r_offset < start_offset + copy_size) {
+ sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
+ get_reloc_expr(name, sizeof(name), sym_name);
+ type = ELF32_R_TYPE(rel->r_info);
+ addend = rel->r_addend;
+ reloc_offset = rel->r_offset - start_offset;
+ switch(type) {
+ case R_X86_64_32:
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n",
+ reloc_offset, name, addend);
+ break;
+ case R_X86_64_32S:
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n",
+ reloc_offset, name, addend);
+ break;
+ case R_X86_64_PC32:
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
+ reloc_offset, name, reloc_offset, addend);
+ break;
+ default:
+ error("unsupported X86_64 relocation (%d)", type);
+ }
+ }
+ }
+ }
+#elif defined(HOST_PPC)
+ {
+#ifdef CONFIG_FORMAT_ELF
+ char name[256];
+ int type;
+ int addend;
+ int reloc_offset;
+ for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+ if (rel->r_offset >= start_offset &&
+ rel->r_offset < start_offset + copy_size) {
+ sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
+ reloc_offset = rel->r_offset - start_offset;
+ if (strstart(sym_name, "__op_jmp", &p)) {
+ int n;
+ n = strtol(p, NULL, 10);
+ /* __op_jmp relocations are done at
+ runtime to do translated block
+ chaining: the offset of the instruction
+ needs to be stored */
+ fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
+ n, reloc_offset);
+ continue;
+ }
+
+ get_reloc_expr(name, sizeof(name), sym_name);
+ type = ELF32_R_TYPE(rel->r_info);
+ addend = rel->r_addend;
+ switch(type) {
+ case R_PPC_ADDR32:
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+ reloc_offset, name, addend);
+ break;
+ case R_PPC_ADDR16_LO:
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n",
+ reloc_offset, name, addend);
+ break;
+ case R_PPC_ADDR16_HI:
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n",
+ reloc_offset, name, addend);
+ break;
+ case R_PPC_ADDR16_HA:
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n",
+ reloc_offset, name, addend);
+ break;
+ case R_PPC_REL24:
+ /* warning: must be at 32 MB distancy */
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n",
+ reloc_offset, reloc_offset, name, reloc_offset, addend);
+ break;
+ default:
+ error("unsupported powerpc relocation (%d)", type);
+ }
+ }
+ }
+#elif defined(CONFIG_FORMAT_MACH)
+ struct scattered_relocation_info *scarel;
+ struct relocation_info * rel;
+ char final_sym_name[256];
+ const char *sym_name;
+ const char *p;
+ int slide, sslide;
+ int i;
+
+ for(i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
+ unsigned int offset, length, value = 0;
+ unsigned int type, pcrel, isym = 0;
+ unsigned int usesym = 0;
+
+ if(R_SCATTERED & rel->r_address) {
+ scarel = (struct scattered_relocation_info*)rel;
+ offset = (unsigned int)scarel->r_address;
+ length = scarel->r_length;
+ pcrel = scarel->r_pcrel;
+ type = scarel->r_type;
+ value = scarel->r_value;
+ } else {
+ value = isym = rel->r_symbolnum;
+ usesym = (rel->r_extern);
+ offset = rel->r_address;
+ length = rel->r_length;
+ pcrel = rel->r_pcrel;
+ type = rel->r_type;
+ }
+
+ slide = offset - start_offset;
+
+ if (!(offset >= start_offset && offset < start_offset + size))
+ continue; /* not in our range */
+
+ sym_name = get_reloc_name(rel, &sslide);
+
+ if(usesym && symtab[isym].n_type & N_STAB)
+ continue; /* don't handle STAB (debug sym) */
+
+ if (sym_name && strstart(sym_name, "__op_jmp", &p)) {
+ int n;
+ n = strtol(p, NULL, 10);
+ fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
+ n, slide);
+ continue; /* Nothing more to do */
+ }
+
+ if(!sym_name)
+ {
+ fprintf(outfile, "/* #warning relocation not handled in %s (value 0x%x, %s, offset 0x%x, length 0x%x, %s, type 0x%x) */\n",
+ name, value, usesym ? "use sym" : "don't use sym", offset, length, pcrel ? "pcrel":"", type);
+ continue; /* dunno how to handle without final_sym_name */
+ }
+
+ get_reloc_expr(final_sym_name, sizeof(final_sym_name),
+ sym_name);
+ switch(type) {
+ case PPC_RELOC_BR24:
+ if (!strstart(sym_name,"__op_gen_label",&p)) {
+ fprintf(outfile, "{\n");
+ fprintf(outfile, " uint32_t imm = *(uint32_t *)(gen_code_ptr + %d) & 0x3fffffc;\n", slide);
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((imm + ((long)%s - (long)gen_code_ptr) + %d) & 0x03fffffc);\n",
+ slide, slide, name, sslide );
+ fprintf(outfile, "}\n");
+ } else {
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | (((long)%s - (long)gen_code_ptr - %d) & 0x03fffffc);\n",
+ slide, slide, final_sym_name, slide);
+ }
+ break;
+ case PPC_RELOC_HI16:
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d) >> 16;\n",
+ slide, final_sym_name, sslide);
+ break;
+ case PPC_RELOC_LO16:
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d);\n",
+ slide, final_sym_name, sslide);
+ break;
+ case PPC_RELOC_HA16:
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d + 0x8000) >> 16;\n",
+ slide, final_sym_name, sslide);
+ break;
+ default:
+ error("unsupported powerpc relocation (%d)", type);
+ }
+ }
+#else
+#error unsupport object format
+#endif
+ }
+#elif defined(HOST_S390)
+ {
+ char name[256];
+ int type;
+ int addend;
+ int reloc_offset;
+ for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+ if (rel->r_offset >= start_offset &&
+ rel->r_offset < start_offset + copy_size) {
+ sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
+ get_reloc_expr(name, sizeof(name), sym_name);
+ type = ELF32_R_TYPE(rel->r_info);
+ addend = rel->r_addend;
+ reloc_offset = rel->r_offset - start_offset;
+ switch(type) {
+ case R_390_32:
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+ reloc_offset, name, addend);
+ break;
+ case R_390_16:
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n",
+ reloc_offset, name, addend);
+ break;
+ case R_390_8:
+ fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n",
+ reloc_offset, name, addend);
+ break;
+ default:
+ error("unsupported s390 relocation (%d)", type);
+ }
+ }
+ }
+ }
+#elif defined(HOST_ALPHA)
+ {
+ for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
+ if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) {
+ int type;
+ long reloc_offset;
+
+ type = ELF64_R_TYPE(rel->r_info);
+ sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
+ reloc_offset = rel->r_offset - start_offset;
+ switch (type) {
+ case R_ALPHA_GPDISP:
+ /* The gp is just 32 bit, and never changes, so it's easiest to emit it
+ as an immediate instead of constructing it from the pv or ra. */
+ fprintf(outfile, " immediate_ldah(gen_code_ptr + %ld, gp);\n",
+ reloc_offset);
+ fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, gp);\n",
+ reloc_offset + (int)rel->r_addend);
+ break;
+ case R_ALPHA_LITUSE:
+ /* jsr to literal hint. Could be used to optimize to bsr. Ignore for
+ now, since some called functions (libc) need pv to be set up. */
+ break;
+ case R_ALPHA_HINT:
+ /* Branch target prediction hint. Ignore for now. Should be already
+ correct for in-function jumps. */
+ break;
+ case R_ALPHA_LITERAL:
+ /* Load a literal from the GOT relative to the gp. Since there's only a
+ single gp, nothing is to be done. */
+ break;
+ case R_ALPHA_GPRELHIGH:
+ /* Handle fake relocations against __op_param symbol. Need to emit the
+ high part of the immediate value instead. Other symbols need no
+ special treatment. */
+ if (strstart(sym_name, "__op_param", &p))
+ fprintf(outfile, " immediate_ldah(gen_code_ptr + %ld, param%s);\n",
+ reloc_offset, p);
+ break;
+ case R_ALPHA_GPRELLOW:
+ if (strstart(sym_name, "__op_param", &p))
+ fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, param%s);\n",
+ reloc_offset, p);
+ break;
+ case R_ALPHA_BRSGP:
+ /* PC-relative jump. Tweak offset to skip the two instructions that try to
+ set up the gp from the pv. */
+ fprintf(outfile, " fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld + 4) + 8);\n",
+ reloc_offset, sym_name, reloc_offset);
+ break;
+ default:
+ error("unsupported Alpha relocation (%d)", type);
+ }
+ }
+ }
+ }
+#elif defined(HOST_IA64)
+ {
+ unsigned long sym_idx;
+ long code_offset;
+ char name[256];
+ int type;
+ long addend;
+
+ for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+ sym_idx = ELF64_R_SYM(rel->r_info);
+ if (rel->r_offset < start_offset
+ || rel->r_offset >= start_offset + copy_size)
+ continue;
+ sym_name = (strtab + symtab[sym_idx].st_name);
+ code_offset = rel->r_offset - start_offset;
+ if (strstart(sym_name, "__op_jmp", &p)) {
+ int n;
+ n = strtol(p, NULL, 10);
+ /* __op_jmp relocations are done at
+ runtime to do translated block
+ chaining: the offset of the instruction
+ needs to be stored */
+ fprintf(outfile, " jmp_offsets[%d] ="
+ "%ld + (gen_code_ptr - gen_code_buf);\n",
+ n, code_offset);
+ continue;
+ }
+ get_reloc_expr(name, sizeof(name), sym_name);
+ type = ELF64_R_TYPE(rel->r_info);
+ addend = rel->r_addend;
+ switch(type) {
+ case R_IA64_IMM64:
+ fprintf(outfile,
+ " ia64_imm64(gen_code_ptr + %ld, "
+ "%s + %ld);\n",
+ code_offset, name, addend);
+ break;
+ case R_IA64_LTOFF22X:
+ case R_IA64_LTOFF22:
+ fprintf(outfile, " IA64_LTOFF(gen_code_ptr + %ld,"
+ " %s + %ld, %d);\n",
+ code_offset, name, addend,
+ (type == R_IA64_LTOFF22X));
+ break;
+ case R_IA64_LDXMOV:
+ fprintf(outfile,
+ " ia64_ldxmov(gen_code_ptr + %ld,"
+ " %s + %ld);\n", code_offset, name, addend);
+ break;
+
+ case R_IA64_PCREL21B:
+ if (strstart(sym_name, "__op_gen_label", NULL)) {
+ fprintf(outfile,
+ " ia64_imm21b(gen_code_ptr + %ld,"
+ " (long) (%s + %ld -\n\t\t"
+ "((long) gen_code_ptr + %ld)) >> 4);\n",
+ code_offset, name, addend,
+ code_offset & ~0xfUL);
+ } else {
+ fprintf(outfile,
+ " IA64_PLT(gen_code_ptr + %ld, "
+ "%d);\t/* %s + %ld */\n",
+ code_offset,
+ get_plt_index(sym_name, addend),
+ sym_name, addend);
+ }
+ break;
+ default:
+ error("unsupported ia64 relocation (0x%x)",
+ type);
+ }
+ }
+ fprintf(outfile, " ia64_nop_b(gen_code_ptr + %d);\n",
+ copy_size - 16 + 2);
+ }
+#elif defined(HOST_SPARC)
+ {
+ char name[256];
+ int type;
+ int addend;
+ int reloc_offset;
+ for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+ if (rel->r_offset >= start_offset &&
+ rel->r_offset < start_offset + copy_size) {
+ sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
+ get_reloc_expr(name, sizeof(name), sym_name);
+ type = ELF32_R_TYPE(rel->r_info);
+ addend = rel->r_addend;
+ reloc_offset = rel->r_offset - start_offset;
+ switch(type) {
+ case R_SPARC_32:
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+ reloc_offset, name, addend);
+ break;
+ case R_SPARC_HI22:
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + %d) = "
+ "((*(uint32_t *)(gen_code_ptr + %d)) "
+ " & ~0x3fffff) "
+ " | (((%s + %d) >> 10) & 0x3fffff);\n",
+ reloc_offset, reloc_offset, name, addend);
+ break;
+ case R_SPARC_LO10:
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + %d) = "
+ "((*(uint32_t *)(gen_code_ptr + %d)) "
+ " & ~0x3ff) "
+ " | ((%s + %d) & 0x3ff);\n",
+ reloc_offset, reloc_offset, name, addend);
+ break;
+ case R_SPARC_WDISP30:
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + %d) = "
+ "((*(uint32_t *)(gen_code_ptr + %d)) "
+ " & ~0x3fffffff) "
+ " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
+ " & 0x3fffffff);\n",
+ reloc_offset, reloc_offset, name, addend,
+ reloc_offset);
+ break;
+ case R_SPARC_WDISP22:
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + %d) = "
+ "((*(uint32_t *)(gen_code_ptr + %d)) "
+ " & ~0x3fffff) "
+ " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
+ " & 0x3fffff);\n",
+ rel->r_offset - start_offset,
+ rel->r_offset - start_offset,
+ name, addend,
+ rel->r_offset - start_offset);
+ break;
+ default:
+ error("unsupported sparc relocation (%d)", type);
+ }
+ }
+ }
+ }
+#elif defined(HOST_SPARC64)
+ {
+ char name[256];
+ int type;
+ int addend;
+ int reloc_offset;
+ for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+ if (rel->r_offset >= start_offset &&
+ rel->r_offset < start_offset + copy_size) {
+ sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
+ get_reloc_expr(name, sizeof(name), sym_name);
+ type = ELF32_R_TYPE(rel->r_info);
+ addend = rel->r_addend;
+ reloc_offset = rel->r_offset - start_offset;
+ switch(type) {
+ case R_SPARC_32:
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+ reloc_offset, name, addend);
+ break;
+ case R_SPARC_HI22:
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + %d) = "
+ "((*(uint32_t *)(gen_code_ptr + %d)) "
+ " & ~0x3fffff) "
+ " | (((%s + %d) >> 10) & 0x3fffff);\n",
+ reloc_offset, reloc_offset, name, addend);
+ break;
+ case R_SPARC_LO10:
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + %d) = "
+ "((*(uint32_t *)(gen_code_ptr + %d)) "
+ " & ~0x3ff) "
+ " | ((%s + %d) & 0x3ff);\n",
+ reloc_offset, reloc_offset, name, addend);
+ break;
+ case R_SPARC_OLO10:
+ addend += ELF64_R_TYPE_DATA (rel->r_info);
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + %d) = "
+ "((*(uint32_t *)(gen_code_ptr + %d)) "
+ " & ~0x3ff) "
+ " | ((%s + %d) & 0x3ff);\n",
+ reloc_offset, reloc_offset, name, addend);
+ break;
+ case R_SPARC_WDISP30:
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + %d) = "
+ "((*(uint32_t *)(gen_code_ptr + %d)) "
+ " & ~0x3fffffff) "
+ " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
+ " & 0x3fffffff);\n",
+ reloc_offset, reloc_offset, name, addend,
+ reloc_offset);
+ break;
+ case R_SPARC_WDISP22:
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + %d) = "
+ "((*(uint32_t *)(gen_code_ptr + %d)) "
+ " & ~0x3fffff) "
+ " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
+ " & 0x3fffff);\n",
+ reloc_offset, reloc_offset, name, addend,
+ reloc_offset);
+ break;
+ default:
+ error("unsupported sparc64 relocation (%d) for symbol %s", type, name);
+ }
+ }
+ }
+ }
+#elif defined(HOST_ARM)
+ {
+ char name[256];
+ int type;
+ int addend;
+ int reloc_offset;
+ uint32_t insn;
+
+ insn = get32((uint32_t *)(p_start + 4));
+ /* If prologue ends in sub sp, sp, #const then assume
+ op has a stack frame and needs the frame pointer. */
+ if ((insn & 0xffffff00) == 0xe24dd000) {
+ int i;
+ uint32_t opcode;
+ opcode = 0xe28db000; /* add fp, sp, #0. */
+#if 0
+/* ??? Need to undo the extra stack adjustment at the end of the op.
+ For now just leave the stack misaligned and hope it doesn't break anything
+ too important. */
+ if ((insn & 4) != 0) {
+ /* Preserve doubleword stack alignment. */
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + 4)= 0x%x;\n",
+ insn + 4);
+ opcode -= 4;
+ }
+#endif
+ insn = get32((uint32_t *)(p_start - 4));
+ /* Calculate the size of the saved registers,
+ excluding pc. */
+ for (i = 0; i < 15; i++) {
+ if (insn & (1 << i))
+ opcode += 4;
+ }
+ fprintf(outfile,
+ " *(uint32_t *)gen_code_ptr = 0x%x;\n", opcode);
+ }
+ arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end,
+ relocs, nb_relocs);
+
+ for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+ if (rel->r_offset >= start_offset &&
+ rel->r_offset < start_offset + copy_size) {
+ sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
+ /* the compiler leave some unnecessary references to the code */
+ if (sym_name[0] == '\0')
+ continue;
+ get_reloc_expr(name, sizeof(name), sym_name);
+ type = ELF32_R_TYPE(rel->r_info);
+ addend = get32((uint32_t *)(text + rel->r_offset));
+ reloc_offset = rel->r_offset - start_offset;
+ switch(type) {
+ case R_ARM_ABS32:
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+ reloc_offset, name, addend);
+ break;
+ case R_ARM_PC24:
+ case R_ARM_JUMP24:
+ case R_ARM_CALL:
+ fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n",
+ reloc_offset, addend, name);
+ break;
+ default:
+ error("unsupported arm relocation (%d)", type);
+ }
+ }
+ }
+ }
+#elif defined(HOST_M68K)
+ {
+ char name[256];
+ int type;
+ int addend;
+ int reloc_offset;
+ Elf32_Sym *sym;
+ for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+ if (rel->r_offset >= start_offset &&
+ rel->r_offset < start_offset + copy_size) {
+ sym = &(symtab[ELFW(R_SYM)(rel->r_info)]);
+ sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
+ get_reloc_expr(name, sizeof(name), sym_name);
+ type = ELF32_R_TYPE(rel->r_info);
+ addend = get32((uint32_t *)(text + rel->r_offset)) + rel->r_addend;
+ reloc_offset = rel->r_offset - start_offset;
+ switch(type) {
+ case R_68K_32:
+ fprintf(outfile, " /* R_68K_32 RELOC, offset %x */\n", rel->r_offset) ;
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %#x;\n",
+ reloc_offset, name, addend );
+ break;
+ case R_68K_PC32:
+ fprintf(outfile, " /* R_68K_PC32 RELOC, offset %x */\n", rel->r_offset);
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %#x) + %#x;\n",
+ reloc_offset, name, reloc_offset, /*sym->st_value+*/ addend);
+ break;
+ default:
+ error("unsupported m68k relocation (%d)", type);
+ }
+ }
+ }
+ }
+#else
+#error unsupported CPU
+#endif
+ fprintf(outfile, " gen_code_ptr += %d;\n", copy_size);
+ fprintf(outfile, "}\n");
+ fprintf(outfile, "break;\n\n");
+ } else {
+ fprintf(outfile, "static inline void gen_%s(", name);
+ if (nb_args == 0) {
+ fprintf(outfile, "void");
+ } else {
+ for(i = 0; i < nb_args; i++) {
+ if (i != 0)
+ fprintf(outfile, ", ");
+ fprintf(outfile, "long param%d", i + 1);
+ }
+ }
+ fprintf(outfile, ")\n");
+ fprintf(outfile, "{\n");
+ for(i = 0; i < nb_args; i++) {
+ fprintf(outfile, " *gen_opparam_ptr++ = param%d;\n", i + 1);
+ }
+ fprintf(outfile, " *gen_opc_ptr++ = INDEX_%s;\n", name);
+ fprintf(outfile, "}\n\n");
+ }
+}
+
+int gen_file(FILE *outfile, int out_type)
+{
+ int i;
+ EXE_SYM *sym;
+
+ if (out_type == OUT_INDEX_OP) {
+ fprintf(outfile, "DEF(end, 0, 0)\n");
+ fprintf(outfile, "DEF(nop, 0, 0)\n");
+ fprintf(outfile, "DEF(nop1, 1, 0)\n");
+ fprintf(outfile, "DEF(nop2, 2, 0)\n");
+ fprintf(outfile, "DEF(nop3, 3, 0)\n");
+ for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
+ const char *name;
+ name = get_sym_name(sym);
+ if (strstart(name, OP_PREFIX, NULL)) {
+ gen_code(name, sym->st_value, sym->st_size, outfile, 2);
+ }
+ }
+ } else if (out_type == OUT_GEN_OP) {
+ /* generate gen_xxx functions */
+ fprintf(outfile, "#include \"dyngen-op.h\"\n");
+ for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
+ const char *name;
+ name = get_sym_name(sym);
+ if (strstart(name, OP_PREFIX, NULL)) {
+#if defined(CONFIG_FORMAT_ELF) || defined(CONFIG_FORMAT_COFF)
+ if (sym->st_shndx != text_shndx)
+ error("invalid section for opcode (0x%x)", sym->st_shndx);
+#endif
+ gen_code(name, sym->st_value, sym->st_size, outfile, 0);
+ }
+ }
+
+ } else {
+ /* generate big code generation switch */
+
+#ifdef HOST_ARM
+ /* We need to know the size of all the ops so we can figure out when
+ to emit constant pools. This must be consistent with opc.h. */
+fprintf(outfile,
+"static const uint32_t arm_opc_size[] = {\n"
+" 0,\n" /* end */
+" 0,\n" /* nop */
+" 0,\n" /* nop1 */
+" 0,\n" /* nop2 */
+" 0,\n"); /* nop3 */
+ for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
+ const char *name;
+ name = get_sym_name(sym);
+ if (strstart(name, OP_PREFIX, NULL)) {
+ fprintf(outfile, " %d,\n", sym->st_size);
+ }
+ }
+fprintf(outfile,
+"};\n");
+#endif
+
+fprintf(outfile,
+"int dyngen_code(uint8_t *gen_code_buf,\n"
+" uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
+" const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels)\n"
+"{\n"
+" uint8_t *gen_code_ptr;\n"
+" const uint16_t *opc_ptr;\n"
+" const uint32_t *opparam_ptr;\n");
+
+#ifdef HOST_ARM
+/* Arm is tricky because it uses constant pools for loading immediate values.
+ We assume (and require) each function is code followed by a constant pool.
+ All the ops are small so this should be ok. For each op we figure
+ out how much "spare" range we have in the load instructions. This allows
+ us to insert subsequent ops in between the op and the constant pool,
+ eliminating the neeed to jump around the pool.
+
+ We currently generate:
+
+ [ For this example we assume merging would move op1_pool out of range.
+ In practice we should be able to combine many ops before the offset
+ limits are reached. ]
+ op1_code;
+ op2_code;
+ goto op3;
+ op2_pool;
+ op1_pool;
+op3:
+ op3_code;
+ ret;
+ op3_pool;
+
+ Ideally we'd put op1_pool before op2_pool, but that requires two passes.
+ */
+fprintf(outfile,
+" uint8_t *last_gen_code_ptr = gen_code_buf;\n"
+" LDREntry *arm_ldr_ptr = arm_ldr_table;\n"
+" uint32_t *arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
+/* Initialise the parmissible pool offset to an arbitary large value. */
+" uint8_t *arm_pool_ptr = gen_code_buf + 0x1000000;\n");
+#endif
+#ifdef HOST_IA64
+ {
+ long addend, not_first = 0;
+ unsigned long sym_idx;
+ int index, max_index;
+ const char *sym_name;
+ EXE_RELOC *rel;
+
+ max_index = -1;
+ for (i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+ sym_idx = ELF64_R_SYM(rel->r_info);
+ sym_name = (strtab + symtab[sym_idx].st_name);
+ if (strstart(sym_name, "__op_gen_label", NULL))
+ continue;
+ if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
+ continue;
+
+ addend = rel->r_addend;
+ index = get_plt_index(sym_name, addend);
+ if (index <= max_index)
+ continue;
+ max_index = index;
+ fprintf(outfile, " extern void %s(void);\n", sym_name);
+ }
+
+ fprintf(outfile,
+ " struct ia64_fixup *plt_fixes = NULL, "
+ "*ltoff_fixes = NULL;\n"
+ " static long plt_target[] = {\n\t");
+
+ max_index = -1;
+ for (i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+ sym_idx = ELF64_R_SYM(rel->r_info);
+ sym_name = (strtab + symtab[sym_idx].st_name);
+ if (strstart(sym_name, "__op_gen_label", NULL))
+ continue;
+ if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
+ continue;
+
+ addend = rel->r_addend;
+ index = get_plt_index(sym_name, addend);
+ if (index <= max_index)
+ continue;
+ max_index = index;
+
+ if (not_first)
+ fprintf(outfile, ",\n\t");
+ not_first = 1;
+ if (addend)
+ fprintf(outfile, "(long) &%s + %ld", sym_name, addend);
+ else
+ fprintf(outfile, "(long) &%s", sym_name);
+ }
+ fprintf(outfile, "\n };\n"
+ " unsigned int plt_offset[%u] = { 0 };\n", max_index + 1);
+ }
+#endif
+
+fprintf(outfile,
+"\n"
+" gen_code_ptr = gen_code_buf;\n"
+" opc_ptr = opc_buf;\n"
+" opparam_ptr = opparam_buf;\n");
+
+ /* Generate prologue, if needed. */
+
+fprintf(outfile,
+" for(;;) {\n");
+
+#ifdef HOST_ARM
+/* Generate constant pool if needed */
+fprintf(outfile,
+" if (gen_code_ptr + arm_opc_size[*opc_ptr] >= arm_pool_ptr) {\n"
+" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
+"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 1);\n"
+" last_gen_code_ptr = gen_code_ptr;\n"
+" arm_ldr_ptr = arm_ldr_table;\n"
+" arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
+" arm_pool_ptr = gen_code_ptr + 0x1000000;\n"
+" }\n");
+#endif
+
+fprintf(outfile,
+" switch(*opc_ptr++) {\n");
+
+ for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
+ const char *name;
+ name = get_sym_name(sym);
+ if (strstart(name, OP_PREFIX, NULL)) {
+#if 0
+ printf("%4d: %s pos=0x%08x len=%d\n",
+ i, name, sym->st_value, sym->st_size);
+#endif
+#if defined(CONFIG_FORMAT_ELF) || defined(CONFIG_FORMAT_COFF)
+ if (sym->st_shndx != text_shndx)
+ error("invalid section for opcode (0x%x)", sym->st_shndx);
+#endif
+ gen_code(name, sym->st_value, sym->st_size, outfile, 1);
+ }
+ }
+
+fprintf(outfile,
+" case INDEX_op_nop:\n"
+" break;\n"
+" case INDEX_op_nop1:\n"
+" opparam_ptr++;\n"
+" break;\n"
+" case INDEX_op_nop2:\n"
+" opparam_ptr += 2;\n"
+" break;\n"
+" case INDEX_op_nop3:\n"
+" opparam_ptr += 3;\n"
+" break;\n"
+" default:\n"
+" goto the_end;\n"
+" }\n");
+
+
+fprintf(outfile,
+" }\n"
+" the_end:\n"
+);
+#ifdef HOST_IA64
+ fprintf(outfile,
+ " {\n"
+ " extern char code_gen_buffer[];\n"
+ " ia64_apply_fixes(&gen_code_ptr, ltoff_fixes, "
+ "(uint64_t) code_gen_buffer + 2*(1<<20), plt_fixes,\n\t\t\t"
+ "sizeof(plt_target)/sizeof(plt_target[0]),\n\t\t\t"
+ "plt_target, plt_offset);\n }\n");
+#endif
+
+/* generate some code patching */
+#ifdef HOST_ARM
+fprintf(outfile,
+"if (arm_data_ptr != arm_data_table + ARM_LDR_TABLE_SIZE)\n"
+" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
+"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 0);\n");
+#endif
+ /* flush instruction cache */
+ fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");
+
+ fprintf(outfile, "return gen_code_ptr - gen_code_buf;\n");
+ fprintf(outfile, "}\n\n");
+
+ }
+
+ return 0;
+}
+
+void usage(void)
+{
+ printf("dyngen (c) 2003 Fabrice Bellard\n"
+ "usage: dyngen [-o outfile] [-c] objfile\n"
+ "Generate a dynamic code generator from an object file\n"
+ "-c output enum of operations\n"
+ "-g output gen_op_xx() functions\n"
+ );
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ int c, out_type;
+ const char *filename, *outfilename;
+ FILE *outfile;
+
+ outfilename = "out.c";
+ out_type = OUT_CODE;
+ for(;;) {
+ c = getopt(argc, argv, "ho:cg");
+ if (c == -1)
+ break;
+ switch(c) {
+ case 'h':
+ usage();
+ break;
+ case 'o':
+ outfilename = optarg;
+ break;
+ case 'c':
+ out_type = OUT_INDEX_OP;
+ break;
+ case 'g':
+ out_type = OUT_GEN_OP;
+ break;
+ }
+ }
+ if (optind >= argc)
+ usage();
+ filename = argv[optind];
+ outfile = fopen(outfilename, "w");
+ if (!outfile)
+ error("could not open '%s'", outfilename);
+
+ load_object(filename);
+ gen_file(outfile, out_type);
+ fclose(outfile);
+ return 0;
+}
Added: trunk/src/host/qemu-neo1973/dyngen.h
===================================================================
--- trunk/src/host/qemu-neo1973/dyngen.h 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/dyngen.h 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,465 @@
+/*
+ * 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;
+#if defined(__sparc__) || defined(__arm__)
+ void __op_gen_label1(){}
+ void __op_gen_label2(){}
+ void __op_gen_label3(){}
+#else
+ int __op_gen_label1, __op_gen_label2, __op_gen_label3;
+#endif
+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;
+
+ 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 ARM_LDR_TABLE_SIZE 1024
+
+typedef struct LDREntry {
+ uint8_t *ptr;
+ uint32_t *data_ptr;
+ unsigned type:2;
+} LDREntry;
+
+static LDREntry arm_ldr_table[1024];
+static uint32_t arm_data_table[ARM_LDR_TABLE_SIZE];
+
+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;
+ uint32_t mask;
+
+ data_size = (data_end - data_start) << 2;
+
+ 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;
+ if (offset < 0) {
+ fprintf(stderr, "Negative constant pool offset\n");
+ abort();
+ }
+ switch (le->type) {
+ case 0: /* ldr */
+ mask = ~0x00800fff;
+ if (offset >= 4096) {
+ fprintf(stderr, "Bad ldr offset\n");
+ abort();
+ }
+ break;
+ case 1: /* ldc */
+ mask = ~0x008000ff;
+ if (offset >= 1024 ) {
+ fprintf(stderr, "Bad ldc offset\n");
+ abort();
+ }
+ break;
+ case 2: /* add */
+ mask = ~0xfff;
+ if (offset >= 1024 ) {
+ fprintf(stderr, "Bad add offset\n");
+ abort();
+ }
+ break;
+ default:
+ fprintf(stderr, "Bad pc relative fixup\n");
+ abort();
+ }
+ insn = *ptr & mask;
+ switch (le->type) {
+ case 0: /* ldr */
+ insn |= offset | 0x00800000;
+ break;
+ case 1: /* ldc */
+ insn |= (offset >> 2) | 0x00800000;
+ break;
+ case 2: /* add */
+ insn |= (offset >> 2) | 0xf00;
+ break;
+ }
+ *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);
+ }
+ /* Keep code ptr aligned. */
+ if ((long) gen_code_ptr & 15)
+ gen_code_ptr += 8;
+ *gen_code_pp = gen_code_ptr;
+}
+
+#endif
Added: trunk/src/host/qemu-neo1973/ecc.h
===================================================================
--- trunk/src/host/qemu-neo1973/ecc.h 2007-04-02 20:43:26 UTC (rev 1638)
+++ trunk/src/host/qemu-neo1973/ecc.h 2007-04-02 20:50:31 UTC (rev 1639)
@@ -0,0 +1,77 @@
+/*
+ * Calculate Error-correcting Codes. Used by NAND Flash controllers
+ * (not by NAND chips).
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This code is licensed under the GPLv2.
+ */
+
+struct ecc_state_s {
+ uint8_t cp; /* Column parity */
+ uint16_t lp[2]; /* Line parity */
+ uint16_t count;
+};
+
+/*
+ * Pre-calculated 256-way 1 byte column parity. Table borrowed from Linux.
+ */
+static const uint8_t nand_ecc_precalc_table[] = {
+ 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
+ 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
+ 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
+ 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+ 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
+ 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+ 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
+ 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+ 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
+ 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+ 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
+ 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+ 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
+ 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+ 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
+ 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+ 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
+ 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+ 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
+ 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+ 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
+ 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+ 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
+ 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+ 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
+